docs(branding): brand kit contract + CLAUDE.md section
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) <noreply@anthropic.com>
This commit is contained in:
parent
3efae30e84
commit
3dfed23b43
2 changed files with 162 additions and 0 deletions
110
branding/README.md
Normal file
110
branding/README.md
Normal file
|
|
@ -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 `<img>` 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/<dep>/icons/<app>/logo.{svg,png}` to override the brand's primary logo for a single standalone build.
|
||||
|
||||
Resolution at build time:
|
||||
|
||||
1. `branding/<dep>/icons/<app>/logo.svg`
|
||||
2. `branding/<dep>/icons/<app>/logo.png`
|
||||
3. `branding/<dep>/logo.svg`
|
||||
4. `branding/<dep>/logo.png`
|
||||
5. Build fails with a clear error pointing here.
|
||||
|
||||
`<app>` 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/<file>` 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/<name>.png`. HTML `<link>` tags reference `/icons/<name>.{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/<host>/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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue