Namaste Ji by Ayushman Dash

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)

QuestionAnswer
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

  1. Edit tokens.css and tokens.json (they must stay identical).
  2. Propagate to apps/consumer/src/theme.ts and apps/console/src/styles/theme.css.
  3. Update any preview card whose rendered value changed.
  4. Re-sync to Claude Design (below). One atomic commit for the whole change.

Adding/changing a component

  1. Design it in the relevant previews/*.html card first (or a new card with a first-line @dsCard marker: <!-- @dsCard group="…" name="…" subtitle="…" width="…" height="…" -->). Cards are self-contained HTML — tokens inlined, Google-Fonts link, no external assets.
  2. Implement it in the app(s) from tokens.
  3. 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 (localDir docs/design-system, writes = changed paths) → write_files with localPath. The @dsCard markers 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_file the changed paths back into docs/design-system before 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.jsondesign-system serves docs/design-system on http://localhost:8811 (cards at /previews/*.html).

Guardrails in CI/lint

  • apps/consumer/eslint.config.js: hex literal outside src/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.