DESIGN.md · git:20261007.66f8383 · 2026-10-07 · sha256 0b9fdeb0785d2a94

DESIGN.md git:20261007.66f8383A

Immutable. This exact content never changes and is served at /api/v1/blob/0b9fdeb0785d2a94.

# Design
## Source of truth
Status: Active for the local homepage upgrade, 2026-10-03. Reference: public desktop/mobile captures of https://hypit.ai/, https://hypit.ai/quickstart/ and https://hypit.ai/docs/; current zenstory.ai captures; four project READMEs and their immutable video sources. Scope: the organization site (zenstory.ai): home, /projects, /guides, six project pages, practical guides, /compare, glossary, each in English at the root and in 中文 under `/zh`, plus the workbench docs at `/docs`. Implementation: `apps/web/scripts/site-shell.mjs` (head metadata, header, footer, language model shared by every static page), `apps/web/scripts/build-org-pages.mjs` (organization pages, run once per language), `apps/web/scripts/build-docs-pages.mjs` (workbench docs on the same shell, sidebar from `src/data/docsNavigation.ts`) and `apps/web/scripts/org-pages.css` (plain CSS, copied to `/org/org.css`). Content is read from `apps/web/content/*.json` and `apps/web/docs/**/*.md`; article and guide content is preserved while homepage curation is maintained separately. The React workbench and admin are governed by the scoped decisions below, updated 2026-10-07.
## Brand
An open-source story studio that reads as edited and credible. The palette comes from the brand mark: navy `#081431` is the ink for headings, primary buttons and the footer band; cream paper `#faf7f0` with `#f3ecdb` chapter bands; cyan `#22D3EE` only for tiny accents (star glyph, active-nav underline, dark-mode focus ring); warm orange `#b3542e` / text `#9a4523` for eyebrows, actions and link hover. Dark scheme maps the same roles. Reuse `public/brand/zenstory-ai-mark.svg`; social preview is `public/brand/og-zenstory-ai.png` (1200×630). No stock imagery, gradients, badges, testimonials or invented metrics.
## Product goals
Bring the organization homepage’s design, product demonstration and knowledge structure up to the presentation quality of Hypit, while keeping ZenStory’s own brand and factual story-creation scope. Real results appear before a catalog of tools. A visitor can see a demo, understand its input/output, choose a task and follow a practical method. SEO and GEO are acceptance criteria, not promises of ranking or AI citations. No article-count target, invented trust logos, promotional statistics, copied Hypit art or misleading cross-project continuity.
Success signals: real artifact visible at 1440×900 and begins inside 390×844; four task families covered by sourced examples; three input-based paths; four knowledge layers; complete bilingual static HTML; no broken key links or serious/critical axe violations. Search traffic and citation effects require external measurement and are not inferred from screenshots.
## Personas and jobs
Chinese web-fiction authors arriving from an AI answer on a phone; short-drama, game and video creators; English Claude Code users looking for non-coding skills; people who want the browser workbench. They compare formats and install surface before choosing.
## Information architecture
Home → real examples → input-based creative paths → tools and working environments → four knowledge layers → project relationships. Each section answers one question: what a result looks like, what to do with the material you have, which tool and where to run it, where to look something up, how the projects connect. Four skill packs create or adapt; DSH and the browser workbench are separate working surfaces, not extra stages of the same output. Five independent example cards currently cover a playable RPG, Oh Story product video, short-drama sample, finished recap and a desktop 3D game capture. They do not represent one story moving through all four tools.
Each example exposes input, output, a same-language method, immutable README/source and a direct playback/prototype link. The hero follows one verified case from source to result — Journey to the West chapter 59 (the public-domain source file), a rule from the Novel to Game source bible, and the playable prototype (browser QA capture plus the game's own character art), all pinned to the owner repository — so a real result is complete inside 1440×900 and visible inside 390×844. The largest showcase demonstrates the writing workflow (poster from 23 s of the real session); the showcase RPG tile uses the README overworld screenshot, not the hero capture. Creative tools and working environments have separate visual groups. The homepage carries three action-labeled paths (idea / manuscript / footage) and four layers (get started / whole workflows / techniques and templates / revision and reference). `/guides` retains the complete ten-task taxonomy, optional search and paginated corpus. Do not print all articles on home.
Main nav remains Projects · Guides · Glossary · GitHub · EN/中文 · Open app; on home the one primary hero action goes to the creative paths (`#start-h`), the hero caption links the stage case to its own project setup (`/novel-to-game#start-h`) and to the examples, and each section opens with a star-marked eyebrow. Each creative path names the tool it starts with and links to that tool's row; each tool row links to its project page's install-and-entry steps; each knowledge layer's more-link is labelled with where it lands. Existing project, article, glossary, guide and comparison URLs are retained. Workbench docs remain a separate product’s `/docs` corpus, reached from `/workbench` and footer.
## Language delivery
One language per URL. The organization generator runs once per language; `t(en, zh)`, `pick(field)`, `pair()` and `heading()` render the current language only, and `<html lang data-lang>` is set at build time, so nothing depends on a script or on `localStorage`. Each page carries `<link rel="alternate" hreflang>` for en, zh-CN and x-default (English), `og:locale` with its alternate, JSON-LD `inLanguage` for its own language, and the sitemap repeats the pair on both entries. The header switch is a link to the counterpart page. Title, description, headline and breadcrumb names are in the page language so Chinese engines match Chinese query vocabulary (网文写作 skill 包, 去AI味, 剪映草稿) in the title itself. On Chinese pages internal links to organization routes are re-pointed at `/zh/...` and per-element `lang="zh-CN"` markers are dropped; English pages keep them on Chinese-only fragments (glossary terms). The workbench docs are the one exception: a single URL with the 中文 article first and the English article below, both anchored, and the switch points at the anchors.
## Design principles
Preserve crawler metadata, language separation, sources and public URL contracts. Homepage headings and layouts may change for the new goal; update obsolete text assertions while strengthening behavior/SEO contracts. Preserve assertions for unrelated page behavior. One type system, one measure, disciplined color. Reduce link density: prose links are ink with a hairline underline; navigational lists and card titles are ink 600 without underline; orange text only for eyebrows and buttons. Show the same object the same way on every page (one card component, one guide list, one proof chip).
## Visual language
Homepage (`<body data-page="home">`, scoped block at the end of org-pages.css): "manuscript to world". The page is manuscript paper (`#f5f1e7`), the stage and the showcase/closing bands are the ink-navy world, a dashed cream story thread connects things and the mark's cyan star is the only node or bullet. One family — Geist with the system CJK sans, Geist Mono for paths and commands (loaded only on home via `HOME_FONTS`); the quoted source text is set vertically in a CJK serif. Media share one frame recipe (12px radius, hairline, shadow); a vertical video sits over a blurred copy of its poster, never in a device mock. Rhythm: paper hero → navy showcase → paper tools table / uneven path grid / library → navy closing into the footer. Other pages keep the editorial system below.
Body: Plus Jakarta Sans with a system CJK sans stack for both languages, 16px/1.65 (ZH 1.8, +.01em); headings: Source Serif 4 with system CJK serif fallback (h1 clamp 34–50px, h2 26px with a hairline rule and 64px top margin, h3 19px); mono: JetBrains Mono for commands. Google Fonts load non-render-blocking (preload + print-swap + noscript); Noto Serif SC is not loaded. Measure 720px shared by both languages; page wrap 1120px; 24px gutters; cards 1px borders, 8–10px radius, no heavy shadows. Alternating paper/cream bands mark home chapters.
## Components
Header (sticky, translucent with a plain fallback, `--top-h` drives `scroll-margin-top`), skip link, language switch, proof chips, copy-able install block, task cards, project cards, guide cards and guide list rows (flex, arrow never wraps), "What you need" table and "Start in 3 steps" rail on project pages, numbered Q&A list, compact two-column source notes, answer block on guides (`.pair.answer`), side-rail table of contents ≥960px, manuscript example panel, glossary two-column index, compact roster band, four-column navy footer. Content comes from JSON. Homepage showcase media is indexed by content/showcases.json, with local source-derived posters, native video controls and directly readable text. Complete project repositories and catalog routes remain accessible; old homepage duplication is not a preservation requirement.
## Accessibility
One `<h1>` per page, ordered headings, `nav[aria-label]`, `main#main`, `lang` on every Chinese node, visible `:focus-visible` on links and buttons (ink ring in light, cyan in dark), AA contrast for text including muted text (#626779) and dark-mode buttons, header controls ≥40px on phones, tables readable on mobile, no motion required. Verified with axe-core on home, project, guide, comparison and glossary pages in both schemes.
## Responsive behavior
Desktop 1440 and phone 390 are the reference widths; 640px and 960px breakpoints. Cards go 3 → 2 → 1 columns; the guide TOC becomes static in flow on phones; the header stacks to brand + switch + CTA over a link row within 96px; nothing scrolls horizontally except code and tables inside their own containers.
## Interaction states
No JavaScript is required to read, see cases or switch language. Videos ship with native controls, no autoplay, preload="none", local posters and always-visible direct-watch fallbacks; with JavaScript one play button stands in for the native bar until the visitor starts playback. GitHub CDN availability is external; posters, descriptions and method links remain usable if playback fails. Recap has a source-derived Chinese captions track; captions for the other videos are not yet established. Guide search progressively enhances a complete static browse index. Only the copy buttons wait for the classic script. Missing paths remain platform 404s. The workbench CTA explains that sign-in may be needed; no token transfer.
## Content voice
Specific, modest, bilingual. New UI copy is neutral labels or derived from JSON fields (install command, entry command, host list, dates); no ranking, citation, profit or quality guarantees. On home, say a thing once, in the section that owns it, and let the next section pick up from there: the hero caption is one case line plus short actions; hosts, licences and environment rules live in the tool section, project pages and the closing facts; case cards carry one new sentence each, not their media type again; the tool table shows a short “what you get” note (`home-reading.json` `tools`) rather than the project tagline that restates the goal; the closing keeps the diagram and actions, not the product catalogue again. Shorten visible copy, never by shrinking type, lowering contrast or hiding text with CSS, and keep crawlable titles, links and no-JS media fallbacks. A novel adapts into drama or a game; a recap starts from footage — copy and diagrams keep that distinction.
## Decisions recorded 2026-09-13
- Install commands wrap onto a second line inside cards and tables (tokens never split; the Copy button has its own column) instead of the earlier nowrap-and-scroll rule, because a clipped command reads as broken.
- The Open Graph image is a 1200×630 PNG card (`/brand/og-zenstory-ai.png`) instead of the 32px SVG mark; this is the one intentional metadata change versus the previous pages, and the GEO diff allow-lists it.
- Bilingual inline pairs carry a real " · " separator text node (hidden in single-language modes) so text extractors never see glued tokens.
- The visible "as of <date>" appears once per hero; per-card copies are visually hidden but kept in the HTML, and the org-wide proof sentence keeps its own date because it is content.
## Decisions recorded 2026-09-14
- Split languages onto separate URLs (`/zh` prefix, hreflang, x-default = English) instead of the toggle-on-one-URL model: engines index one title, description and body per URL, and the panel prompts are two-thirds Chinese while every title used to be English. Existing English URLs did not change.
- The workbench docs moved off the React app shell onto the organization shell (static, no app bundle) with a sidebar generated from `docsNavigation.ts`, resolved markdown links (a link to a missing page fails the build) and a "Docs" entry on the `/workbench` project page instead of the site navigation. The in-app docs search is not available on these pages; the React `DocsPage` remains for development builds.
- `llms.txt` lists guides and workbench docs in separate sections and points at the `/zh` corpus.

## Implementation constraints
Generators share `site-shell.mjs`, plain CSS, no new dependencies; isolated generator fixtures copy the complete content directory and generator scripts, while full builds copy public media, no new routes without updating `content/site-routing.json`, `vercel.json` (`--write-config`), `llms.txt` and the sitemap count. Every change is verified with the generator tests, a GEO diff against a baseline build (metadata, JSON-LD, links and text tokens must survive), 390px overflow checks, and axe.
## Open questions
- [x] `/docs` now sits on the organization shell (2026-09-14). Open: whether the app's own docs entry should link to `/docs` with a language hint.
- [ ] Palette moved from terracotta-on-paper to the mark's navy/cream/cyan with orange accents; owner sign-off recorded when the branch is merged.
- [ ] Search Console access is still not established; indexing remains unverified.

## Homepage decisions recorded 2026-10-03
- Keep the navy/cream/orange editorial identity; do not clone Hypit’s black/pink identity or machinery.
- A real public RPG screenshot replaces the abstract hero diagram. The conceptual project diagram moves down to the relationship section.
- Existing README-hosted videos are first-class evidence: writing-product demo, 68.5 s short-drama sample, 58.96 s finished recap and 14.96 s 3D gameplay capture. Original media remains CDN-hosted; local posters are extracted from those exact videos. Source-derived recap captions are retained. No placeholders or synthetic demo footage.
- Native controls and direct-watch links, with no startup video download, are preferred over carousel/player dependencies; an inline script replaces the native bar with one play button until the first play. The hero carries no install command: a single command next to one case read as “install this to reproduce it”; install commands live on project pages, reached from the tool rows.
- The full ten-topic directory stays on `/guides`; homepage establishes learning layers instead of ten equal topic cards.
- Local acceptance is based on independent screenshot review, native playback, static contract tests and build evidence. Public release verification is separate. Only recap has a confirmed caption track; public embedding permissions are not independently established by repository licenses. No search-ranking or AI-citation gains are claimed.

## React workbench scope — module review, 2026-10-04
This section governs `app.zenstory.ai` only; it does not change the organization-site contract above. Evidence: `apps/web/src/index.css`, `components/ui/Modal.tsx`, `ConfirmDialog.tsx`, `Toast.tsx`, `BottomTabs.tsx`, `Layout.tsx`, and `apps/web/docs/ui-async-state-standard.md`.

- **Goal:** preserve the writing workflow and supported capabilities while fixing demonstrated interaction, accessibility, and state-management defects. No visual redesign or new design-system layer.
- **Visual language:** retain the existing light/dark HSL semantic tokens, serif writing typography, sans-serif controls, spacing, icons, and elevation. Reuse existing primitives; do not import the organization site's palette into the workbench.
- **Navigation:** keep dashboard, project editor, materials, skills, billing, settings, and admin boundaries. Inspirations and complex material-analysis stages stay disabled by default; historical data remains readable.
- **Dialogs:** maintain accessible names, initial focus, Tab/Shift+Tab containment, Escape/backdrop policies, scroll locking, and focus restoration. Loading confirmations must not allow cancellation. Nested dialogs must not release the outer dialog's scroll lock.
- **Mobile workspace:** preserve mounted editor/chat/file state across switches. Tabs must reference real labelled panels; inactive panels must be unavailable to keyboard interaction. Retain the existing 768/1024 px layout boundaries and 44 px touch targets.
- **Feedback:** success/info notifications use polite announcements; errors use alert semantics. Keep current deduplication, maximum visible count, and expiry. Loading, empty, error/retry, and disabled states follow the existing async-state standard, not ad-hoc placeholder screens.
- **Motion:** honor reduced-motion preferences without changing normal animations or removing functional progress indicators.
- **Content:** reuse existing bilingual translation keys, task-oriented labels, and terminology. Do not expose inert actions as working controls.
- **Verification:** regression tests precede behavioral changes; run targeted component/page tests, TypeScript/lint, and keyboard/mobile browser checks. DOM semantics alone do not establish physical focus behavior or visual quality.
- **Open question:** email-change re-verification policy is not established by existing product contracts; preserve it rather than silently introducing a new access policy.

## React responsive decisions — 2026-10-05
- Dashboard and admin own viewport-height shells with independent main scrolling; public/docs long pages remain document-scrolled. Fixed workbench/admin shells use inset sizing, not100vw alongside document scrollbar gutters.
- Workbench panel units are explicit: desktop20/48/32%, sidebar minimum180px/chat300px; tablet25/40/35%, chat280px. Keep existing768/1024 breakpoints, draggable panes, mobile mounted/inert state and keyboard viewport handling.
- Desktop chat textarea minimum64px, saved input-panel floor144px; mobile44px controls remain. Empty placeholder is a concise idea prompt; long typed text/accessories remain scrollable. Tool status stays together; filenames wrap fully rather than losing text.
- All reachable React routes and generated static template families are checked at small laptop, tablet and mobile viewports. A scrollbar alone is not a defect: preserve legitimate file/message/table/code/long-page scroll, repair clipping and competing outer scroll boundaries.

## Admin growth decisions — 2026-10-07
Evidence: `AdminDashboard.tsx`, `StatsCard.tsx`, `AdminPageState.tsx`, admin HSL tokens, existing usage and payment endpoints. Active scope: authenticated `app.zenstory.ai/admin`; operator job is to compare acquisition, actual AI activity, registration-cohort activation, actual payment and operating costs.

- Put the selected 7/14/30-day growth period first; compare with the prior equally long period, including the same partial-day progress. Beijing boundaries and the observation cutoff must be visible.
- AI active means distinct non-admin customers with live metered AI calls. Activation and signup-to-paid rates use only the same registration cohort; zero denominator is unavailable, not zero. Independent telemetry event counts are never displayed as a conversion funnel.
- Revenue comes from paid orders in integer cents. Paid customers, orders and free grants are separate. Subscription-history attribution is supporting evidence, not the payment ledger.
- Reuse admin surfaces, StatsCard, existing light/dark tokens, Lucide icons and query states. No new theme, chart dependency, organization palette or promotional graphics. Daily data uses an accessible table, with bounded horizontal scrolling on phones.
- Cards adapt from two columns on phones to four on desktop; controls have 44px touch targets, selected state, visible keyboard focus. Loading/error/retry are independent of legacy operational statistics.
- Copy is bilingual and factual, explicitly labels incomplete days, cohort observation windows, estimates and event counts. No invented visitors, retention, profit or attribution. Local component, API contract, type/lint and build checks precede publication.
- [ ] Embedding account funding is external; provider balance must be restored before reindexing can recover missing search entries. Owner: operator.