refactor(builder): slim the design layer — guidelines over machinery#177
Draft
yyyyaaa wants to merge 6 commits into
Draft
refactor(builder): slim the design layer — guidelines over machinery#177yyyyaaa wants to merge 6 commits into
yyyyaaa wants to merge 6 commits into
Conversation
Add a design.md→globals.css pipeline so any build can re-skin without breaking shadcn/Blocks, with a "keep default constructive" opt-out. Engine (scripts/lib/design/, zero-dep): oklch (convert + WCAG contrast + lightness math), design-md (parse/serialize, reuses the existing YAML reader), invariants (taste lint: ≤1 accent, sat<80%, no pure black, AI-purple ban, contrast pairs), compile (role→shadcn remap + missing-var synthesis + .dark derivation + AA contrast repair, never throws), fonts (next/font allowlist) + 50 unit tests. Applier: scripts/wire-design.mjs — idempotent --dry-run codemod overriding :root/.dark token VALUES after the Blocks @import (restyles template + Blocks at once); optional layout.tsx font/defaultTheme + branding.ts; preset:constructive = no-op. scripts/check-design.mjs — lint gate that fails an un-themeable design (no green-wash). Presets: fixtures/design/{constructive,minimalist,editorial,soft,brutalist,playful}.md + compiler fixtures. Docs/grammar: references/design-system.md (dials + invariants + compile contract), brief-grammar `design:` block + auto-propose default, brief-policy validateDesign, SKILL.md S-step + phase docs. Layout taste (scope B): scaffold-frontend mandatory loading/empty/error states + dial-driven density (generic, no entity literals). Verify: design rot-canary wired into verify-gates.sh / verify-phase.sh / genericity-check.sh. Static gates green (50/50 tests, 6 presets lint clean, structural-safe, idempotent). Adversarially reviewed + fixed. Live Chrome-QA acceptance pending. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLz6M63G5vFJDZhW7dwBtb
…gnment, opt-out canary Follow-ups from live acceptance (two themed builds, both PASS end-to-end): - scaffold-frontend.mjs: resolve layout density from brief.design.dials.density → emitted design.md dials fallback → cozy default, so an auto-proposed theme's density "just works" regardless of where the agent recorded the dial (generic, zero-dep, idempotent). - references/design-system.md §8: document density as emit-time baked Tailwind spacing literals (comfortable/cozy/compact), NOT a runtime data-density attribute; state brief.design.dials as the single source of truth + the emit-once/re-emit note. - references/brief-grammar.md: note the zero-dep YAML reader has no folded/literal block scalars — design.brief must be a single-line quoted string. - fixtures/design/constructive.md: add `preset: constructive` so the opt-out design.md self-identifies → `wire-design --design …/constructive.md` is a byte NO-OP. Fixes the design rot-canary's opt-out assertion (was a pre-existing canary defect, not a regression). Verified: 50 design unit tests pass; all 6 presets lint clean; density resolves across all 4 paths; rot-canary opt-out=no-op AND editorial-applies both pass. Live acceptance: owner+auto-propose (focus-green) and public-read+editorial (terracotta) each built <10min warm, Chrome-QA light+dark, contrast AA/AAA, flows through RLS, independent evaluator PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLz6M63G5vFJDZhW7dwBtb
…per the design.md Fixes the gap that themed variants were re-skinned but STRUCTURALLY identical (same icon-sidebar + centered card-over-list). Adds GUIDANCE so agent builders vary an app's art direction (shell + page composition) per the agreed design.md, while preserving the functional contract. Guidance-only (no worked examples / no new scaffold templates); auto-propose now proposes STRUCTURE by default. - references/art-direction.md (NEW): the two-layer model — the PRESERVE checklist (the <entity>-* testid family + -empty/-select/social-btn- conventions + row-scoping/interactability + hooks/selection/refetch/Stack-pushes + RLS scoping per policy + flow route/block/manifest/sentinels + provider order/auth-bridge + static gates) vs the FREE presentational layer; the dial->structure mapping (VARIANCE->shell boldness, DENSITY->table-vs-card/rhythm); an archetype palette (shells x compositions) as guidance; the edit seams (app-shell.tsx frame + hideSidebar, the entity-page return block, the width clamp); the consistency-to-design.md rule (recorded in an art_direction block for turn-to-turn consistency); safety rails + a self-verify step. - SKILL.md: a rule granting the latitude + cross-ref. design-system.md: VARIANCE drives structure; auto-propose proposes structure too; the optional design.art_direction block; the CSS-compiler (token-only) vs frontend-structure distinction. brief-grammar.md: the art_direction block. - entity-page.tsx + entity-page.mjs: PRESENTATION/PRESERVE seam-marker comments (comments only). Validated (ultracode): independent verify — the preserve checklist is ACCURATE vs the real code, gates green. LIVE — an agent restructured the owner canary into a top-nav + data-table + compact "console-teal" dense dashboard (maximally distinct from the default mold); pnpm build green; live-qa OVERALL PASS (full CRUD-through-RLS on the data-table); theme light+dark; theme toggle works. Independent eval PASS: brokeTheMold + contractHeld + coherentWithDesignMd + guidanceSufficient (rules alone sufficed, no worked examples). Bold restructure ~12min (vanilla path unaffected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLz6M63G5vFJDZhW7dwBtb
…ontend The token-compiler + enforced invariants produced correct-but-generic output (variants were re-skinned, not art-directed). Pivot: the design.md is the FULL design spec; the agent AUTHORS the frontend from it; Blocks compose; only two hard rails remain. Taste comes from authoring, not token-swapping a generic template. - compile.mjs: faithful design.md -> shadcn token block — drop the override-surface creative-cap + the contrast-clamp; custom tokens/fonts pass through; keep synthesis (Rail 2) + .dark derivation. - check-design.mjs: default = hard-validate ONLY the Blocks/shadcn-token contract (40 names + @theme/@source/@custom-variant wiring) + ADVISORY warnings for contrast/AI-purple/>1-accent (never clamp/fail); add a Blocks-contract validator over an app globals.css; --strict opt-in. - invariants.mjs: taste rules -> advisory (warn/info); only missing-primary stays an error. - references/art-direction.md + SKILL.md: the frontend phase is now "scaffold the functional skeleton, then AUTHOR the presentation tastefully from the design.md" (taste-skill playbook; Blocks as ingredients; Rail 1 preserved). scaffold-frontend/templates: comment/seam-marker only (SHA-proved). - design-system.md + brief-grammar.md + fixtures/design/*: the design.md is now a rich, opinionated spec (atmosphere/dials/type-scale/spacing/components/ornament/prose/banned-patterns); presets upgraded from thin token sets to distinctive art directions; auto-propose generates it richly by default. Two hard rails only: (1) functional contract (testids/hooks/RLS/Blocks-mounts — unchanged), (2) shadcn-token contract (names + Tailwind wiring, so Blocks render). Everything else = design.md- authored, free. Static-verified: 65 design tests pass; faithful emit + custom-token pass-through; Blocks-contract validator catches a dropped name / broken @theme and passes a good globals.css; contrast/anti-slop now advisory; functional gates (Rail 1) intact. Live taste validation pending (next wave). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLz6M63G5vFJDZhW7dwBtb
…umeric test refs, token canary
Follow-ups from the pivot's static verify + the live TASTE proof (build PASS):
- design-md.mjs: tolerate unquoted CSS-function color values (oklch/oklab/lch/lab/rgb/hsl/hwb/
color-mix/color/var/calc/gradient) — a hand-authored `primary: oklch(0.55 0.34 280)` no longer
splits on internal commas into a false missing-primary. Balanced-paren aware; idempotent on already-
quoted values. +4 unit tests (65 -> 68).
- references/art-direction.md: the stale "50 design unit tests" literal -> non-numeric phrasing.
- fixtures/design/editorial.md: a tokens: block (custom props) so the design.md -> parse -> compile
pass-through is rot-canaried end-to-end.
Live taste proof (scratch build, independent eval PASS): an agent authored a rich design.md
("Margins — a reading room": Spectral serif + iron-gall ink + ~190 lines hand-written component CSS +
an authored editorial entity page + an auth title-page) and the evaluator returned genuinelyTasteful +
distinctiveVsOldGeneric + blocksCompose + contractHeld + pivotValidated — a clear step-change from the
old generic output, with live-qa CRUD-through-RLS PASS and Blocks still composing. (Authoring took
~62min — the real cost of genuine taste vs the ~10min token-swap path.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLz6M63G5vFJDZhW7dwBtb
The design compiler was already dead code on the live build path (the agent hand-authors the CSS), so delete it and the contradictory "compiler writes your tokens" story. Collapse design-system.md + art-direction.md into one lean design-guide.md, ship 6 anonymized real-world exemplars + the constructive opt-out, and keep ONE functional gate (check-design.mjs --app validates the built globals.css still defines the shadcn token names + Tailwind-v4 wiring so Blocks render — functional, not stylistic). - DELETE: wire-design.mjs; compile/oklch/invariants/fonts.mjs + their tests; the engine fixtures; design-system.md; art-direction.md; 6 heavy presets - ADD: scripts/lib/design/tokens.mjs (single-source 39-name contract); references/design-guide.md (232 lines); references/examples/*.md (7 exemplars) - check-design.mjs -> functional Rail-2 validator only (366 -> 188 lines) - gate rewired onto the BUILT globals.css (verify-gates.sh / genericity-check.sh) - SKILL.md S6.5 removed; speedrun S6.5 -> S7.5 (after the skeleton); brief-grammar design block slimmed (lines 1-563 byte-unchanged); density read + all rails kept Net +291 / -5484. Verified GREEN: blocks-contract test, gate bidirectional proof (valid->0, dropped-token->1, broken-wiring->1), static canaries, single-model coherence. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Slim the
constructive-builderskill's design layer from machinery → guidelines.The design compiler was already dead code on the live build path (the agent hand-authors the CSS),
so this deletes it and the contradictory "compiler writes your tokens" story, collapses three docs
into one lean opinionated guide, ships condensed anonymized exemplars, and keeps exactly one
functional gate (the built
globals.cssmust keep the shadcn token names + Tailwind-v4 wiring soBlocks render).
Net: +291 / −5,484 lines.
Changes
wire-design.mjs;compile/oklch/invariants/fonts.mjs+ their tests;the engine fixtures;
references/design-system.md(587) +references/art-direction.md(400);the 6 heavy
fixtures/design/*.mdpresets.scripts/lib/design/tokens.mjs(single-source 39-name shadcn contract);references/design-guide.md(232 lines — the one opinionated guide);references/examples/*.md(7 condensed exemplars: Graphite / Prism / Eclipse / Folio / Solaris /Concrete + the
constructiveopt-out).check-design.mjs→ functional Rail-2 validator only (366 → 188 lines).globals.css; SKILL.md S6.5 removed; speedrun S6.5 → S7.5(after the skeleton);
brief-grammar.mddesign block slimmed (lines 1–563 byte-unchanged).Validation
blocks-contracttest; the functional gate proven bidirectional (valid → exit 0,dropped token → 1, broken
@theme inline→ 1); static canaries; single-model coherence acrossSKILL.md / speedrun / design-guide / brief-grammar.
Folio editorial / Prism colorful gallery), each design-gate pass + RLS round-trip pass. The
thesis holds: agents authored genuine restructures from the guidelines, not recolors.
Known gaps — why this is a DRAFT (fix before merge)
scripts/lib/brief-policy.mjsKNOWN_DESIGN_PRESETSstill lists the oldpreset names, so
design: { preset: eclipse|folio|prism }— the exemplarsdesign-guide.mdadvertises — hard-errors at provision. Fix: replace the set with the 7 shipped exemplar aliases.
check-design.mjs --app <root>resolves<root>/src/app/globals.cssliterally and doesnot probe
packages/app(theverify-phasegate wraps it correctly; only the bare S7.5 command is off).scaffold-frontendquick-add fills only the first requiredfield → multi-required-field entities ship type-broken until hand-fixed.
live-qa.mjsdoesn't auto-locate the brief under the cleome outer-dir layout (needsLIVE_QA_SPEC); the nested relationselect:{}shape is undocumented (tsc catches it).Stress-test scorecard: built 3/3 · design-gate 3/3 · live-QA 3/3 · hands-free 0/3 (the 0/3 is GAP-1 + GAP-2).
🤖 Generated with Claude Code