Appearance
Brand & Typography
The brand invariants for QR Setu — the wordmark, the type faces, the one gradient, the icon/monogram pipeline, and the splash policy. Everything here is token-driven (
@qrsetu/tokens) so the DOM web (shadcn/Tailwind) and the RN app (NativeWind) render the identity identically — zero per-stack divergence, zero hard-coded colors (ADR-0011). Verified against the codebase 2026-07-23.
The wordmark — "QR setu"
- Rendered by the
@/uiWordmarkprimitive. The brand renders lowercase "setu" with a single space:QR setu. - "QR" is filled with the brand gradient (below); "setu" uses the
brand-setuink token (210 48% 24%light /210 30% 96%dark). - Face: Akaya Kanadaka (
fonts.brand, single 400 weight —AkayaKanadaka_400Regular). This face is reserved exclusively for the wordmark, never body/UI text. - Bunya is design-time source only — it is personal-use licensed and must never be bundled (no
expo-font/@font-face). The outlined-vector wordmark substitute exists for that reason; Akaya Kanadaka is the shippable brand face. See the tracker's Bunya-license risk row.
Type faces
| Role | Family | Token | Notes |
|---|---|---|---|
| UI / body | Plus Jakarta Sans | fonts.ui (400–800) | Default app text (AppText). No Devanagari glyphs. |
| Devanagari | Noto Sans Devanagari | fonts.deva (400/700) | Any Devanagari or mixed Deva+Latin string (AppText script="deva"). |
| Headline display | Baloo 2 | fonts.display (700 — Baloo2_700Bold) | Onboarding/celebration headlines. Covers Devanagari + Latin in one family, so mixed-script headlines stay in one face. |
| Brand wordmark | Akaya Kanadaka | fonts.brand (400) | Wordmark only. |
| Mono | (see fonts.mono) | fonts.mono | OTP cells, step labels, code-ish accents. |
The one gradient — the QR monogram
There is one brand accent gradient, used everywhere emphasis or brand identity is wanted — never a flat accent color for these:
- Tokens:
brand-qr-from43 100% 58%(warm amber) →brand-qr-to11 100% 60%(coral). Exposed asbrandQrFrom/brandQrTo(wrapped tohsl()), and as NativeWind classes. - Applied to: the wordmark's "QR", the app monogram/icon, the WelcomeStory headline word-highlights, the final-scene "Digital पहचान!" tagline, and the onboarding
SetuCardPreviewband. - RN
<Text>cannot gradient-fill, so gradient text is drawn as measured per-word<Svg>(the@/uiGradientText/GradientHeadlineprimitives) — wraps and renders identically on Android native / iOS native / Web PWA.
Highlight-marker i18n convention
Headline emphasis is authored in the copy itself, per-language, so it is never English-specific:
- Wrap the emphasised words in
*…*in the@qrsetu/i18ncatalog string (e.g.Every business deserves a *digital identity*.). GradientHeadlinerenders the marked spans with the QR gradient;stripMarksyields the plain string for places that must not gradient (e.g. the bilingual secondary subtitle).- A
\nin the copy is a forced line break (kept in i18n, not the component — see WelcomeStory scene 3).
App icon / monogram pipeline
The monogram is a single SVG source of truth, rasterized by a dev-only tool — no committed binary is the source:
- SSOT:
packages/tokens/assets/brand/icon.svg(the QR monogram glyph on the gradient). - Rasterize with
sharp(a dev-only dependency — never bundled into the app) to every required density: the1024²opaque store icon, the web favicon, and the Android adaptive layers (gradient background + white foreground glyph framed inside the ~66% safe zone) + monochrome. expo prebuildregenerates the native icon set fromapp.json.
Splash policy: the native expo-splash-screen is background-only (a flat mark hides the instant fonts load — too fast to register the brand, no room for attribution). The identity is carried by the in-app BrandSplash instead. Keep the native splash logo-less to avoid a duplicate-splash flash.
Animation vocabulary
Driven by the @/ui Entrance / Loop primitives (Reanimated), all reduced-motion-aware:
Entrance—pop(success mark, ring tiles), fades/rises for headlines and CTAs.Loop— gentle continuous float (persona tiles after the ring completes; confetti).- Staggered reveals — the final-scene
RadialHubring pops in sequentially clockwise from top (staggerBase/staggerStepby node index) so the ring visibly "completes". FitBox— scales art/wordmark to fit without distortion.- Under reduced motion, dwell/entrances collapse to a short fade; no essential content is animation-gated.
See also
- Onboarding feature — where these are applied.
- ADR-0011 — surface-matched frontend + the shared design-token package.
- The mobile
@/uiREADME and the onboarding feature README (living docs).