finesse — Technically Spectacular · Soul-Distinct · Never Cheap
finesse builds two kinds of interface and routes by register (§0):
- brand — design IS the product: landing pages, brand sites, launches, portfolios, hero pages. Optimize for spectacle + soul + first impression — a real visual engine, an opinionated personality.
- product — design SERVES the product: dashboards, admin panels, analytics, data tables, app shells, settings. Optimize for clarity + density + usability — and still never cheap.
The through-line is identical: high craft, zero AI-slop. What applies to both is the universal craft floor (tinted neutrals, no
#fff/#000, translucent/hairline borders, tinted shadows, contrast floors), the cheapness blacklist (§6), and the pre-flight (§8). What forks is the substrate above that floor and the middle: brand lays the §3 brand substrate (design-dna.md— grain, vignette, display type) and reaches for a hero engine (§4); product lays its own substrate (product-ui.md§0 — surfaces, cards, KPI tiles, density) and reaches for a component system + data viz. A dashboard is a different design language, not a brand page with charts — it does not inherit grain / vignette / giant hero type / dark-default / a hero engine.Two more registers sit alongside them, and they work differently from each other. commerce (PDP/PLP/cart/checkout) is a hybrid — route it to brand or product by what the specific page is doing. h5 (phone-only screens: app UI, 活动页, mobile PDP, report H5) is a container: it fixes the frame, the safe areas, the thumb hierarchy, and the OS furniture, then wraps one of the other three for the content grammar underneath. A mobile PDP is
h5+commerce; an app dashboard screen ish5+product. h5 never replaces a content register — it wraps one.Every rule below is contextual. Nothing fires automatically. Read the brief, set the register, then pull only what fits. A skill that produces the same page for every brief has failed.
How to use this skill
- Check the scope before anything else. If the brief is a single element — a button, an input, a card, a modal, a toast — go to
references/component-scope.mdand follow it instead; steps 1–6 below are page apparatus and are wrong for one component. Detection and the ambiguity question live in that file. - Run §0 Brand Read — read
.finesse/log.json(the rotation memory,divergence.md§4), then infer register (brand vs product) + soul before touching code. Output the Design Read: the coordinate line, a plainYou'll see:line the user can actually veto, theImages:line naming every slot a picture would carry and where it would come from, its two most likely objections, and the rotation as a sentence (§0.B). Before writing thatImages:line, check this session's actual tool list — an image-gen tool, an MCP image tool, a network fetch, or none — because it decides what you can honestly offer (asset-sourcing.md§1), and prove the one you're about to name actually runs here before naming it (§1.1 — listed is not usable; a generator with no credential is not Path A). Offer it and wait; never generate or download off your own inference. - Set the §1 Three Dials (SOUL · SPECTACLE · DENSITY). Product register pins SPECTACLE low, DENSITY high.
- Lay the substrate — the right one for the register. All share the universal craft floor (tinted neutrals, no
#fff/#000, translucent/hairline borders, tinted shadows, contrast floors —references/design-dna.md§1). Above that floor the substrate forks:- brand → the §3 brand substrate (
references/design-dna.md): grain, vignette,clamp()display type, dark-default, layered hero depth. - product → the product substrate (
references/product-ui.md§0): premium surfaces/cards, KPI tiles, floating panels, fixed type scale, feedback-only motion. Never pour grain / vignette / giant hero type / dark-default / a hero engine into a dashboard — that's brand grammar, not product grammar. - h5 → the frame comes first (
references/h5-mobile.md§1): the viewport contract, the lockedbody+ scrolling#app, the 560px desktop phone frame, then the safe-area math (§2). Only after the frame is standing do you lay the substrate of the register it wraps.
- brand → the §3 brand substrate (
- Then the paths fork further:
- brand → pick a §2 Soul (
references/style-personas.md) and build one §4 Hero Engine (references/hero-engines.md). - product → pick a palette from
references/product-palettes.mdfirst (the neutral ramp is 80% of the pixels; skipping this step is how every dashboard comes out blue). Then split by the page's job:- pages you read — dashboards, analytics, monitoring →
references/product-ui.md(density, tables, charts, interaction states). Before writing, open the closest dashboard inexamples/(index:examples/EXAMPLES.md) to seeproduct-ui.md§0 applied in shipped code — lift patterns, not whole files. - pages you operate — publish/create wizards, merchant & admin consoles, config, settings, review queues →
references/workflow-ui.mdon top ofproduct-ui.md(workflow shell, numbered sections, radio-card choices, live preview, pre-submit check, derived totals, draft/commit). There is no form-workflow page inexamples/— build from the reference, and do not force-fit a dashboard example onto a form. - pages you delegate on — AI 工作台, agent consoles, copilot UI, anything where something other than the user does work over a duration →
references/ai-console.mdon top ofproduct-ui.md(three tenses on one screen, the run stream, nine run states, a resident stop, the in-stream approval card, cost as a receipt). Openexamples/relay-agent-console.html. A dashboard fails by being unreadable and a console by being unfinishable; this one fails by being untrustworthy, and none of the dashboard parts address that.
- pages you read — dashboards, analytics, monitoring →
- h5 → pick one of the six morphologies (
h5-mobile.md§4: app shell · paged deck · snap narrative · commerce stack · longform site · ambient screen), then load the content register it wraps and follow that bullet above. Build the native furniture fromh5-mobile.md§5 rather than inventing it — a TabBar is a convention, not a design opportunity.
- brand → pick a §2 Soul (
- Assemble the skeleton — again, the right one for the register. brand → pick one of the four §5 brand skeletons (landing · portfolio · lookbook · studio) by what the page has to do. product → the skeleton is the shell morphology in
product-ui.md§1 (sidebar · floating panel · bento · triptych …), not §5. h5 → the skeleton is the frame (§1) plus the chosen morphology (§4); §5's brand skeletons andproduct-ui.md§1's desktop shells are both wrong inside 390px. Motion-motivated only, in all three. - Run the §6 Cheapness Blacklist (
references/anti-cheap.md), the mobile floor (references/mobile-floor.md), and §8 Pre-Flight (references/preflight.md) before shipping. h5 builds runh5-mobile.md§9–§10 instead of the mobile floor — the notch/frame/scroll/touch gates, which are a different set of failures from "a desktop page reaching a phone". Then record the build — append to.finesse/log.jsonand stamp the CSS (divergence.md§4.3). An unrecorded build is one the next run will collide with.
The references/*.md files are the deep material. Load the one you need for the current phase — do not inline all of them.
| Reference | When to load |
|---|---|
component-scope.md |
Before the Brand Read, when the brief is one element, not a page — a button, an input, a card, a modal. Routes to the component flow: keeps the register + craft floor + existing tokens, skips the skeleton / hero engine / rotation, and enforces the one gate that decides whether a component is well-made — all eight states shipped, plus a preview file that makes them visible instead of claimed |
divergence.md |
At §0, before the Design Read — the anti-sameness layer. Load it when output keeps converging, when the user says "feels generic / like every other AI site", or before any soul decision: the five-axis composition method (compose a soul, don't select one from a list), the anti-default two-altitude check, the die roll that breaks the model's argmax, and the assert-then-confirm direction proposal. §4 is the memory — .finesse/log.json + the CSS stamp, with a defined read step (§0) and write step (§8); without it "don't repeat" is a rule with nothing behind it. Read its §0 register boundary first — divergence is a goal for brand and a bounded tactic for product (never diverge on dashboard navigation conventions) |
design-dna.md |
Laying the brand substrate (grain, vignette, display type, color tokens, palette families). Product/dashboard inherits only its universal craft floor (§1: tinted neutrals, translucent borders, contrast floors) — the surfaces/cards/type/motion of a dashboard come from product-ui.md §0, not here |
theming.md |
Brief asks for a light/dark toggle or multiple swappable named themes — the token-role and hardcoded-color pitfalls of a runtime palette switch (not the single-locked-palette default) |
motion.md |
Any brief that mentions motion — 动效 · 炫酷 · "make it move" · "有动画" — and every brand build. The motion layer above the engines: the two axes nobody separates (EFFECT what's seen vs ROUTE how it's built), the six routes with their weight, their still form and their failure mode (CSS · native scroll-driven · View Transitions/WAAPI · GSAP · Canvas/WebGL · zero-dep CSS 3D space), a ten-family effect catalogue with ~80 variants and each family's slop form, the effect → route lookup that stops the model reaching for 60KB to do four lines of work, and the beat sheet that replaces "one hero engine + generic fade-ups" with four beats from four different families. Load it before hero-engines.md: that file answers which engine, this one answers whether you need an engine at all |
hero-engines.md |
Building the hero engine (brand register); also covers a secondary motion vocabulary (split-char reveal, magnetic buttons, curtain wipe, scan-line, per-card fly-in) for non-hero moments elsewhere on the page — the decision layer (which engine). Scope note: these are the two heaviest routes (R4 GSAP · R5 Canvas/WebGL) of the six in motion.md — reach here only once that file's lookup has sent you to a heavy route |
page-crafting.md |
The brand implementation layer — what chart-crafting.md is to dataviz.md. Load it when you stop choosing and start writing: the motion gate (REDUCE/FINE probes + terminal states — universal, product too), canvas DPR + cyclic palettes + amplitude envelopes, mask-image photo dissolve, the photographic-hero scrim stack, container-query panels, nav scroll-spy over alternating sections, zero-dependency sticky horizontal pin, exploded-view scrub, colorway pin+snap, clip-path wipes, hand-written FLIP lightbox, generative (guillotine-split) layouts, CSS-only geometric collage, full-page engine + section scrims, and the Fibonacci→KNN→traversal 3D recipe |
h5-mobile.md |
The page only ever lives on a phone — H5 / 移动端页面 / 活动页 / 小程序页 / app UI 原型 / mobile PDP / 报告 H5. The fourth register, and a container one: it fixes the frame and wraps another register for content. Carries the viewport contract, the locked-body/scrolling-#app architecture that inverts every other register, the 560px desktop phone frame, safe-area math, the thumb-zone inversion (primary actions at the bottom), the touch rules that have no desktop equivalent (passive, pointercancel, tap-highlight, 44px), six phone morphologies, and the native furniture recipes — status bar, TabBar, bottom sheet, FAB, push and hand-written FLIP transitions. Not the same file as mobile-floor.md: that one keeps a desktop page from breaking on a phone; this one is for a page that has no desktop form at all |
mobile-floor.md |
Any build that will be seen on a phone — i.e. nearly all of them. The six mechanical causes of a broken phone layout, with the fix for each: overflow-x: clip vs hidden (and why hidden kills your sticky nav), minmax(0,1fr) on image-bearing grid tracks, clickable text that never wraps at any width, overflow-wrap: anywhere on display headings, one sticky at top:0, and the all-caps line-height floor that overrides §3's .86–.95 for uppercase display type. preflight.md asks whether it breaks; this file says why it breaks |
3d-effects.md |
Adding a 3D moment — CSS tilt/flip/coverflow/depth-parallax or Three.js model/displacement |
style-personas.md |
Picking a soul (brand register) |
inspiration-catalog.md |
Persona picked but you want a wider menu of proven techniques for that soul, or the brief doesn't fit any of the 10 personas cleanly |
plain-words.md |
Any time you are writing text the user reads — the §0.B Design Read, audit findings, the memory-lock notice. finesse's whole vocabulary (register, SPECTACLE, grain, scrim, eyebrow, hairline) is load-bearing internally and opaque externally, and it leaks out at exactly the moments the user is supposed to make a decision. One-clause observable glosses, plus the list of internal terms (five-axis coordinates, axis letters, reference filenames) that must never reach a user |
anti-cheap.md |
Before any delivery — cheapness scan |
product-ui.md |
Dashboard / admin / data app — pages you read (product register) |
workflow-ui.md |
Pages you operate (product register): publish/create wizards, merchant & admin consoles, config, settings, review queues — the workflow shell, numbered section cards, radio-card choices, live-preview aside, pre-submit check, derived budget panels, draft/commit |
ai-console.md |
Something other than the user is doing the work, and the page's job is to make that trustworthy — AI 工作台 / agent console / 智能体控制台 / copilot UI / 值守台. A capability layer, not a page type: decide 后台 vs 工作台 first (§1's resolver), pick the body, then stack this on — it fails by being untrustworthy rather than unreadable or unfinishable, and that failure can land on any of them. Carries the four questions it must answer continuously, the three tenses on one screen (queue · live run · history), the run stream that replaces the chart as the centrepiece, the nine run states that product-ui.md §5's eight component states don't cover (including partial and stopped), stop as a primary resident control, the in-stream approval card with linked evidence, cost/context as first-class, the artifact surface, the desktop three-column shell and what changes on a phone (§9). Also the palette rule this category dies on: the AI-violet default, and the --auto vs --needs semantic pair |
product-palettes.md |
Any product-register page — the color layer design-dna.md §6 doesn't cover: 5 tinted neutral ramps, 16 accents with light/dark + text-on-accent contrast, 12 paste-ready sets, the known-SaaS palettes (Linear/Stripe/Supabase/Grafana…). Load it before picking a color, or you will reach for blue |
examples/EXAMPLES.md |
The positive-reference corpus — 22 real shipped pages (9 brand + 8 dashboards + 1 AI console + 4 H5) with a per-file "what to study" table. Open the closest one before building, especially for dashboards and phone shells (lift patterns, not whole files) |
dataviz.md |
Chart-heavy product UI beyond the starter table — full 25-type selection matrix, a11y grade + mandatory fallback, library picks (the decision layer) |
chart-crafting.md |
Any hand-built dashboard chart in a single self-contained file (mandatory for bars — the barcode-chart trap) — the no-library implementation layer: the value→height rule, div height:value/max% bar recipe, SVG coordinate normalization, line/area draw-in, donut/gauge grow, stacked bars, sparklines, the three animations × reduced-motion pairing, slider-driven live update |
commerce-ui.md |
Product detail page (PDP), listing/category page (PLP), cart, checkout — commerce register |
asset-sourcing.md |
At §0.B, as soon as the page has anywhere a picture would carry it — a hero, a gallery, an H5 cover or scene, a PDP shot, even a dashboard's empty state or avatar row. Not a category checklist and not a delivery-time scan: the paths (generate · real stock · generative placeholder) and the ask-first gate on all of them only work if they fire before the layout is written. Carries the session-capability check that decides which path you can honestly offer, and the rule that naming images is an offer the user answers — never a licence to generate or download |
preflight.md |
Final checklist before saying "done" |
design-model.md |
Multi-page projects — token consistency |
redesign-mode.md |
Upgrading an existing page — audit-first protocol |
audit.md |
Read-only diagnostic — cheapness + spectacle + preflight scan |
init.md |
New project — write PRODUCT.md (the persistent brief) |
document.md |
Existing codebase — extract design-model.yaml from real code |
Commands
finesse runs as a full build by default, but supports verb commands for targeted iteration on an existing page — so you don't re-run the whole Brand Read for a single complaint. Each command loads one reference and does one job.
| Command | Category | Does | Reference |
|---|---|---|---|
craft [brief] |
Build | The full flow: Brand Read → Dials → substrate → engine → assemble (the default) | all |
init |
Setup | New project: write PRODUCT.md (register, soul, locked dials, anti-references) — the brief every later task reads |
init.md |
document |
Setup | Existing codebase: extract the built design system into design-model.yaml; report drift |
document.md |
audit [target] |
Evaluate | Read-only diagnostic: run the cheapness blacklist + spectacle-shown + pre-flight, output a findings list. Changes nothing. | audit.md |
bolder [target] |
Refine | Raise SPECTACLE +2, upgrade the engine (e.g. Canvas → Three.js) | hero-engines.md |
quieter [target] |
Refine | Lower SPECTACLE −2, step down to GSAP / CSS-only; calm an overloaded page | hero-engines.md |
soul [target] |
Refine | Re-pick the persona / soul when this page is the wrong vibe | style-personas.md |
diverge [target] |
Refine | Every page comes out the same. The systemic fix, not the per-page one: recompose the soul from the five orthogonal axes, run the two-altitude anti-default check, roll against the model's argmax, and check the used-list. Use when the user says "feels generic / like every other AI site / 每次都差不多" | divergence.md |
animate [target] |
Enhance | Re-cut the page's beat sheet — motion only, soul and substrate untouched. Not just the hero: pick the families (§2), take the cheapest route each (§3), hold the budget (one heavy beat, four total, no two from one family), compose every still. Swapping the hero engine is one case of this, not the whole command | motion.md → hero-engines.md |
depth [target] |
Enhance | Add one 3D moment — CSS pseudo-3D (tilt · flip · coverflow · depth-parallax) or Three.js (model viewer · image displacement) | 3d-effects.md |
densify [target] |
Enhance | Adjust DENSITY ± — add/remove content, tune information-per-viewport | product-ui.md |
redesign [target] |
Iterate | Upgrade an existing page, audit-first; never full-rebuild for one complaint | redesign-mode.md |
Routing rules
- First word matches a command → load that command's reference and follow it. Everything after the command name is the target. Lay the §3 substrate and run the relevant §6/§8 checks, but skip the parts of §0–§5 that don't apply to that single action (e.g.
quieterdoesn't re-pick a soul). - First word doesn't match, but intent clearly maps to one command ("too plain / boring" →
bolder; "too flashy" →quieter; "wrong vibe for this page" →soul; "feels generic / every page looks the same / 每次都差不多" →diverge; "make it pop" →animate; "动效 / 炫酷 / 加点动画 / 让它动起来 / 太静了" →animate(loadmotion.mdfirst — these words select nothing on their own, so §4's beat sheet is what turns them into a decision the user can veto); "add depth / make it 3D / tilt / parallax" →depth; "too sparse / too dense" →densify; "improve / fix this page" →redesign) → route to that command and proceed as if invoked. If two fit, ask once which. - No argument at all (bare
/finesse) → the user is asking "what should I do here?" Don't dump the static menu. Read a few cheap signals and lead with the 2-3 highest-value commands, each with a one-line reason, then offer the full table as fallback. Never auto-run — recommend, the user confirms. Signal → pick:- no
PRODUCT.mdand there's real code/pages → lead withdocument(capture what's built) and/orinit(write the brief). Brand-new empty project →initthencraft. PRODUCT.mdexists, has built pages, never audited → lead withaudit <surface>(read-only health check).- git working tree points at one page/file → scope
auditorredesignto those files, naming them. - a recent
auditfound P0/P1 → lead withredesign(fix the backlog) or the specific refine verb the findings point to (gradient-text/eyebrows →quieter/soul; flat motion →animate). - nothing built yet, clear brief →
craft. Keep it to 2-3 pointed picks with the exact command to type. The menu is the fallback, not the lede.
- no
- A target but no command, building something new → check the scope, then the surface. If the brief names a single element (a button, an input, a card, a modal), route to
references/component-scope.md— the page flow's skeleton, engine, and rotation are all wrong for one component, and the thing that actually decides its quality (all eight states shipped) isn't checked anywhere in the page flow. If the brief names a phone-only page (H5 / 移动端页面 / 活动页 / 小程序页 / app 原型), loadreferences/h5-mobile.mdfirst and build the frame before anything else — a page assembled desktop-first and then squeezed into 406px is the failure mode that file exists to prevent. Otherwise run the fullcraftflow (§0 → §8) — the default for "build me a landing page / dashboard". auditis read-only. It only reports findings; it never edits code. Every other command is allowed to modify the target.
Auto-trigger is unchanged: finesse still activates from natural language via its
description. Commands are an added precision entry-point (/finesse quieter page.html), not a replacement — both routes lead to the same references.
After any command that modified the page, run the relevant §8 Pre-Flight gates before declaring done.
0. BRAND READ (Before Anything Else)
Most AI design output is bad because the model jumps to a default aesthetic instead of reading the brief. Don't.
0.A Determine the Register (this forks every later decision)
Ask the surface question first: does this page have a desktop form at all? If the answer is no — it's an H5 / 移动端页面 / 活动页 / 小程序页 / app 原型, opened from a chat message or a QR code, looked at in a phone mock — then the register is h5, and it is a container: go to
references/h5-mobile.md, build the frame, then come back here and pick the content register underneath it. h5 wraps one of the three below; it never replaces one. The one-question tiebreak when the brief just says "手机端的页面" is inh5-mobile.md§0: "这个页面只在手机上打开,还是电脑上也要好看?" — "both" means it's a brand/product page withmobile-floor.mdapplied, and building a phone frame for it would be wrong.
Ask the same question for 「工作台」, and ask it before anything else. 「工作台」 and 「后台」 are two different products, and defaulting the former to the latter is the most likely mis-build in this skill. Ask what it revolves around — 一批业务对象 → 后台; 他自己反复在做的一件事 → 工作台 — never how many people use it. Only then does the screen matter, and only to pick the workbench's body (desktop shell vs
h5-mobile.mdmorph A.1); an agent doing the work is a capability layer on top (ai-console.md), not a third species. Full resolver under §1's dials table.
- brand — design IS the product: landing page, brand site, launch, portfolio, campaign, hero page. Be bold, opinionated, spectacular. Goes the soul + hero-engine route (§2, §4).
- product — design SERVES the product: dashboard, admin, analytics, data table, app shell, settings, tool. Optimize for clarity, density, usability. Goes the component-system route (
references/product-ui.md). Still never cheap — it inherits the universal craft floor (§3's last three bullets) + the cheapness blacklist (§6), and builds on the product substrate (product-ui.md§0), not the brand substrate's grain/vignette/hero-type/dark-default.- Split it once more — but the first split is 后台 vs 工作台, not a list of page jobs. Ask what it revolves around: a batch of business objects → 后台; one thing he does over and over → 工作台 (full resolver under §1's dials table — it is the most consequential fork in this skill and the easiest to get wrong).
- 后台 splits by job into read and operate. A dashboard you read fails by being unreadable —
product-ui.md, unchanged. A page whose primary action is a consequential commit (发布 / 上线 / 提交 / 保存配置 — a merchant publishing a campaign, an admin configuring a rule) is one you operate, and it fails by being unfinishable: loadreferences/workflow-ui.mdon top. Login forms and search filters don't count;product-ui.md§4 covers those. - 工作台 splits by body, not by job — desktop keeps
product-ui.md's shell at A.1's density and soul; phone goes toh5-mobile.mdmorph A.1. Same species either way. - Then, orthogonal to all of the above: does something other than the user do the work over a duration? An agent runs multi-step tasks, output streams in, a run can fail halfway, there's a queue → layer
references/ai-console.mdon top of whatever you already picked (its §8 is the desktop shell, §9 the phone form). It fails by being untrustworthy — you can't tell what it's doing, why, what it cost, or how to stop it — and none of the read/operate parts address that. This is a capability, not a category: a workbench without an agent doesn't need it, and a back-office that grows one doesn't become a workbench. A chatbot with no tools, no queue and no artifacts isn't one either; a dashboard about model spend is a dashboard.
- 后台 splits by job into read and operate. A dashboard you read fails by being unreadable —
- Color is not optional here. Pick from
references/product-palettes.mdbefore writing CSS. "Dashboard" predicts blue; the product predicts a color.
- Split it once more — but the first split is 后台 vs 工作台, not a list of page jobs. Ask what it revolves around: a batch of business objects → 后台; one thing he does over and over → 工作台 (full resolver under §1's dials table — it is the most consequential fork in this skill and the easiest to get wrong).
- commerce — a third, hybrid case: product detail pages (PDP), category/listing pages (PLP), cart, checkout. It doesn't cleanly fit either bucket above, so don't force it — route by which job the specific page is doing:
- A PDP selling one hero item (a single SKU, a launch, a flagship product) leans brand: pick a soul (§2), but keep DENSITY up for specs/reviews/trust signals — see
references/commerce-ui.mdfor the PDP skeleton. - A PLP / marketplace with many SKUs (filters, sort, grid of many products) leans product: DENSITY high, SPECTACLE low, same as a dashboard — see
references/product-ui.mdfor grid/filter patterns plusreferences/commerce-ui.mdfor commerce-specific rules (price/CTA placement, cart, checkout, dark-pattern bans). - When unsure which it is, ask: "is this page trying to sell the vibe of one product, or help someone compare/filter many?"
- A PDP selling one hero item (a single SKU, a launch, a flagship product) leans brand: pick a soul (§2), but keep DENSITY up for specs/reviews/trust signals — see
Read project memory first — all three files, they answer different questions.
| File | Answers | Written by |
|---|---|---|
PRODUCT.md |
What must stay the same? — register, users, brand personality, locked dials, anti-references. Overrides your guesses. | init |
design-model.yaml |
What is already built? — locked palette / type / substrate, so this page matches its siblings. | document |
.finesse/log.json |
What must change? — the last 20 builds' five-axis coordinates. The rotation memory. | every completed build (§8) |
The first two lock consistency; the third forces difference. They are opposite goals and deliberately live in separate files — see divergence.md §4. If .finesse/log.json is absent, grep the codebase for a /* finesse · CSS stamp and infer one entry from it; if neither exists, this is the first run and there is no rotation constraint.
- No
PRODUCT.md, multi-page or repeat project, thin brief → offer to runinitfirst (onePRODUCT.mdkeeps every later page consistent). Don't force it on a one-off page. - Existing codebase, no
design-model.yaml→ offerdocumentto capture what's there before adding to it. - If memory exists but the new request contradicts it, surface the conflict — don't silently override the lock.
0.B Output a "Design Read" before generating — assert a direction, don't poll for one
Name the rejected default first (§0.D), then the direction — then say what the page will look like in words the user can picture, and give them two concrete ways to object:
Lazy default (rejected): {the obvious aesthetic for this category}
Design Read: {industry} · {soul in 2-3 words} · register={brand|product} · SPECTACLE={n} ·
layout={dominant layout family} · engine={type}
You'll see: {what appears on screen, in plain observable terms — color, motion, type size, structure}
Motion: {the beat sheet — one plain-language line per beat, plus the still. Omit only if
the page genuinely doesn't move. Route names never appear here — motion.md §4}
Images: {how many, of what, and where they'd come from — or "none, and here's why"}
Not right? Most likely one of these: ① {the most probable objection} ② {the second}
Rotation: {plain sentence — which recent direction this deliberately avoids}
Example:
Lazy default (rejected): dark page, violet glow, floating 3D render, three feature cards.
Design Read: deep-space astronomy · cinematic + reverent · register=brand · SPECTACLE=8 ·
layout=full-page engine + scrimmed sections · engine=Three.js particle galaxy
You'll see: a near-black page with slow-drifting star dust behind everything, a very large
headline sitting on top of it, and the galaxy rotating as you scroll.
Motion: 首屏 星尘在背后慢慢漂,标题压在上面
滚动 往下滚星系跟着转,越滚越深
交互 切换观测目标时,参数自己重排,不是整块刷新
收尾 底部那行坐标逐字浮起
静止版 星系定格在一帧构图最好的,其余全停
Images: 3 — a wide nebula plate behind the hero, 2 square instrument details in the spec band.
I can generate them here (they'd share one cold-blue grade); say the word and I'll
list the shots before spending anything. Or the page ships engine-only, no photography.
Not right? Most likely one of these: ① you don't want a moving background
② near-black is too heavy and you want this light.
Rotation: deliberately steering clear of the last three builds (machined metal / paper press /
phosphor terminal) — this one is water and drift.
You'll see: is the line the user actually answers. The Design Read: line is a coordinate for you — SPECTACLE=8, scrimmed sections, and Three.js particle galaxy are three things a non-designer cannot picture, cannot rank, and therefore cannot veto. A gate only one answer can pass is not a gate. Write what renders: color, whether anything moves, how big the type is, what the structure is. No jargon — references/plain-words.md if a term is unavoidable.
Motion: is here because 「炫酷」 and 「好看」 select nothing. Those words map every model to the same answer — a WebGL particle hero over fade-up sections — so a brief containing them is not a motion decision, it's a blank one. Don't ask him to be more specific; he doesn't have the vocabulary and asking spends a round to get 「就是要好看那种」 back. Assert a beat sheet in pictures instead, one line per beat, and make the two Not right? forks structurally different beats — 「你想要能拖着转的,不是自己往前走的」 is answerable in one word. Cover the whole page, not just the hero: a page with one spectacular beat and three generic fade-ups is the shape this line exists to break. Route names are internal (R6, animation-timeline, View Transitions) — he reads the picture, you keep the coordinates (plain-words.md). The still belongs here too: it is a beat the user gets to veto, not a fallback you bolt on at the end. Full method in references/motion.md §4.
Images: is here because the user cannot ask for what he doesn't know you can do. Every register has places a picture would carry the page — a brand hero, a PDP gallery, an H5 cover or ambient scene, even a dashboard's empty state or avatar row — and the default failure is silent: the page gets built with a gradient where a photograph belonged, and nobody ever said the word "image". So name the image slots at the Design Read, before any code exists, whatever the register and whatever the category. Count them, say what each depicts, and say where they'd come from in this session — which means checking your actual tool list first (image-gen tool → you can offer to generate; network fetch only → real stock; neither → say so) and verifying it runs before you name it (asset-sourcing.md §1.1). references/asset-sourcing.md is the protocol for all three paths and its authorization rules still hold — this line is what makes it fire early, when a "yes" is still cheap. If the named path later turns out unusable, §1.2 says drop to the next rung and say so — never fall from generate straight to hand-drawn placeholder.
Naming the slots is an offer, never a green light. Ask, then wait — do not generate and do not download. This line exists so the user learns the option is on the table; it is not permission to spend his generation budget or to pull assets off the open network because you inferred he'd want it. Both are actions with real cost and real provenance consequences, and the only thing that authorizes either is the user answering yes. The failure this prevents is the mirror of the silent-gradient one: a page where four images appeared, billed and un-asked-for, because the model decided the brief implied them. State the count and the source, stop, and let him answer — same gate
asset-sourcing.md§2/§3 puts on both paths, just moved to where it's still free.
If the page genuinely wants no photography (a phosphor-terminal build, a pure-type brutalist page), write none and one clause of why; that is a decision the user can veto too, and stating it is not optional.
Not right? must name real forks, not invite open-ended feedback. "Let me know what you think" returns nothing. Two specific, likely, mutually different objections give the user something to point at, and each one has to be a thing you would genuinely build differently — usually the theme and the motion, since those are the two decisions the whole page hangs off.
The rotation line is not optional, and it is not decoration. Rotation you perform in your head is indistinguishable — afterwards, to you and to the user — from rotation you merely narrated. Writing it down before any code exists is what makes a bad rotation catchable while it's still free to fix. Write it as a sentence, not as axis letters: differs on E + C + A (3/5 ✓) is unfalsifiable to the user — they can't tell what E is, so they can't object that they actually wanted machined metal. The five-axis coordinates still get recorded, in .finesse/log.json and the CSS stamp (§8.0), which is where an audit reads them from. Threshold and format: divergence.md §4.4. Omit the line only on the first build of a project (no log, no stamp) — and say that's why.
STOP after the Design Read. Do not generate any code yet. Wait for confirmation or redirect.
Assert, don't poll. State the direction you're going and invite a veto. Do not hand the user a three-option menu of adjectives — nobody can choose a design from words they can't see, so they'll pick the first one and you'll have learned nothing. A menu is theater when the answer is already clear. Note that You'll see: + Not right? is not a menu: it asserts one direction and pre-names its two most likely failure modes, which is what makes the veto usable instead of ceremonial.
When the user can't evaluate the assertion at all, that's Mode 2. If the brief carried no directional information — only undirected praise-words ("好看", "高级", "有质感", "premium", "clean"), or an explicit "I can't really say" — then
You'll see:will get a rubber-stamp no matter how plainly it's written, because the user has no basis for comparison. Build three real variants instead (divergence.md§7 Mode 2 + the squint test). Undirected adjectives are as strong a fork signal as a genuinely ambiguous brief.
The exception — when the brief genuinely forks (a "premium" brand that could be austere-Nordic or maximal-baroque; a personal site that could be a portfolio or a manifesto): don't describe the options, build them. Three low-fidelity but real, screenshot-able pages, each moving on a different axis, then let the user look. See references/divergence.md §7 — including the squint test that stops the three variants from collapsing into one.
If output keeps coming out samey across projects, the fix is not a better adjective in this line — it's
references/divergence.md(compose the soul from five axes instead of picking from a list; roll a die to break the model's default; keep a used-list so "don't repeat" can actually fire).
0.C If the brief is ambiguous, ask ONE question — do not guess blind
One sharp question beats five rounds of wrong defaults. Ask the thing that most changes the output: "Is this meant to feel restrained-editorial or maximal-spectacle?" / "What should a visitor remember 10 seconds after leaving?" Then commit. Wait for the answer before proceeding.
0.C.1 Say it in words the user can act on
finesse's vocabulary is internal. register, SPECTACLE, grain, scrim, eyebrow, hairline, layout family all earn their place in the reasoning and none of them are answerable by the person reading. They leak out in exactly three places, and all three are places where the user is supposed to decide something:
| Where | What breaks without a gloss |
|---|---|
| §0.B Design Read | the confirmation gate — he can only say "go ahead" |
audit findings |
he can't tell which finding to fix first |
the memory-lock notice (init.md) |
he doesn't know what got locked, or how to unlock it |
The rule: first time a term appears in user-facing text, follow it with a one-clause gloss in observable terms; after that use it bare. Table of glosses, plus the internal terms that must never reach a user at all: references/plain-words.md. This applies to output only — reason in whatever vocabulary you like.
0.D Anti-Default Discipline
Name the lazy default for this brief, then beat it. "Coffee brand → the default is warm-beige + brass serif. I'm rejecting that for {x}." The single most-tested AI tell is reaching for the obvious aesthetic of the category. (Reflex-reject lists live in references/anti-cheap.md.)
0.E Quick-Start Dial Mapping
If the brief contai
…(truncated)