---
title: "Design"
description: "The hi-fi gallery, the botgumi stages mapped onto it, the checks and the pending gates."
source: "design/README.md"
---

> Part of [Brand and design](/design/llms.txt). Every page: [llms.txt](/llms.txt).
> View: [Hi-fi gallery](/design/gallery/index.html)

# Shuke / 述刻 — hi-fi design v1

Static HTML/CSS/JS. No build step is needed to view anything here. Every screen and state is drawn at 393 × 852 pt (iPhone 15/16 Pro) in **both UI languages** (zh-Hans and en, ADR-001 D13), shares one token layer, and carries `data-bind` annotations to the API contract.

## botgumi stages (ADR-0004)

This repo follows the botgumi template (`.botgumi.json`); its design process has five stages, each closed by a
human gate. Shuke's design was finished before those gates existed, so the stage files sit on top of the gallery
below without redrawing anything, and every gate is **retroactive and pending**: no gate issue has been opened, so
no screen is `approved` yet. `design/check.mjs` (botgumi's structural check) passes on this folder.

| # | Stage | Botgumi output | What exists here | Gate |
|---|---|---|---|---|
| 1 | Brand brief | `brand/brief.md`, `brand/mark.svg` | [`brand/brief.md`](/design/brand/index.md) filled from the README and ADR-001; name, domain and mark are open | pending |
| 2 | Design system | `system/design-system.md`, `system/tokens.source.json` | [`system/design-system.md`](/design/design-system/index.md) points at `tokens.md` and `base.css`; `system/tokens.source.json` mirrors `tokens.css` in the template's shape (generated, must be kept in step) | pending |
| 3 | Lo-fi | `lofi/screens.md`, `lofi/wireframes/` | [`lofi/screens.md`](/design/screens/index.md): every screen with a stable ID (S01…S34), its states and flows, generated from `screens.json`, the screen contract (botgumi ADR-0006). The lo-fi stage itself was skipped: the gallery is the wireframe set and the prototype (`lofi/wireframes/README.md`) | skipped |
| 4 | Hi-fi | `hifi/<ID>/screen.md`, `hifi/<ID>/bindings.md`, boards | [`hifi/<ID>/`](/design/hifi/index.md) per screen: contract, a board per state (the gallery files), tokens used, strings, and the data-binding map; every screen is at `hifi` | pending, per screen |
| 5 | Screenshot direction | `screenshots/direction.md` | [`screenshots/direction.md`](/design/screenshots/index.md), not started | pending |

`screens.json` is the screen contract (botgumi ADR-0006, D1): every screen, its stage and gate, its states with their
boards per locale, example data and binds, its calls, binding fields, tokens and strings. For now it is exported
from the gallery by `tools/hifi_index.py`, because `tools/build.py` still draws the boards; the pages under `lofi/`
and `hifi/` and the screen pages of `docs/manifest.json` are generated from it by botgumi's `botgumi-design index`.

Checks (CI runs all of them in `.github/workflows/design.yml`, with botgumi's packages from GitHub Packages):

```bash
node design/check.mjs                           # token shape, screen list, wireframe per screen, hi-fi folders, boards per state, binding maps
node --test design/check.test.mjs               # the check's own tests
python3 design/tools/tokens_source.py --check   # system/tokens.source.json is in step with tokens.css
python3 design/tools/hifi_index.py --check      # screens.json and lofi/wireframes/S*.md are in step with the gallery
pnpm design:check                               # all of the above, then botgumi-design check: the contract's rules, every board and example, tokens, stale pages
```

Gaps: the four required states (`loading`, `empty`, `error`, `offline`) are listed for every screen, but where the
gallery has no board of its own for one, `hifi/<ID>/screen.md` says so and quotes `states.md`; elevation, motion and font-stack tokens have no group in
`tokens.source.json` and stay in `tokens.css`. Each bound field has a typed source checked against
`docs/api/openapi.yaml` (botgumi ADR-0006 D2); the six that wait on CCR-14 are `pending`.

## How to view

Through the docs site: `pnpm docs:dev` at the repo root, then <http://127.0.0.1:4321/design/gallery/> (the gallery
below, served with its tokens, components and fixtures), <http://127.0.0.1:4321/design/hifi/s01/> for a screen's
contract and binding map, and <http://127.0.0.1:4321/api/reference.html> for the rendered API. The hosted docs serve
the same paths. Or from disk:

1. Open **[`screens/index.html`](/design/gallery/index.html)** in a browser (double-click works; `file://` is fine). This is the gallery: every screen/state as a live thumbnail, grouped by flow.
   - **Language:** 中文 / English swaps every screen. Deep link with `index.html?lang=en`.
   - **Theme:** light / dark. **Type:** Dynamic Type 100 / 120 / 135 %. **Show:** data-bind outlines, reduced motion, increased contrast. **Zoom:** S / M / L.
2. Click a thumbnail to open the screen full size. The **spec panel** on the right lists the state description, API calls, local state, interaction notes, sibling states, and a link to the other language. Press **b** to outline every bound element with its source path.
3. The **paywall is interactive**: open `screens/paywall/paywall--default.html` (or `.en.html`), drag the 3/5/7 slider and switch plans. The projection, calendar, billing date and CTA update from the embedded `/v1/paywall` + StoreKit JSON.

URL parameters work on any screen file: `?theme=dark&dt=1.2&motion=reduced&contrast=high&binds=1`.

## Index

| Deliverable | File | What it is |
|---|---|---|
| Gallery | [`screens/index.html`](/design/gallery/index.html) | 102 zh-Hans + 101 en screens/states in 15 groups |
| Screens | `screens/<group>/<screen>--<state>.html` (zh-Hans), `….en.html` (en) | One file per screen per state per language |
| Screen manifest | [`screens/manifest.json`](/design/gallery/manifest.json) | Every file with title, description, API calls, local state, data binds |
| Tokens | [`tokens.css`](/design/tokens.css) + [`tokens.md`](/design/tokens/index.md) | Colour (light/dark/high-contrast), type (iOS text styles), spacing, radii, elevation, motion, haptics |
| Token source (botgumi shape) | `system/tokens.source.json` | Generated mirror of `tokens.css` for `design/check.mjs` and `@botgumi/design-tokens`; regenerate after any token change |
| Base components | [`base.css`](/design/base.css), [`base.js`](/design/base.js) | Shared components + viewer (theme / type / bindings / count-ups) |
| Strings | [`strings.json`](/design/strings.json) + [`copy.md`](/design/copy/index.md) | Every client string keyed, **en and zh-Hans** (xcstrings-shaped JSON; copy.md is generated) |
| Example data | `../docs/api/examples/` `en/`, `zh-Hans/`, `index.json` | API-shaped responses behind every number on screen (seed data), each validated against its operation by `botgumi-design check` |
| Flows | [`flows.md`](/design/flows/index.md) | 9 flows as Mermaid + step tables (screen, trigger, API, success, failure, exit) |
| States | [`states.md`](/design/states/index.md) | Screen × {loading, empty, error-retryable, error-fatal, offline, partial} |
| Data binding | [`data-binding.md`](/design/data-binding/index.md) | Element → source → format → fallback for every screen, and the **contract change requests** |
| Onboarding | [`onboarding.md`](/design/onboarding/index.md) | Rationale, questions, mapping to `/v1/onboarding` and the plan |
| Paywall | [`paywall.md`](/design/paywall/index.md) | Projection formula, calendar rules, honesty rules |
| Engagement | [`engagement.md`](/design/engagement/index.md) | Quest, XP, streak, levels, achievements, notifications, haptics/motion per moment, dark patterns not used |
| iOS handoff | [`ios-handoff.md`](/design/ios-handoff/index.md) | SwiftUI component map, SF Symbols, localization, Dynamic Type, VoiceOver labels, hit targets |
| Generator | `tools/` | `build.py` + fixtures + string catalog + screen templates (stdlib Python) |
| Stage pages | `screens.json`, `lofi/`, `hifi/`, `brand/`, `system/`, `screenshots/` | The botgumi stage files (see the top of this page); `screens.json` is exported by `tools/hifi_index.py`, and `lofi/screens.md` and `hifi/` are generated from it by `pnpm design:index` |

### Screen groups

Onboarding (welcome, **practice language**, goal, scenario, self-level, commitment, notification priming) · Diagnostic (intro, read, mic purpose sheet, record × 6, processing × 5, result reveal) · Plan · Paywall × 6 · Home × 10 · Library × 6 · Read × 3 · Record round 1 × 7 · Processing × 7 · Feedback × 6 · Compress round 2 × 7 · Complete × 6 · Growth × 4 · Profile & settings × 8 (incl. languages) · Global × 5.

## How iOS should consume this

1. **Tokens → code.** Mirror `tokens.css` into `DesignSystem/Tokens.swift` (`Color.accentPrimary`, `Spacing.s4`, `Radius.card`, `Motion.base`, `Font.shuke(.headline)`) and an asset catalog with Any / Dark / High-Contrast variants. Names map 1:1 (tokens.md).
2. **Strings → `Localizable.xcstrings`.** Convert `strings.json` directly (same key, `en` source, `zh-Hans` translation, `**bold**` markdown). Never hard-code a string or a unit.
3. **Screens → views.** Use the gallery for layout and states, and the spec panel for API calls. `data-binding.md` is the field-by-field contract for each view model. Components and system/custom decisions are in `ios-handoff.md`.
4. **Example data → previews/tests.** `docs/api/examples/<locale>/*.json` decode straight into the API models. Use them for `#Preview` and snapshot tests in both locales (zh-Hans persona 晓雯 practises zh-Hans + en; en persona Mia practises en).
5. **States.** Every screen must implement the cells in `states.md`. Reviewers check against the gallery.
6. **Contract gaps.** Fields the screens need but the contract lacks are listed at the top of `data-binding.md` with fallbacks. CCR-1…13 were applied in #8; CCR-14 is open. Each needs an `openapi.yaml` PR. The design track does not edit the contract.

## Regenerating

The committed HTML is the deliverable; viewing needs nothing. To change content or templates:

```bash
python3 design/tools/build.py          # rewrites screens/, docs/api/examples/, strings.json, copy.md; runs structural checks
python3 design/tools/tokens_source.py  # rewrites system/tokens.source.json from tokens.css (after a token change)
python3 design/tools/hifi_index.py     # rewrites screens.json and lofi/wireframes/S*.md from the gallery
pnpm design:index                      # rewrites lofi/screens.md, hifi/S*/ and the screen pages in docs/manifest.json from screens.json
pnpm docs:build                        # rebuilds docs/public/
```

Run them in that order after a change. `hifi_index.py` keeps each screen's ID, stage and gate from the committed
`screens.json`, so an approved screen stays approved.

The build fails on unbalanced HTML, duplicate ids, lorem ipsum, a missing string key in either language, or any CJK text leaking into an English screen.

## Visual language (kept from the prototype, polished)

Warm off-white canvas `#FAF9F5` / `#F5F2E9`, ink `#171717` cards for the moments that matter (today's quest, **Change just one thing / 这次只改一件事**, the before/after block), coral `#FF6030` **only** for the primary action and live recording, lime `#DFFC66` **only** for rewards and levels, violet / green / amber for topics and dimensions. Avenir Next + PingFang SC, pill + 16–20 pt radii, the concentric-ring record button. Removed per ADR-001: the 4th 迁移 step, fixed numbers, the 3-second gate, the desktop frame, unconditional praise.
