|
1 | 1 | # Rebranding / white-labeling |
2 | 2 |
|
3 | | -Brand identity is data + two scripts. The visual + text rebrand happy path: |
| 3 | +Brand identity is **one JSON file + a folder of SVGs + one command**. The visual |
| 4 | ++ text rebrand happy path: |
4 | 5 |
|
5 | | -## 1. Edit the config (`src/config/`) |
| 6 | +## 1. Edit `src/config/brand.json` |
6 | 7 |
|
7 | | -- **`brand-meta.json`** — `name`, `hosts` (your web domains), `socialHandle`. |
8 | | -- **`brand-colors.json`** — `neutral` ramp, `accents` (the selectable families), `defaultAccent`. |
9 | | -- **`brand-logo.json`** — `flat` wordmark (required). Set `dimensional: null` if you have no 3D logo; hero surfaces fall back to the flat wordmark in the accent. |
10 | | -- **`brand.ts`** — `links` (legal/support/download URLs). |
| 8 | +The single source of truth, editor-validated by `brand.schema.json` (your IDE |
| 9 | +flags missing keys, bad hex values, an unknown `defaultAccent`, etc.). Sections: |
11 | 10 |
|
12 | | -## 2. Drop in the app icon |
| 11 | +- **identity** — `name`, `hosts` (your web domains; `hosts[0]` is primary), |
| 12 | + `socialHandle` (X/Twitter @, empty to omit). |
| 13 | +- **`colors`** — `neutral` (the contrast_ ramp), `accents` (the selectable |
| 14 | + primary_ families), `defaultAccent` (the one this build ships). |
| 15 | +- **`oauth`** — `defaultBaseUrl` (your domain), `clientName`, `scope` / |
| 16 | + `declaredScope`, `handleResolver`, `signupPdsHost`. |
| 17 | +- **`links`** — legal / support / download URLs (point them at your own pages). |
| 18 | +- **`services`** — atproto endpoints; default to the public Bluesky network, |
| 19 | + override only what you self-host. |
| 20 | +- **`verification`**, **`ageAssurance`** — trust roots / age backend. |
13 | 21 |
|
14 | | -Replace `assets/app-icons/ios_icon_default_next.png` with your 1024×1024 square tile. |
| 22 | +Build-time `EXPO_PUBLIC_*` env vars override a few of these per deployment (see |
| 23 | +`.env.example`); keep those in the env, not the JSON. |
| 24 | + |
| 25 | +## 2. Drop in your logos (`assets/brand/`) |
| 26 | + |
| 27 | +One SVG per role. Only `mark.svg` is **required**; the rest are optional and fall |
| 28 | +back to it, so a single-glyph brand and a symbol+wordmark brand both work: |
| 29 | + |
| 30 | +| file | role | |
| 31 | +| ------------- | ----------------------------------------------- | |
| 32 | +| `mark.svg` | the symbol/glyph (required; fallback for all) | |
| 33 | +| `wordmark.svg`| the styled brand name | |
| 34 | +| `lockup.svg` | symbol + word together | |
| 35 | +| `hero.svg` | large / marketing (a multi-tone "3D" logo lives here) | |
| 36 | +| `icon.svg` | app-icon-specific art (else the mark on a tile) | |
| 37 | + |
| 38 | +**Theming convention** so one SVG follows light/dark + the accent picker: |
| 39 | + |
| 40 | +- `fill="currentColor"` → the primary tint (driven by the component). |
| 41 | +- `fill="theme:<paletteKey>"` (e.g. `theme:primary_900`) → substituted from the |
| 42 | + active palette at render. This is how a two-tone `hero.svg` follows the accent; |
| 43 | + there is no special "dimensional" data shape any more. |
| 44 | + |
| 45 | +Plain colours (hex/rgb) render as-authored (for genuinely multi-colour logos). |
15 | 46 |
|
16 | 47 | ## 3. Run the generators |
17 | 48 |
|
18 | 49 | ```bash |
19 | | -pnpm brand:gen-favicons # favicons + safari mask, from the icon tile |
20 | | -pnpm brand:sync-web # writes colors/splash/og/title into web/index.html + bskyweb/templates/base.html |
21 | | -pnpm brand:check-web # CI guard: non-zero if the above is out of sync |
| 50 | +pnpm brand # gen-logo + sync-web + favicons - the full visual rebrand |
| 51 | +pnpm brand:check # CI guard: non-zero if the generated artifacts are stale |
22 | 52 | ``` |
23 | 53 |
|
24 | | -That's the full visual + text rebrand. `BRAND.name` propagates through the UI automatically; the upstream "Bluesky" → name swap lives in `src/config/brandStrings.ts` (add message IDs there if any slip through). |
| 54 | +Under the hood (run individually if you like): |
| 55 | + |
| 56 | +- `pnpm brand:gen-logo` — `assets/brand/*.svg` → `src/config/brand-logo.generated.json` |
| 57 | + (committed; consumed by `<BrandLogo>`, the splash, and the favicon mask). |
| 58 | +- `pnpm brand:sync-web` — writes the colours / splash / og / title into the |
| 59 | + pre-boot HTML (`web/index.html`, `bskyweb/templates/base.html`). |
| 60 | +- `pnpm brand:gen-favicons` — favicons + Safari mask from the icon master PNG. |
| 61 | + |
| 62 | +That's the full visual + text rebrand. `BRAND.name` propagates through the UI |
| 63 | +automatically; the upstream "Bluesky" → name swap lives in |
| 64 | +`src/config/brandStrings.ts` (add message IDs there if any slip through). |
| 65 | + |
| 66 | +## App icon + OG image (optional `gen-raster`) |
| 67 | + |
| 68 | +Favicons are generated from the icon master at |
| 69 | +`assets/app-icons/ios_icon_default_next.png` — replace it with your 1024×1024 |
| 70 | +square tile, or generate it from SVG: |
| 71 | + |
| 72 | +```bash |
| 73 | +pnpm brand:gen-raster # from assets/brand/{icon,og}.svg if present |
| 74 | +pnpm brand:gen-raster --compose # else compose defaults from your mark |
| 75 | +``` |
| 76 | + |
| 77 | +`gen-raster` is **optional and not a project dependency**. It auto-detects a |
| 78 | +rasterizer — `@resvg/resvg-js` (install it yourself, never committed) → |
| 79 | +`rsvg-convert` (`brew install librsvg`) → `magick` (ImageMagick) — and skips with |
| 80 | +a message if none is present. It is **non-destructive**: it only writes an output |
| 81 | +when its SVG source exists (`icon.svg` → icon master + favicons; `og.svg` → |
| 82 | +`web/og-image.jpg`), or composes a default under `--compose`. A brand with |
| 83 | +hand-designed raster art ships no source SVGs and is never touched. |
| 84 | + |
| 85 | +## OAuth (per deployment) |
| 86 | + |
| 87 | +You run your own OAuth confidential client (`services/oauth`); the `client_id` is |
| 88 | +your domain. Generate a signing keypair once (do **not** commit the private half): |
| 89 | + |
| 90 | +```bash |
| 91 | +node scripts/gen-oauth-keypair.js # writes the public JWKS (commit it); |
| 92 | + # prints the private JWK -> Worker secret |
| 93 | +``` |
| 94 | + |
| 95 | +Deploy with `scripts/deploy-cloudflare.sh` (see `services/oauth/` and |
| 96 | +`services/web/`). Note: the OAuth assertion host must be a **1-level subdomain** |
| 97 | +(`oauth-brand.example.com`) **or** added as a Worker **Custom Domain** — a |
| 98 | +2-level subdomain (`oauth.brand.example.com`) is not covered by Cloudflare's |
| 99 | +Universal SSL and the TLS handshake will fail. |
25 | 100 |
|
26 | 101 | ## Beyond the basics |
27 | 102 |
|
28 | | -- **Services** — edge services live in `services/` (Bunny scripts). Network read APIs default to Bluesky's (until eurosky appview is available). You **must** run your own **OAuth** (`services/oauth` — the client_id is your domain); optionally your own OG / analytics / geolocation / age. Point the app at them via `EXPO_PUBLIC_*` env vars (see `.env.example`). Bluesky's GrowthBook flags + product metrics are toggled by the `EXPO_PUBLIC_ENABLE_*` flags. |
29 | | -- **Native build** (separate pass) — bundle IDs, app name, scheme, app groups, associated domains, EAS / App Store / Sentry / Firebase IDs: `app.config.js`, `eas.json`, `ios/`, `android/`. |
30 | | -- **Content** (optional, still eurosky-specific) — onboarding packs, suggested follows, default feeds, news sources, verifier DIDs: `src/screens/Onboarding/`, `src/features/newsFeed/sources.ts`, `src/lib/constants.ts`. |
| 103 | +- **Services** — edge services live in `services/`. Read APIs default to |
| 104 | + Bluesky's; override per build via `EXPO_PUBLIC_*` (see `.env.example`). |
| 105 | + GrowthBook flags + product metrics toggle via `EXPO_PUBLIC_ENABLE_*`. |
| 106 | +- **Native build** (separate pass) — bundle IDs, app name, scheme, app groups, |
| 107 | + associated domains, EAS / App Store / Sentry / Firebase IDs live in |
| 108 | + `app.config.js`, `eas.json`, `ios/`, `android/`. |
| 109 | +- **Content** (optional) — onboarding packs, suggested follows, default feeds, |
| 110 | + news sources, verifier DIDs: `src/screens/Onboarding/`, |
| 111 | + `src/features/newsFeed/sources.ts`, `src/lib/constants.ts`. |
| 112 | +``` |
0 commit comments