Docs / design-system/philosophy.md · mirrored from the repo
Namaste Ji Design System — Philosophy & Maintenance
Why the system looks the way it does, the rules that keep it coherent, and the playbook for changing it. Read this before touching any UI. The token values live in tokens.css / tokens.json; the visual truth lives in previews/ and the Claude Design project “Namaste Ji Design System”.
1. Philosophies (the why)
P1 — Festive, never gaudy; ornate, but crafted
The governing principle from the brand. Our audience associates celebration with color and abundance — but cheap festive (clashing gradients, drop shadows on everything, five colors per screen) reads as untrustworthy. Restraint is what makes festive feel premium: one dominant primary, gold at most once per screen, charcoal ink for everything that must be read. When in doubt, remove decoration and let the greeting image carry the celebration.
P2 — The two-zone model
One app, two grounds — this resolves “the brand is bright” vs “a feed is dark”:
- Feed zone (immersive theatre): Charcoal
#1C1A18, edge-to-edge imagery, glass overlays, white text. The greeting image IS the product; chrome exists only to serve it and must never compete with it. - Chrome zone (festival morning): Warm Paper
#F9F7F4+ Crisp White cards, Charcoal ink, Sunrise Orange actions. Login, onboarding, settings, sheets — and the entire BO console.
No user-facing theme toggle; the zones are fixed by design. Every new surface must declare its zone first — the zone decides the ground, text color, and whether overlays are glass or solid.
P3 — Elder-first, low-literacy-first (design for the 35+ aunty, delight the nephew)
Our median user is 35+, possibly newly online, on a low-end Android phone. Rules that follow and are non-negotiable:
- Minimum body text 16px in chrome; generous line-height; Indic scripts optically larger (+1–2px vs Latin).
- Touch targets ≥48px; primary CTAs 52px.
- Never icon-only. Every rail icon gets an 11px label in the user’s language. Recognition over recall, always.
- Contrast ≥4.5:1 everywhere; the feed’s bottom gradient exists to guarantee caption contrast on any image.
- Kind copy: errors explain the fix warmly (“कोई बात नहीं, ji”) — never blame, never “Invalid input”, never urgency or fear.
P4 — Recognition over brand purity
Familiarity beats elegance for this audience. The WhatsApp-green share CTA is the
canonical example: it “breaks” the single-primary discipline deliberately, because
#25D366 + the glyph is instantly understood by the TG (the ShareChat-proven pattern).
Such exceptions are allowed but must be explicit, singular, and documented —
one functional color per function, listed in tokens.json under functional.
P5 — The share is the product
The dominant action on every content surface is sending the greeting onward. Layout, hierarchy, and motion all serve time-to-share: the CTA is the largest tap target on screen, always visible, always labeled, always in the user’s language. Everything else (save, download, navigate) is secondary and lives in quieter affordances.
P6 — Tokens are law
No component anywhere renders a color, size, radius, or easing that isn’t a token.
This is what lets agents (and future-you) restyle the entire product by editing one
file. Enforced by lint in apps/consumer (no hex literals outside theme.ts) and by
review convention in apps/console.
P7 — One system, many surfaces
The consumer app, the BO console, mockups, and generated marketing collateral all draw from the same tokens. The console is not a separate design world — it is the chrome zone applied to back-office objects (see ../console/DESIGN-PATTERNS.md for the object presentation contracts that sit on top).
2. Decision rules (fast answers)
| Question | Answer |
|---|---|
| What color is this action? | Primary action → Sunrise Orange. Destructive → Kumkum Red + confirm. Share-to-WhatsApp → WhatsApp Green. Everything else → not colored. |
| Can I add a new color? | No. If a function genuinely needs one (like WhatsApp green), add it to functional in tokens.json with a one-line justification, update previews, re-sync. |
| Which font? | Headings/display → Poppins 600/700. Everything else → Inter 400/500 (+ Noto Sans Devanagari fallback). No third font, no extra weights. |
| Radius? | Cards 24 · inputs/small 12–16 · buttons/chips pill (100). |
| Is this overlay glass or solid? | Feed zone / over imagery → glass (light or dark recipe, always with the 1px white border). Chrome zone → solid white card + border. |
| Motion? | Press scale(0.96)/100ms · entry fadeUp 400ms · feed snap mandatory. Nothing else without updating the system. Respect prefers-reduced-motion. |
| New screen: where do I start? | Declare the zone → compose from existing preview components → only then design anything new, as a system addition (not a one-off). |
3. Maintenance playbook (the how)
Source-of-truth chain
docs/brand-tokens.json ← the brand (locked; changes are founder decisions)
└─ docs/design-system/tokens.css + tokens.json ← canonical UI tokens (THIS system)
├─ apps/consumer/src/theme.ts ← consumer theme module
├─ apps/console/src/styles/theme.css ← console CSS variables
└─ previews/*.html ⇄ Claude Design project ← visual truth, managed in claude.ai/design
Changing a token
- Edit
tokens.cssandtokens.json(they must stay identical). - Propagate to
apps/consumer/src/theme.tsandapps/console/src/styles/theme.css. - Update any preview card whose rendered value changed.
- Re-sync to Claude Design (below). One atomic commit for the whole change.
Adding/changing a component
- Design it in the relevant
previews/*.htmlcard first (or a new card with a first-line@dsCardmarker:<!-- @dsCard group="…" name="…" subtitle="…" width="…" height="…" -->). Cards are self-contained HTML — tokens inlined, Google-Fonts link, no external assets. - Implement it in the app(s) from tokens.
- Re-sync. A component that exists in an app but not in a preview card is a bug.
Syncing with Claude Design
- Push (repo → Claude Design): DesignSync
finalize_plan(localDirdocs/design-system, writes = changed paths) →write_fileswithlocalPath. The@dsCardmarkers auto-index the cards — no manual registration. - Pull (Claude Design → repo): if the design was edited in the claude.ai/design
UI (e.g. during a look-and-feel session),
list_files+get_filethe changed paths back intodocs/design-systembefore any local edit, so nothing is clobbered. The repo copy is the merge point; git history is the audit trail. - Never wholesale-replace the project; sync incrementally, component by component.
Local preview
.claude/launch.json → design-system serves docs/design-system on
http://localhost:8811 (cards at /previews/*.html).
Guardrails in CI/lint
apps/consumer/eslint.config.js: hex literal outsidesrc/theme.ts= error; raw JSX strings = error (i18n rule) — both protect P3/P6.- Review checklist for any UI PR: zone declared? tokens only? labels on icons? contrast held? preview card updated?
Cadence
- After any UI-touching PR: check whether a preview card drifted from the shipped component; fix in the same PR.
- Before a look-and-feel overhaul (planned): branch, iterate in Claude Design and/or previews first, validate on-device, then propagate tokens — the chain makes a restyle a token diff, not a rewrite.