|
| 1 | +# Plan 27 — Brand Identity: the Purple Phone Logo, Everywhere |
| 2 | + |
| 3 | +**Status:** 📝 planned |
| 4 | +**Inspired by:** ServerKit's branding pipeline — one master SVG |
| 5 | +(`frontend/src/assets/ServerKitLogo.svg`: 2048 viewBox, white squircle tile, diagonal |
| 6 | +indigo gradient `#6366f1 → #4f46e5`), a JSX twin (`components/ServerKitLogo.jsx`) whose |
| 7 | +gradient reads **CSS accent variables** so the mark re-tints with the user's accent (unique |
| 8 | +gradient id per instance via `useId()` — shared ids collide and paint nothing), a |
| 9 | +hand-simplified 32×32 stroke favicon, and `serverkit-agent/packaging/icons/generate_icons.py` |
| 10 | +rasterizing the master into `.ico`/tray icons. |
| 11 | +**Depends on:** 12 (accent CSS vars — the JSX logo tints from them), 25 (soft — OTA can |
| 12 | +ship the re-branded APK fleet-wide once phase 3 rebuilds it) |
| 13 | + |
| 14 | +## Problem |
| 15 | + |
| 16 | +DeviceKit has **three different marks and two different brand colors**: |
| 17 | + |
| 18 | +- Web sidebar + login: the lucide `Layers` glyph in a white square (`App.jsx:145-149`, |
| 19 | + `auth/Login.jsx:16-21`) — no `Logo` component exists. |
| 20 | +- Web favicon: a *different* custom phone-outline SVG, emerald `#10b981` on `#050505`. |
| 21 | +- **Android agent: already the target identity** — adaptive icon with solid indigo |
| 22 | + `#6366F1` background + white phone glyph (`ic_launcher_background.xml` / |
| 23 | + `ic_launcher_foreground.xml`), app theme `colorPrimary #6366F1`, dark purple surfaces |
| 24 | + (`#0F0D1A` / `#1E1B2E`). |
| 25 | + |
| 26 | +The "og logo" ask = make the agent's purple-tile-with-phone the canonical mark, draw it |
| 27 | +properly as one master SVG in ServerKit's style, and roll it out to every surface. |
| 28 | + |
| 29 | +## Design for DeviceKit |
| 30 | + |
| 31 | +### Part 1 — The master asset + Logo component |
| 32 | + |
| 33 | +- `frontend/src/assets/DeviceKitLogo.svg` — ServerKit's geometry (white inset tile |
| 34 | + `x/y=150, 1748², rx=150`; gradient squircle ring; glyph in `brandGradient |
| 35 | + #6366f1 → #4f46e5` diagonal) with the server shelves replaced by a **phone**: rounded |
| 36 | + body, white screen cutout, speaker slot, home indicator, and the green `#3ddc97` status |
| 37 | + LED kept for family continuity. Starting draft (refine proportions during execution): |
| 38 | + |
| 39 | +```xml |
| 40 | +<?xml version="1.0" encoding="UTF-8"?> |
| 41 | +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048"> |
| 42 | + <defs> |
| 43 | + <linearGradient id="brandGradient" x1="0%" y1="0%" x2="100%" y2="100%"> |
| 44 | + <stop offset="0%" stop-color="#6366f1"/> |
| 45 | + <stop offset="100%" stop-color="#4f46e5"/> |
| 46 | + </linearGradient> |
| 47 | + </defs> |
| 48 | + <rect x="150" y="150" width="1748" height="1748" rx="150" fill="white"/> |
| 49 | + <!-- outer squircle ring --> |
| 50 | + <path fill="url(#brandGradient)" fill-rule="evenodd" d="M378,70 H1670 A308,308 0 0 1 1978,378 V1670 A308,308 0 0 1 1670,1978 H378 A308,308 0 0 1 70,1670 V378 A308,308 0 0 1 378,70 Z M450,220 A230,230 0 0 0 220,450 V1598 A230,230 0 0 0 450,1828 H1598 A230,230 0 0 0 1828,1598 V450 A230,230 0 0 0 1598,220 Z"/> |
| 51 | + <!-- phone body with screen cutout --> |
| 52 | + <path fill="url(#brandGradient)" fill-rule="evenodd" d="M804,434 H1244 A100,100 0 0 1 1344,534 V1514 A100,100 0 0 1 1244,1614 H804 A100,100 0 0 1 704,1514 V534 A100,100 0 0 1 804,434 Z M794,560 A30,30 0 0 0 764,590 V1390 A30,30 0 0 0 794,1420 H1254 A30,30 0 0 0 1284,1390 V590 A30,30 0 0 0 1254,560 Z"/> |
| 53 | + <rect x="944" y="481" width="160" height="32" rx="16" fill="white"/> |
| 54 | + <rect x="924" y="1501" width="200" height="32" rx="16" fill="white"/> |
| 55 | + <circle cx="1216" cy="628" r="28" fill="#3ddc97"/> |
| 56 | +</svg> |
| 57 | +``` |
| 58 | + |
| 59 | +- `frontend/src/components/Logo.jsx` — same paths, gradient stops wired to the accent ramp |
| 60 | + so the mark follows the user's accent. **Gotcha:** plan 12 stores accent vars as |
| 61 | + space-separated `R G B` triplets for Tailwind alpha, so stops must be |
| 62 | + `stopColor="rgb(var(--accent-hover, 90 103 232))"` etc., and the gradient id must come |
| 63 | + from `useId()` (ServerKit's collision lesson). Props: `size`, `className`. |
| 64 | + |
| 65 | +### Part 2 — Web rollout |
| 66 | + |
| 67 | +- Sidebar header (`App.jsx`) and Login/invite card (`auth/Login.jsx`): swap the white |
| 68 | + `Layers` square for `<Logo size={…}/>`. About pane gets a 64px one. |
| 69 | +- **Favicon:** replace `frontend/public/favicon.svg` with a 32×32 stroke redraw in |
| 70 | + ServerKit's favicon style — gradient tile `#6d7cff → #5a67e8`, white 2px stroke phone, |
| 71 | + green `#3ddc97` LED: |
| 72 | + |
| 73 | +```xml |
| 74 | +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none"> |
| 75 | + <defs> |
| 76 | + <linearGradient id="dkFavTile" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse"> |
| 77 | + <stop stop-color="#6d7cff"/><stop offset="1" stop-color="#5a67e8"/> |
| 78 | + </linearGradient> |
| 79 | + </defs> |
| 80 | + <rect width="32" height="32" rx="7" fill="url(#dkFavTile)"/> |
| 81 | + <g fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
| 82 | + <rect x="10.5" y="5" width="11" height="22" rx="2.5"/> |
| 83 | + <line x1="14.5" y1="23.5" x2="17.5" y2="23.5"/> |
| 84 | + </g> |
| 85 | + <circle cx="23" cy="8" r="2.5" fill="#3ddc97"/> |
| 86 | +</svg> |
| 87 | +``` |
| 88 | + |
| 89 | +- `index.html`: icon links (svg + ico/png rasters if practical), title stays `DeviceKit`. |
| 90 | + Add `public/manifest.json` (name `DeviceKit`, `theme_color #4f46e5`, |
| 91 | + `background_color #000000`, icon `/favicon.svg` maskable) if absent. |
| 92 | + |
| 93 | +### Part 3 — Brand color: purple becomes the default accent |
| 94 | + |
| 95 | +- `theme.js`: `DEFAULT_ACCENT` `#10b981` → **`#6d7cff`** (ServerKit's live periwinkle; |
| 96 | + the static logo asset keeps the deeper `#6366f1/#4f46e5` pair — same two-purples split |
| 97 | + ServerKit uses). Add Periwinkle/Indigo to `ACCENT_PRESETS`; update the |
| 98 | + `appearance.accent` default in `SETTINGS_DEFAULTS`. |
| 99 | +- **Semantic emerald is untouched** — plan 12's rule stands: online/pass/success stays |
| 100 | + `#10b981`; only brand chrome rides the accent ramp. Users with a stored accent keep it |
| 101 | + (settings row wins); only the default changes. |
| 102 | + |
| 103 | +### Part 4 — Android agent alignment |
| 104 | + |
| 105 | +- `ic_launcher_background.xml`: solid `#6366F1` → the diagonal gradient (VectorDrawable |
| 106 | + `<gradient>` inside the adaptive background, API 26+ — already the minimum for |
| 107 | + `mipmap-anydpi-v26`). Align `ic_launcher_foreground.xml`'s phone glyph with the master's |
| 108 | + proportions; touch `ic_notification.xml` if it drifts. App label stays `DeviceKit Agent`. |
| 109 | +- Rebuild via the `build-agent-apk` skill; distribute through plan 25's OTA channel once |
| 110 | + live (until then, hand-flash — same as every agent change today). |
| 111 | + |
| 112 | +## Phases |
| 113 | + |
| 114 | +| Phase | Delivers | Proves | |
| 115 | +|---|---|---| |
| 116 | +| 1 | Master SVG + `Logo.jsx` + sidebar/login/About swap + favicon + manifest | one mark everywhere on web; changing the accent re-tints the sidebar logo live | |
| 117 | +| 2 | Purple default accent (`#6d7cff`), presets updated, settings default | a fresh install boots purple; an existing user's chosen accent survives | |
| 118 | +| 3 | Android adaptive-icon gradient + glyph alignment + APK rebuild | the launcher icon on a real device matches the web favicon family | |
| 119 | + |
| 120 | +## Decisions to make while executing (log, don't stop) |
| 121 | + |
| 122 | +- **Sidebar tile treatment:** full `<Logo/>` mark vs ServerKit's sidebar pattern (lucide |
| 123 | + glyph in a small accent-gradient tile). Recommend the real `<Logo/>` at 26–32px — DeviceKit |
| 124 | + finally has a mark; use it. |
| 125 | +- **Raster favicons** (`.ico`, 16/32 png): generate if a quick tool is at hand |
| 126 | + (sharp/cairosvg one-liner); the SVG link alone covers modern browsers — don't block on it. |
| 127 | +- **`index.html` title** currently `DeviceKit Pro | SamanLabs` — normalize to `DeviceKit` |
| 128 | + (PageTitle already overrides at runtime). |
| 129 | + |
| 130 | +## Definition of done |
| 131 | + |
| 132 | +Sidebar, login, About, browser tab, and the Android launcher all show the same purple |
| 133 | +phone-in-squircle family; the web mark re-tints when the accent changes; no `Layers`-as-logo |
| 134 | +usage remains (grep `Layers` in App.jsx/Login.jsx); phase 3's APK on a physical device shows |
| 135 | +the gradient icon. |
| 136 | + |
| 137 | +## Out of scope |
| 138 | + |
| 139 | +- **Light/system theme + white-label** — plan 28 (white-label will let users *replace* this |
| 140 | + logo; it needs `Logo.jsx` to exist first). |
| 141 | +- **Desktop/tray icon pipeline** (ServerKit's `generate_icons.py`) — DeviceKit has no desktop |
| 142 | + agent; revisit if one appears. |
| 143 | + |
| 144 | +## ServerKit source map (for implementers) |
| 145 | + |
| 146 | +- Master SVG: `frontend/src/assets/ServerKitLogo.svg` (geometry to clone) |
| 147 | +- JSX twin + useId gotcha: `frontend/src/components/ServerKitLogo.jsx` |
| 148 | +- Favicon style: `frontend/public/favicon.svg`; manifest: `frontend/public/manifest.json` |
| 149 | +- Sidebar tile alternative: `components/Sidebar.jsx:325-330` + `styles/components/_sidebar.scss:179` |
| 150 | +- Icon rasterization reference: `serverkit-agent/packaging/icons/generate_icons.py` |
0 commit comments