Flat v2 page boards — the contract every Phase C board follows (2026-10-09)
Status: Active · Date: 2026-10-09 · Phase C of flat-grammar-v2-migration-plan.md. Owner: "design the layouts for all of the pages based on the new components library." Inputs: the grammar (§4b seams), the component library (§3–§15), the behaviour addendum, the IA and flows (§4 template groups, §6 rulings), scheme S2. Every page board is drawn under this contract so the boards read as one system.
1. Library only
A page is composed only from library components (§3–§14) in their specified geometry and states. When a page needs something the library does not have, the board does not invent it: it draws the closest library composition, marks the spot "library gap", and lists it in the board's gaps panel (the library is extended first, then the page). Primitives are copied from the library boards (flat-v2-components.jsx, flat-v2-controls.jsx, flat-v2-patterns.jsx); the old kit's WF* layout helpers are never used.
2. Frames
390 × 844 pt at 1:1, status bar 44, home inset 34; a page longer than 844 is drawn as a scroll capture with the 844 fold marked. Rail 20; 4pt grid; the S2 palette (FV_PAL_S2). Korean in-app copy per the terminology guide; English only in annotations.
3. What each page shows
| Axis | Requirement |
|---|---|
| Ideal | every route of the template, populated for its primary role |
| States | empty / first-run (the right kind: first-run, filtered-empty, permission wall), loading (one skeleton per screen at the v2 pitches), error and offline (cold offline is never "empty"; stale data shows the offline strip), overflow (long names wrap and are never cut, many rows with section caps and 전체 보기, 99+, 20-character club names) — for every route at least the empty and loading frames; the full set for the representative pages the IA doc names |
| English | the representative pages in en (ko and en ship): Tags stay 1–2 words, sentence case, plurals |
| 200% text | the representative pages at 200% per the addendum (B6): trailing under line 2, Cells stacked, roster 2-up, chrome capped |
| Roles | the role variants the IA doc lists per page (member, official, host, guest / non-member, blocked, archived, signed out) |
| Dark | one dark frame per page family |
| Overlays | every sheet, dialog, menu and ActionSheet the page opens, drawn on its trigger page |
4. Annotation per page
Beside each phone: the route and template; the stack top → bottom with pt values and library component names; the one coloured action (or "none"); the data each row reads (the view model or hook today); every navigation out (route, presentation); the accessibility headings and the first three spoken labels (B8); the IA ruling or flow it implements; what changed versus today (one line).
5. Rules checked on every page (and printed in the board's verification table, DOM-measured)
Rail 20 / 370 · every box on the 4pt grid (exemptions listed with reasons; spacing values — pads, gaps, seams — are never exempt, while a height set by text lines, n × 22, is a standard exemption) · type nodes only on the scale (12/16, 13/18, 15/22, 17/24, 20/28, 24/32, 40/48) · media rows 80, person rows 68, cells 48 (min-heights) · section seams 32 ink-to-ink, no line between sections, at most one band · one coloured action per screen (FAB or CTA) and at most one Block per hub · one trailing element per row · zero glyphs in rows (hero facts only) · no shadows · no middle dots (MetaBreak) · Tags ≤ 2 per object · every interactive element ≥ 44 target.
6. Process
Read the screen's blueprint (docs/architecture/screen-blueprints/*.md) and its current code before drawing (what data and actions exist); draw; DOM-measure (a scroll capture takes its height from its board's table, HUB_BOTTOM or FM_NEED: yarn measure:board-heights re-derives both from the built boards and fails on drift, and --emit hub|forms prints a table to apply); screenshot at 1800 wide (--disable-lcd-text) and look at every strip as a critic (alignment, gaps, cramped rows, states visibly different, nothing clipped); fix and re-shoot; register the board in scripts/build-wireframes.mjs with groundedIn = every screen file the board redraws, then REGROUND=<key>; prettier --check. Boards show final states only; one question per proposal where an owner question exists; decisions already ruled (IA §6, library §13–§15) are drawn, not re-asked.
7. Boards
| Board | Routes (IA §4) | Representative pages for the full state set |
|---|---|---|
flat-v2-hub | 홈, 기록, 프로필, 클럽 홈 (+ its six panes) | 홈, 클럽 홈 |
flat-v2-list-a | session lists, club lists (members, dues, sessions, venues, join requests), notifications, messages | 번개 찾기, 멤버, 회비 |
flat-v2-list-b | records, leaderboards, history, rivals, venue directory and contributions, admin lists | 리더보드, 테니스장 |
flat-v2-detail | session detail (first, with its CTA state strip), venue, post, record, player, match board (the club preview retired, review 41) | 일정 상세 |
flat-v2-forms | create session (default-first), create club, dues edit, contribution and edit forms, the six settings routes | 일정 만들기, 설정 |
flat-v2-auth | sign-in, onboarding (first-action chooser), consent, the public share receivers | 온보딩 |
flat-v2-flows | the nine task flows of IA §3 as screen sequences with tap counts (today → target) | — |
8. Review format (owner, 2026-10-11)
Owner: "clean up and organize the wireframe pages … getting rid of unnecessary and/or stale specs and explanations and meta data so that the reviewer doesn't have to read through tons of stuff they don't need to ingest." Every flat v2 board, library and pages alike, follows this format. It supersedes the annotation requirements of §4, which now apply only inside the spec layer.
| Layer | What it holds | Visible by default |
|---|---|---|
| Board head | the title and one sentence on what the board is for; the open owner questions, if any, one line each | yes |
| Sections | one per component (library) or per page (pages): the name, one sentence on its job, then its frames in a row: the ideal first, then states and variants. Each frame has a caption of at most one line saying what differs from the ideal. | yes |
| Spec layer | anatomy rulers, measurements, behaviour tables, the spoken labels, motion values, what the component replaces in code, and the DOM verification. It must be accurate to the current library and is kept for the build. | no: one "Show specs" toggle per board, closed |
Removed from every board: build history ("Phase B", "round 3", "was / now"), notes that restate a ruling's reasoning (the decision log holds them), panels for questions already ruled, "library gap" tables once the library covers them, duplicated frames, and any note that contradicts the current library. A frame earns its place by showing something the reviewer must judge; a state that only repeats another at a different value is dropped or folded into a caption.
Implementation: annotation markup carries data-spec, and the page's toggle shows or hides every data-spec element. The DOM verification still runs over the frames and prints into the spec layer.
9. The shared kit (2026-10-11)
Every flat v2 board composes from one kit; no board keeps a private copy of a primitive. Before the kit, each board carried its own palette and primitives (146,000 lines across 13 boards), which is how components drifted between boards.
| File | Holds |
|---|---|
wireframes/flat-v2-kit.jsx (core) | tokens (FVK_LIGHT, FVK_DARK, fvkTagTones), type roles with minimums and scale caps (FVK_TYPE, fvkType), the width-aware rail (fvkRail), context (FvkProvider, useFvk), text (FvkT), icons (FVK_ICONS, FvkIcon), the phone (FvkPhone, FvkKeyboard) and the Android system bars (FvkAndroidStatus, FvkSysNav), the specimen stage (FvkStage), the board scaffolding (FvkBoard, FvkSection, FvkFrames, FvkFrame, FvkGroup), the spec layer (FvkSpec, FvkSpecTable, FvkGuide), helpers (FvkMeta, FvkBreak, FvkCellLine, fvkL), and the marks drawn over a frame after layout (FvkFlowStep for taps, FvkFocusOrder for the numbered stops of a screen reader and for gesture zones, each placed by a script that finds the control by its spoken name or visible text) |
flat-v2-kit-chrome.jsx | library part A §3: header, tabs, tab bar, FAB, CTA band, sticky edges, MediaBand, Live row, WizardShell header and progress, Search takeover, header badge, coachmark |
flat-v2-kit-content.jsx | library part B: blocks, strip, hero, notice, caption row, band, chart, heatmap, calendar, podium, form strip, photo grid, shelf, thumbs; rows and cells; labels and avatars |
flat-v2-kit-controls.jsx | library part C: controls and fields, overlays and feedback, conversation, scoring |
Rules for kit authors.
- Export with
functionorvaronly: the build evals each file into one global scope, whereconstandletare not shared. - Prefix every global
Fvk(components),FVK_(data) orfvk(helpers). - One component per pattern, with props for every variant and state (
state="pressed",tone="danger",size="sm"). - Read every colour, size and space from the core; never a literal hex outside the core.
- Mark measurable parts with
data-g(the part's name),data-hit(a target),data-railanddata-rail-r(an edge that must sit on the rail), anddata-t(text, set byFvkT), so one verification script can check every board.
Rules for board authors.
- A board is a composition:
FvkBoard›FvkSection›FvkFrames›FvkFrame›FvkPhoneorFvkStage› kit components. - Captions are one line.
- Rulers, anatomy and tables go in
FvkSpecorFvkSpecTable. - A board that needs something the kit lacks adds it to the kit family file, never to the board.
Toast placement (forms pass, 2026-10-20). A frame's Toast is drawn through the frame helper's toast prop (its text and action): the helper places it 16 above the tallest layer under it (the CTA band the frame draws, taller with a helper line; else the home inset). No frame passes its own pin.