From 3dfed23b439540d4cc1ecc671dac9b1e473c2d43 Mon Sep 17 00:00:00 2001 From: Padreug Date: Wed, 10 Jun 2026 00:02:23 +0200 Subject: [PATCH] docs(branding): brand kit contract + CLAUDE.md section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit branding/README.md is the deployer contract: - Directory layout, source format constraints (SVG > PNG ≥ 1024), brand.json schema, per-standalone override resolution order - BRAND_DIR / BRAND_APP usage, generator pipeline walkthrough - Pointer to issue #95 + the NixOS Phase 2 integration webapp CLAUDE.md gains a Brand Kit section describing the moving parts (vite-branding.ts, @brand alias, brandAssetsPlugin, public/icons/ gitignore, per-app override path) so future sessions on this repo know the convention without grepping. Adds BRAND_DIR / BRAND_APP to the Environment Variables example. Workspace ~/dev/CLAUDE.md note about "brand changes don't need flake.lock bump" deferred to Phase 2 (server-deploy migration) — that's when the workflow becomes reality. Part of aiolabs/webapp#95. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 52 +++++++++++++++++++++ branding/README.md | 110 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 branding/README.md diff --git a/CLAUDE.md b/CLAUDE.md index 5b890de..8008bc2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -712,8 +712,60 @@ VITE_ADMIN_PUBKEYS='["pubkey1","pubkey2"]' # Optional: Disable WebSocket if needed VITE_WEBSOCKET_ENABLED=true + +# Brand kit override (defaults to ./branding/default) +BRAND_DIR=branding/cfaun + +# Per-standalone brand override (set by build pipeline, not directly) +BRAND_APP=events ``` +## Brand kit (white-label PWA branding) + +The webapp ships a brand kit architecture so the hub + every standalone +(events, wallet, chat, market, …) can be rebranded per deployment without +forking the codebase. See `branding/README.md` for the deployer contract. + +**Single source of truth:** `branding//` holds `logo.{svg,png}` + +`brand.json`. `vite-branding.ts` reads brand.json and exposes a `@brand` +import alias. `pwa-assets.config.ts` + `@vite-pwa/assets-generator` derive +the full PWA icon set from the single logo source. + +**brand.json schema:** `{ name, shortName?, themeColor?, backgroundColor? }` +— `name` drives the manifest. `themeColor`/`backgroundColor` are optional +chrome overrides; when unset, each standalone's per-app accent applies. + +**In-app logo:** components reference `@brand/logo.png`. Active consumers: +`Login.vue`, `LoginDemo.vue`, `AppSidebar.vue`, `MobileDrawer.vue`. The +Vite alias resolves to the active brand dir at build time. + +**Generated icons:** `public/icons/` is gitignored. `brandAssetsPlugin()` +(registered first in every `vite.*.config.ts`'s plugins[]) runs the +generator once per build/dev start via `buildStart`. Outputs match the +existing filename convention (`icon-192.png`, `icon-maskable-512.png`, +…) so HTML `` hrefs and VitePWA `manifest.icons` reference +`/icons/` consistently across all 9 configs. + +**Per-standalone override:** `branding//icons//logo.{svg,png}` +is checked before the brand's primary logo. The standalone build sets +`BRAND_APP`; deployers just put files in the right place. + +**Switching brands:** +```bash +BRAND_DIR=branding/cfaun pnpm build:events +``` + +**Adding a new in-app logo consumer:** use `` +instead of `@/assets/logo.png`. The latter still works for non-brand +assets (`@/assets/bitcoin.svg`, etc.) — it's only the logo that moved. + +**NixOS deployment:** brand directories will eventually live in +`deploy/server-deploy/hosts//branding/`, with each host's +`services/webapp.nix` calling `inputs.webapp.lib.mkWebapp { brandDir = +./../branding; }`. `flake.nix` exposing `lib.mkWebapp` is a follow-up +to this PR. Until it lands, server-deploy continues to build webapp +through its existing path. See aiolabs/server-deploy#8. + ## Payment Rails Pattern Shared primitives for modules that mix Lightning + fiat (and, future, diff --git a/branding/README.md b/branding/README.md new file mode 100644 index 0000000..37bb1ce --- /dev/null +++ b/branding/README.md @@ -0,0 +1,110 @@ +# Brand kit + +This directory holds the **white-label brand kit** that drives the PWA's icons, manifest name/colors, and in-app `` logo across the hub and every standalone (events, wallet, chat, market, …). + +The committed `default/` is aiolabs's brand and is what unparameterized builds use. Downstream deployers add a sibling directory (e.g. `branding/cfaun/`) and point `BRAND_DIR` at it to ship a fully rebranded build with no fork required. + +## Directory layout + +``` +branding/ + README.md + default/ # aiolabs default, committed + logo.svg # preferred source (sharp at every size) + logo.png # fallback source (≥ 1024×1024 if PNG-only) + brand.json # { name, shortName?, themeColor?, backgroundColor? } + icons/ # optional per-standalone overrides + events/logo.svg + wallet/logo.png + cfaun/ # downstream deployer's brand (gitignored or in deploy repo) + logo.svg + brand.json +``` + +aiolabs's `default/` currently ships PNG-only (1024×1024). Replace with `logo.svg` when a vector source becomes available — produces sharper icons at every size and unlocks `favicon.svg`. + +## Source formats + +**SVG strongly preferred:** + +- Crisp at every output size (192 / 512 maskable / 180 apple / 48 favicon) +- Enables sharp `favicon.svg` for modern browsers +- The in-app `@brand/logo` reference can be tinted via CSS (`currentColor`, filters) + +**PNG accepted with constraints:** + +- **≥ 1024×1024** — smaller sources produce blurry icons on high-DPI Android install screens +- **Square aspect ratio** — PWA icon canvas is square +- **Transparent background** — the generator applies maskable/apple background colors itself +- PNG-source deployments lose the `favicon.svg` benefit and the recolorable in-app logo + +When both `logo.svg` and `logo.png` are present, SVG wins. + +## brand.json schema + +```jsonc +{ + "name": "AIO", // required — drives PWA manifest name + "shortName": "AIO", // optional — PWA home-screen label; defaults to `name` + "themeColor": "#1f2937", // optional — PWA chrome color override (otherwise each standalone keeps its accent) + "backgroundColor": "#fff" // optional — PWA splash background +} +``` + +`themeColor` and `backgroundColor` are *overrides*, not defaults. When unset, each standalone's own accent applies (wallet yellow `#eab308`, chat green `#16a34a`, …) — so the default brand kit preserves the per-app visual identity, and a deployer who wants unified chrome adds the override. + +## Per-standalone overrides + +Place a logo at `branding//icons//logo.{svg,png}` to override the brand's primary logo for a single standalone build. + +Resolution at build time: + +1. `branding//icons//logo.svg` +2. `branding//icons//logo.png` +3. `branding//logo.svg` +4. `branding//logo.png` +5. Build fails with a clear error pointing here. + +`` is set via `BRAND_APP` env var (the standalone build script sets this; deployers don't touch it directly). + +## How to use + +**Building with the default brand:** + +```bash +pnpm build # main shell +pnpm build:events # events standalone +# … one per standalone +``` + +**Building with a deployer's brand:** + +```bash +BRAND_DIR=branding/cfaun pnpm build:events +``` + +`BRAND_DIR` accepts relative paths (resolved from the webapp repo root) or absolute paths (used by the NixOS builder, which mounts the brand directory into the sandbox at a `/nix/store/...-branding` path). + +**Regenerating icons explicitly:** + +The Vite plugin auto-runs the generator on every build/dev start. To run it standalone: + +```bash +pnpm generate-pwa-assets +``` + +Outputs land in `public/icons/` (gitignored). + +## Build pipeline + +1. `BRAND_DIR` is resolved (defaults to `./branding/default`). +2. `vite-branding.ts` reads `brand.json` and exposes `@brand/` alias. +3. `brandAssetsPlugin()` (registered in every `vite.*.config.ts`) runs `scripts/generate-pwa-assets.mjs` once per build via `buildStart`. +4. The script stages the source logo into `public/icons/.brand-source.{svg,png}`, runs `pwa-assets-generator`, then deletes the staged source. +5. Vite copies `public/icons/` into `dist/icons/`. Manifest references `icons/.png`. HTML `` tags reference `/icons/.{ico,png}`. + +## Integration with NixOS deployment + +See [aiolabs/webapp#95](https://git.atitlan.io/aiolabs/webapp/issues/95) for the full architecture. In short: `deploy/server-deploy/hosts//branding/` will hold per-host brands, and each host's `services/webapp.nix` will call `inputs.webapp.lib.mkWebapp { brandDir = ./../branding; }` once `lib.mkWebapp` is exposed from `flake.nix` (separate follow-up issue). + +The architectural payoff: brand and code become independent axes. Logo changes ship via server-deploy commits + redeploys — no webapp release, no `flake.lock` bump.