This repository has no description
README.md

Brand assets #

This directory is the build-time source of truth for Streamplace's visual identity. Everything else — the Expo app icon and splash screen (and from those, every iOS and Android icon format via expo prebuild), favicons, the Web Push fallback icon, OG link banner, desktop ICO/ICNS icons, docs logos, the downloadable SVGs on /brand, and the logo components rendered in the app itself — is generated from these files by js/brand/generate.mjs and gitignored.

Run the generator with pnpm run brand from the repo root. It also runs automatically on pnpm install and before app, docs, and desktop builds.

Web Push uses /notification-icon, which serves the node's runtime mainLogo branding asset with its declared image MIME type. Production and other branded nodes can therefore use the same binary; no custom build is required. If no image logo is configured, the endpoint serves the bundled /brand/notification-icon.png, a 512×512 PNG generated from the app-icon artwork (icon.svg / icon.png, or the synthesized mark). The main notification image never uses the favicon; the small notification badge is unchanged. Responses are cached for five minutes, so runtime logo changes can take that long to appear.

Runtime browser favicons #

In Settings → Branding, upload three independent icons: Default favicon, Light mode favicon, and Dark mode favicon. Each accepts SVG, PNG, or ICO up to 100 KiB. Use an icon with a background for the default and transparent light/dark overrides if desired; uploads are served unchanged. Override selection follows the browser/OS prefers-color-scheme, not the app's theme setting, and changes without reloading the page.

The branding keys are favicon (default), faviconLight, and faviconDark. Clients without theme selection and schemes without an override use the default; if no default is uploaded, they use the bundled mark. The same keys travel with branding ZIP exports/imports and can be set through the branding CLI or XRPC. No custom frontend build is needed for uploads.

The HTML declares a generic /favicon.png link before media-qualified /favicon.png?scheme=light and /favicon.png?scheme=dark links, so selection also works before JavaScript loads. /favicon.ico remains the generic fallback. These routes serve uploads with their declared image MIME type and cache for five minutes; the open admin tab reflects uploads and deletions immediately. Hydrated fallback links use fresh URLs on branding changes so a deleted upload cannot return from the browser's cache. The brand generator owns the bundled PNG and ICO, rather than Expo injecting an extra generic icon link that would override the themed links.

Favicons are web-only; native app icons and the Web Push icon are unchanged.

White-labeling #

To ship your own identity, point the generator at your own flat directory of files, either of:

  • brand/custom/ — a gitignored sibling of this directory; if it contains a brand.json it takes precedence.
  • SP_BRAND_DIR=/path/to/your/brand — explicit override, wins over both.

The directory in git holds the generic open-source identity.

File contract #

Only two files are required; everything else is synthesized from the mark and brand.json colors when absent.

File Required Purpose
brand.json yes Name, wordmark text, colors, monochrome flag, optional story for the /brand guidelines page.
mark.svg yes The logo mark. Must declare a viewBox. If monochrome is true, use fill="currentColor" so the UI can tint it.
icon.svg / icon.png no Full-bleed square app icon art. Default: mark at 62% on colors.iconBackground.
icon-foreground.svg / .png no Android adaptive icon foreground (keep art in the inner ~66% safe zone). Default: mark at 45% on transparent.
splash.svg / splash.png no Splash screen logo, shown on colors.splashBackground. Default: mark at 50% on transparent.
wordmark.svg no Wordmark lettering for downloads/lockup. Default: SVG <text> of the wordmark string.
linkbanner.svg / .png no 1200×630 OG/social card. Default: mark centered on colors.bannerBackground.

brand.json #

{
  "name": "Streamplace",
  "wordmark": "stream.place",
  "defaultSiteTitle": "My Streamplace Node",
  "monochrome": false,
  "colors": {
    "ink": "#0A0A0B",
    "paper": "#ffffff",
    "iconBackground": "#ffffff",
    "iconForeground": null,
    "adaptiveIconBackground": "#111113",
    "adaptiveIconForeground": null,
    "splashBackground": "#ffffff",
    "splashForeground": null,
    "tileBackground": "#111113",
    "tileForeground": "#ffffff",
    "tileHairline": "rgba(255,255,255,0.10)",
    "bannerBackground": null,
    "bannerForeground": null
  },
  "story": null
}

All colors are optional; *Foreground colors default to ink and only apply to monochrome marks (a multi-color mark renders as-is). wordmark is the text rendered next to the mark in the app's lockup — a . in it gets the accent treatment. defaultSiteTitle (default My <name> Node) is what an unbranded node calls itself in the nav until its operator sets a runtime siteTitle via the branding admin; a first-party brand points it at its own wordmark so its nodes show the styled wordmark with no runtime config. story optionally carries the mark's design story for the /brand guidelines screen (tagline, readings, geometry, specs, usage — see BrandStory in the generated js/app/assets/generated/brand.ts); sections without data are hidden.