Skip to main content

Design Variant Picker

Generate 3 HTML design previews before site build.

Skill metadata​

SourceBundled (installed by default)
Pathskills/creative/design-variant-picker
Version1.0.0
AuthorVibeOS
LicenseMIT
Platformslinux, macos, windows
Tagsdesign, variants, preview, landing, creative, html, tokens, gallery
Related skillsclaude-design, popular-web-designs, design-to-code-loop, internet-starter, design-md, desktop-local-preview, cinematic-web

Reference: full SKILL.md​

info

The following is the complete skill definition that VibeOS loads when this skill is triggered. This is what the agent sees as instructions when the skill is active.

Design Variant Picker Skill

When a user loudly and clearly asks for a site (“landing for a coffee shop”, “SaaS like Linear”, “calm yoga studio, lots of air”), do not scaffold a full Next app first. Normalize the brief, generate three visually different HTML preview stubs + tokens, let the user pick A/B/C, then lock DESIGN.md and design/tokens.css before internet-starter / design-to-code-loop. Every direction also fixes its graphic language and one motion density (quiet, expressive, or cinematic) before implementation.

This skill owns procedure + scripts + templates. Brief Architect owns references/briefs.yaml + references/tone-brand-map.md (8 loud scenarios + tone→brand families). Fixture & QA owns fixtures/ and tests/skills/test_design_variant_picker.py. Do not edit those paths from here.

Load canonical scenarios when normalizing a brief or writing offline tests: skill_view(name="design-variant-picker", file_path="references/briefs.yaml") and the mapping table in references/tone-brand-map.md.

When to Use​

  • User asks for a new landing / marketing site / portfolio with taste expectations
  • Request names a brand mood (“like Stripe”, “not dark”, “no purple”)
  • You need side-by-side design directions before committing to scaffold
  • Desktop Design rail will read manifest.json (phase 2); skill path works without UI

Prerequisites​

  • claude-design for taste and HTML artifact rules
  • popular-web-designs when brief maps to a known brand family
  • design-to-code-loop after selection (not during variant generation)
  • internet-starter after selection if no app exists yet
  • desktop-local-preview or /preview to open preview.html
  • Write access under project or profile home for .vibeos/design-variants/

How to Run​

End-to-end (operator):

  1. Normalize user text → normalize_brief.py → run brief.md (+ optional JSON)
  2. Generate variants A, B, C (default N=3; fourth only if brief is wide or user asks)
  3. Write manifest.json; run validation + diversity gate
  4. User picks variant → select_variant.py locks choice into project
  5. Then apply tokens → scaffold first page — never before step 4

Scripts (from repo root):

python3 skills/creative/design-variant-picker/scripts/normalize_brief.py \
--text "Сделай лендинг для уютной кофейни, без неона" \
--out .vibeos/design-variants/run-<id>/brief.md \
--json-out .vibeos/design-variants/run-<id>/brief.json

python3 skills/creative/design-variant-picker/scripts/normalize_brief.py \
--seed-id local_coffee_salon \
--out .vibeos/design-variants/run-<id>/brief.md

python3 skills/creative/design-variant-picker/scripts/validate_manifest.py \
--manifest .vibeos/design-variants/run-<id>/manifest.json

python3 skills/creative/design-variant-picker/scripts/diversity_gate.py \
--run-dir .vibeos/design-variants/run-<id>/

python3 skills/creative/design-variant-picker/scripts/select_variant.py \
--run-dir .vibeos/design-variants/run-<id>/ \
--variant B \
--project-dir ./my-site

python3 skills/creative/design-variant-picker/scripts/ensure_variant_tokens.py \
--run-dir .vibeos/design-variants/run-<id>/

python3 skills/creative/design-variant-picker/scripts/latest_run.py \
--project-dir ./my-site

python3 skills/creative/design-variant-picker/scripts/mix_variant.py \
--run-dir .vibeos/design-variants/run-<id>/ \
--colors A --fonts C [--out-id H]

python3 skills/creative/design-variant-picker/scripts/archive_run.py \
--run-dir .vibeos/design-variants/run-<id>/

python3 skills/creative/design-variant-picker/scripts/reject_variant.py \
--run-dir .vibeos/design-variants/run-<id>/

python3 skills/creative/design-variant-picker/scripts/apply_design.py \
--project-dir ./my-site

# Day 14 MVP page (preferred)
python3 skills/creative/design-variant-picker/scripts/scaffold_landing_page.py \
--project-dir ./my-site

# Alternate template path (same pipeline stage)
python3 skills/creative/design-variant-picker/scripts/scaffold_page.py \
--project-dir ./my-site

Quick Reference​

ArtifactPurpose
brief.mdNormalized brief for this run
manifest.jsonVariant list + metadata for UI / scripts
A/preview.htmlSelf-contained hero + 1–2 sections
A/tokens.css:root CSS variables
A/direction.mdArt direction, graphic language, motion contract, anti-patterns
A/thumb.pngOptional gallery thumbnail
selected.json{ "variant": "B", "locked_at": "…" } after pick
design/tokens.cssCopied into project on select
DESIGN.mdCopied from chosen direction.md on select
ScriptExitRole
normalize_brief.py0/1Loud text or --seed-id → brief.md / JSON
validate_manifest.py0/1Schema + files exist
diversity_gate.py0/1Variants differ enough
ensure_variant_tokens.py0/1tokens.css + colors[] fallback (no screenshot)
capture_variant_thumbs.py0/1/2Optional thumb.png (colors strip offline; Playwright optional)
latest_run.py0/1Newest run-* with manifest under project
select_variant.py0/1Lock + copy to project
mix_variant.py0/1Hybrid variant: colors from one id, fonts from another
archive_run.py0/1Move run dir to archived/ before regenerate
reject_variant.py0/1Clear lock without archive / project copy
apply_design.py0/1/2After lock: @import tokens into app CSS (2 = no app)
scaffold_landing_page.py0/1/2After apply — preferred MVP page.tsx Hero→Footer (2 = missing lock)
scaffold_page.py0/1/2After apply — alternate template path (page.tsx.tmpl; 2 = no app dir)
DefaultValue
Variant count N3 (A, B, C)
Run folder.vibeos/design-variants/run-<timestamp>/
Post-select tokens<project>/design/tokens.css
Post-select direction<project>/DESIGN.md

Procedure​

1. Create run directory​

.vibeos/design-variants/
run-<timestamp>/
brief.md
manifest.json
A/ preview.html tokens.css direction.md [thumb.png]
B/ …
C/ …
selected.json # after user picks

Use ISO-ish run id: run-20260721T120000Z. Paths in manifest.json are relative to the run folder.

2. Normalize brief​

Run normalize_brief.py on the user's loud request (or --seed-id for offline seeds in references/briefs.yaml). Writes brief.md from templates/brief.md and optional JSON with structured fields. Required fields:

FieldNotes
industrye.g. coffee shop, B2B SaaS, portfolio
audiencewho lands on the page
tonecalm / bold / luxury / playful / technical
primary_ctaone main action
must_sectionshero + blocks user expects
forbidhard negatives — colors, dark mode, card soup
reference_brandsStripe, Linear, etc. if named
localeru / en

Good: “Calm yoga studio, light only, no purple, hero = one headline + book class.”
Bad: Dropping forbid list; vague “modern and clean” with no industry.

If user named a brand: one variant should brand-match; others are mood neighbors, not clones (see Agent A references/tone-brand-map.md when present).

3. Generate variants (default N=3)​

For each id in A, B, C:

  1. Copy templates/direction.md → <id>/direction.md (fill title, why, layout_keyword, fonts, palette, graphic language, and motion contract)
  2. Write <id>/tokens.css with --color-*, --font-*, spacing tokens
  3. Write <id>/preview.html — self-contained HTML+CSS; hero + one follow section max
  4. Optional thumbs: python3 scripts/capture_variant_thumbs.py --run-dir <run> (--mode colors = offline palette strip; --mode playwright = preview screenshot). Always keep colors[] (≥3 hex) for swatches when thumbs are skipped. Run ensure_variant_tokens.py to backfill missing tokens.css / colors[] without network.

Do not run internet-starter, create app/page.tsx, or full Next scaffold for each variant. Previews are lightweight HTML stubs only.

Load popular-web-designs templates when brand_ref is set. Load claude-design for process and anti-slop. Use read_file / patch for files; use browser_navigate or desktop /preview to verify previews open.

4. Hero budget (first screen)​

One job on the hero — no clutter:

Allow (pick one each)Forbid in hero
Brand mark or wordmarkFake metrics / “10k+ users” stats
One headline (H1)Pill badge clusters
One primary CTAFeature card grid
One visual anchor (photo, product, abstract shape)Stock-photo clichés with overlay stickers
Optional one line of supporting copyPurple/pink AI gradient blobs
Dashboard mockups with invented numbers
More than two type sizes above the fold

Sections after hero may add proof/features; keep preview.html short (hero + 1 block).

5. Anti-slop rules (all variants)​

Across A/B/C you must vary direction, not just hue:

  • No four “AI purple gradient” clones
  • No glassmorphism-by-default, rainbow palettes, emoji decor unless brand uses them
  • No left-border accent callout cards as the only layout idea
  • No generic labels (“Insights”, “Scale”, “Optimize”) without real copy
  • Respect forbid[] from brief literally (if “no dark theme”, no variant is dark)
  • Layout keywords must differ across A/B/C (hard gate): editorial, split, full-bleed, centered, asymmetric, grid, stacked, craft, soft-wellness, hybrid (mix) — diversity_gate.py fails when all variants share one keyword
  • Motion density should differ when the brief permits it. Show quiet, expressive, and cinematic behavior instead of giving three static color variations the same choreography.

Forbidden clichés (Day 16 — never ship these in preview.html):

ClichéWhy it fails taste
Purple / indigo / violet glow, neon mesh, pink→indigo blobsDefault AI “premium”; almost never brand-true
Fake metrics hero (“10k+ users”, “99.9%”, invented stars)Lies in first screen; proof belongs below or omit
Card soup in hero (3–6 equal feature cards above fold)Kills hero budget; features sit after
Pill badge clusters / floating stickers on photosNoise; one visual anchor max
Glassmorphism frosted panels by defaultTrend residue unless brand is glass/OS UI
Dark UI shell when brief says light / “no dark”Violates forbid[]; Linear brand-match stays light
Rainbow accents + emoji decorationUnless the brand literally uses them
Fake scarcity / countdown badges without real dataFake urgency
Identical layout + font family + near-same paletteCaught by diversity gate — regenerate

Good reference HTML (offline, no CDN): references/good-variants/editorial.html, split.html, full-bleed.html.

6. Write manifest.json​

Minimal shape (full schema: templates/manifest.schema.json):

{
"run_id": "run-20260721T120000Z",
"brief_path": "brief.md",
"created_at": "2026-07-21T12:00:00Z",
"variants": [
{
"id": "A",
"title": "Quiet Editorial",
"why": "Calm tone and airy type fit a wellness brief.",
"brand_ref": "original",
"preview_path": "A/preview.html",
"tokens_path": "A/tokens.css",
"direction_path": "A/direction.md",
"colors": ["#f7f5f2", "#2a2520", "#8b7355"],
"fonts": { "heading": "Fraunces", "body": "Source Sans 3" },
"layout_keyword": "editorial"
}
]
}

Each variant needs colors[] (≥3 hex for gallery swatches) or thumb_path. Offline runs use colors[] only — no screenshot required. Validate:

python3 skills/creative/design-variant-picker/scripts/validate_manifest.py \
--manifest .vibeos/design-variants/run-<id>/manifest.json

7. Ensure tokens + colors (offline fallback)​

Before validation or when thumbs are skipped:

python3 skills/creative/design-variant-picker/scripts/ensure_variant_tokens.py \
--run-dir .vibeos/design-variants/run-<id>/

Repairs missing/empty tokens.css from manifest colors[] + fonts, adds --color-* when absent, and restores colors[] (≥3 hex) from existing CSS. No network; thumb.png is optional when colors[] is present.

8. Diversity gate​

Before showing the gallery to the user:

python3 skills/creative/design-variant-picker/scripts/diversity_gate.py \
--run-dir .vibeos/design-variants/run-<id>/

If exit 1 — fix in this order (Day 16 procedure):

  1. Same layout_keyword on all variants → assign distinct skeletons first (editorial / split / full-bleed / centered). Do not only recolor.
  2. Pair too similar (≥2 of layout / font / palette) → change the closest variant’s layout_keyword and heading font and ≥2 palette hexes.
  3. Re-run the gate. Optional: --strict-layouts for CI-style “all distinct + canonical keywords”. Thresholds: diversity_gate.py --help.

8b. Desktop bridge (after variants exist)​

After writing run artifacts and diversity_gate.py exits 0, tell the user how to open the gallery — do not scaffold Next or call internet-starter yet.

  1. Resolve the run directory (absolute path):
python3 skills/creative/design-variant-picker/scripts/latest_run.py \
--project-dir /path/to/project
  1. Print in chat (one short block):
  • Absolute path to the run directory
  • Suggest opening the Design tab in Desktop, or slash: /design or /design load <absolute-run-dir>
  • One machine-parseable marker line (Desktop may parse later):
VIBEOS_DESIGN_VARIANTS_RUN=/absolute/path/to/run-20260721T120000Z

Example assistant message:

Three design directions are ready (A/B/C). Open the Design tab in the right
rail (or use the Open variants control in chat), or run
`/design load /Users/you/my-site/.vibeos/design-variants/run-20260721T120000Z`.
VIBEOS_DESIGN_VARIANTS_RUN=/Users/you/my-site/.vibeos/design-variants/run-20260721T120000Z

Hard rule (no scaffold before select): do not run internet-starter, create app/page.tsx, or start a full Next scaffold until the user selects a variant (select_variant.py or Desktop Select). Variants + Design gallery only — scaffold is step 10, never step 8.

9. User selection → lock​

After explicit user choice (chat, Desktop Design tab, or slash):

python3 skills/creative/design-variant-picker/scripts/select_variant.py \
--run-dir .vibeos/design-variants/run-<id>/ \
--variant B \
--project-dir /path/to/project

Writes selected.json, updates manifest.selected, copies:

  • <variant>/tokens.css → <project>/design/tokens.css
  • <variant>/direction.md → <project>/DESIGN.md

Re-running select is idempotent (overwrites lock and project files).

10. After lock only (Day 13 — apply into a real app)​

Run this only after select_variant.py (or Desktop Select) has written selected.json, <project>/design/tokens.css, and <project>/DESIGN.md. Do not start apply while the gallery is still open for pick / mix / reject.

10.1 Detect whether an app exists​

Look for a CSS entry under --project-dir (first match wins):

Candidate pathTypical stack
app/globals.cssNext.js App Router
src/app/globals.cssNext.js App Router (src/)
styles/globals.cssNext / CRA-style
src/styles/globals.cssVite / CRA with src/
app/global.cssAlternate Next naming

Offline stub for scripts/tests: fixtures/next-app-stub/app/globals.css (minimal :root shell).

App present = at least one of the paths above exists as a file.
No app = none found (empty project, tokens-only lock, or not scaffolded yet).

10.2 If no app — ask before scaffold​

  1. Tell the user there is no app CSS entry yet.
  2. Propose running internet-starter to scaffold (Next/SPA) into the same --project-dir (or a path they choose).
  3. Do not auto-run internet-starter without explicit user consent.
  4. After they confirm and scaffold finishes, re-check §10.1, then continue to §10.3. Re-run select_variant.py only if design/tokens.css / DESIGN.md were wiped by scaffold (normally keep them).

10.3 Apply locked tokens (apply_design.py)​

When an app CSS entry exists:

python3 skills/creative/design-variant-picker/scripts/apply_design.py \
--project-dir /path/to/project

Contract (script under scripts/apply_design.py):

  • Requires locked <project>/design/tokens.css (from select). Missing → exit 1.
  • Detects CSS entry via the paths in §10.1. None → exit 2 and print an internet-starter / scaffold hint — never scaffolds Next itself.
  • On success (exit 0): injects an idempotent block into globals.css:
/* vibeos-design-tokens:start */
@import url("../design/tokens.css");
/* vibeos-design-tokens:end */

Re-runs replace that span only (no duplicate imports).

  • When fonts can be derived from --font-* or a <link> comment in tokens, writes <project>/design/fonts.html for the operator to paste into layout.tsx / HTML head (does not auto-edit React layout).
  • Optional --json for machine-readable result.

Fallback if the script is unavailable: design-to-code-loop (read_file + patch) — same order, still only after select.

10.4 Verify select artifacts (already done at lock)​

Confirm these exist before treating apply as complete:

ArtifactSource
<project>/design/tokens.cssCopied by select_variant.py
<project>/DESIGN.mdCopied from chosen direction.md

Optional formal polish of DESIGN.md via design-md is fine but not required for Day 13 — select already wrote the direction file.

10.5 Stop here — Day 14 builds the page​

Do not invent a full cinematic site in this step. After apply exits 0, continue to §12 (scaffold_landing_page.py preferred) for the MVP landing page, then preview. Optional polish via cinematic-web / cinematic_landing_scaffold is not required for MVP.

Day 13 success = tokens live in app CSS. Day 14 success = first page.tsx under locked direction.

11. Day 11 — More variants, mix, reject (Desktop /design)​

When the user wants another batch of directions, a hybrid, or to back out of a choice without locking:

User intentDesktop slashScript / action
Regenerate A/B/C/design moreArchive old run, then new run (below)
Mix palette + type/design mix A Cmix_variant.py --colors A --fonts C
Clear selection / don't lock/design rejectreject_variant.py (clear lock only; ≠ archive)

Regenerate flow (operator):

  1. Archive the current run so latest_run.py and Desktop load a clean tree:
python3 skills/creative/design-variant-picker/scripts/archive_run.py \
--run-dir .vibeos/design-variants/run-<id>/

Moves to .vibeos/design-variants/archived/run-<id>-<timestamp>/.

  1. Create a new run-<timestamp>/, normalize brief, generate fresh A/B/C, validate + diversity gate (sections 2–8).

  2. Emit the Desktop bridge marker again:

VIBEOS_DESIGN_VARIANTS_RUN=/absolute/path/to/run-20260721T140000Z

Suggest /design load <path> or open the Design tab. Do not scaffold Next until the user selects again.

Mix flow:

When the user likes colors from A but typography from C (or chat says “mix A and C”):

python3 skills/creative/design-variant-picker/scripts/mix_variant.py \
--run-dir .vibeos/design-variants/run-<id>/ \
--colors A --fonts C

Writes hybrid folder H/ (override with --out-id) with:

  • tokens.css — --color-* from --colors, --font-* from --fonts
  • direction.md — explains hybrid; layout_keyword = hybrid
  • preview.html — self-contained hero stub using hybrid tokens
  • Updated manifest.json entry (replaces existing same out-id)

Re-run diversity_gate.py — hybrid should still pass vs A/B/C when sources differ.

Desktop: /design mix A C should invoke the same script on the loaded run.

Reject flow:

Reject means: clear a tentative selection — do not lock, do not copy into project design/tokens.css / DESIGN.md. Reject ≠ archive the whole run.

python3 skills/creative/design-variant-picker/scripts/reject_variant.py \
--run-dir .vibeos/design-variants/run-<id>/

Deletes selected.json if present and removes manifest.selected (same fields select_variant.py writes). Leaves A/B/C (and hybrid) folders intact.

  1. Run reject_variant.py on the loaded run.
  2. Tell the user the gallery is unlocked; they can pick another variant or /design mix.
  3. Optionally archive the whole run if they asked to “start over” (archive_run.py).

Do not call select_variant.py on reject. Do not run internet-starter after reject.

12. Day 14 — Scaffold MVP landing page​

After select → apply succeeds, generate a first real page that follows the locked direction (not a random other site). Prefer scaffold_landing_page.py. Do not require cinematic-web for MVP.

WhoScriptNotes
Preferred MVPscaffold_landing_page.pyCLI + Desktop /design scaffold (intended)
Alternatescaffold_page.pytemplates/page.tsx.tmpl markers path

12.1 Prerequisites​

Confirm:

ArtifactFrom
<project>/design/tokens.cssselect_variant.py
<project>/DESIGN.mdselect_variant.py (chosen direction)
App CSS has token @importapply_design.py (exit 0)

Optional: latest run brief.md under .vibeos/design-variants/ (or pass --brief / --run-dir) for brand, CTA, and must-have section mapping.

12.2 Run scaffold​

python3 skills/creative/design-variant-picker/scripts/scaffold_landing_page.py \
--project-dir /path/to/project

# Alternate template path
python3 skills/creative/design-variant-picker/scripts/scaffold_page.py \
--project-dir /path/to/project

Contract (scaffold_landing_page.py):

  • Missing DESIGN.md or design/tokens.css → exit 2 (select+apply first).
  • Existing page.tsx without --force → exit 1 (no silent clobber).
  • Writes app/page.tsx or src/app/page.tsx (creates app/ if needed).
  • Styles only via var(--color-*) / var(--font-*) — no hardcoded purple slop.
  • Prints the written path on stdout (exit 0).

Alternate (scaffold_page.py + templates/page.tsx.tmpl):

  • Missing tokens/DESIGN → exit 1; no app/ / src/app/ → exit 2.
  • Markers vibeos-scaffold-page:start/end; refuses non-trivial overwrite without --force.

Map brief must_sections (and DESIGN.md title/why) to canonical blocks. Defaults when brief is sparse: Hero, Features, Proof, CTA, Footer. Full keyword table: references/section-map.md.

SectionRole
HeroBrand, one headline, one CTA, one visual job
Features2–3 value props (not hero clutter)
ProofTrust / quote / social proof
CTARepeat primary action
FooterHours / contact / locale envelope

12.4 Motion + prefers-reduced-motion​

Scaffold uses CSS-only fade/stagger (2–3 intentional reveals). Must include:

@media (prefers-reduced-motion: reduce) {
/* disable / simplify animations — no Framer Motion required for MVP */
}

12.5 Preview​

After scaffold exits 0:

  1. Start / open the app via desktop-local-preview or Desktop /preview
  2. Optional smoke: site-page-analyze vs brief expectations
  3. Operator may edit copy freely after first generation

Live Desktop /preview smoke is operator / Agent B — do not claim done offline.

12.6 Optional polish — cinematic-web (not MVP)​

Golden task cinematic_landing_scaffold (cinematic-web / scaffold_cinematic.py) remains ready as optional polish after design_variant_picker_scaffold_offline. Not required for Day 14 MVP.

Pipeline: select → apply → scaffold_landing_page → preview (→ optional cinematic-web).

Pitfalls​

Forbidden clichés / anti-slop​

Regenerate any variant that hits these — they read as generic AI output, not brief-specific design:

ClichéWhy it failsFix
Purple glow / purple–indigo gradient defaultInstant “AI slop” signal; ignores brief forbid[]Warm neutrals, brand-true accent, or brief reference palette
Fake metrics in hero (“10k+ users”, invented stars)Erodes trust; local/wellness briefs never asked for statsOne real headline + one CTA; proof lives below fold
Card soup / pill clusters in heroHero does four jobs at once; nothing readsOne visual anchor + one headline + one primary CTA (see §4 hero budget)
Identical layout across A/B/CGallery compares hue swaps, not directionsDistinct layout_keyword per variant (editorial, split, centered, full-bleed)
Dark UI when brief forbids darkViolates explicit forbid[] (e.g. yoga, coffee shop)Light surfaces, soft contrast; re-read brief before writing CSS

Taste references (not a run): references/good-variants/ — open locally before generating.

  • Scaffolding Next×3 before pick — expensive, slow, violates product contract
  • Auto-running internet-starter after lock — ask first; no silent scaffold
  • Applying tokens before select — apply_design.py needs locked design/tokens.css
  • Scaffolding page before apply — run /design scaffold or either scaffold script only after apply
  • Requiring cinematic-web for MVP — optional follow-on polish; Day 14 = locked-direction page.tsx
  • Ignoring forbid[] — user said “no dark”; all variants must comply
  • Same layout + font + palette — diversity gate exists; fix before user sees gallery
  • Full page in preview.html — hero + one section is enough for comparison
  • Skipping manifest validation — Desktop rail and tests expect stable schema
  • Editing Agent A/C paths — briefs.yaml, fixtures, tests are out of scope here
  • Mid-conversation cache break — defer /design variants skill load to turn boundary when possible; do not swap toolsets mid-turn for variant generation

Verification​

  • Run folder matches layout in section 1; brief.md filled
  • Exactly 3 variants by default (A/B/C) unless user asked for more
  • Each preview.html opens locally (file or static server) and shows distinct direction
  • validate_manifest.py exits 0
  • diversity_gate.py exits 0
  • After generation: chat shows run path + /design hint + VIBEOS_DESIGN_VARIANTS_RUN=…
  • latest_run.py --project-dir … exits 0 when a run exists
  • select_variant.py writes selected.json + project design/tokens.css + DESIGN.md
  • No full Next scaffold created before select
  • After lock: detect globals.css (or ask for internet-starter with consent)
  • apply_design.py --project-dir … exits 0 when app CSS exists (or manual design-to-code-loop merge); app CSS contains locked --color-* / --font-*
  • Day 14: scaffold_landing_page.py --project-dir … writes app/page.tsx (or src/app/page.tsx) with Hero/Features/Proof/CTA/Footer, token CSS vars, and prefers-reduced-motion (see references/section-map.md)
  • Alternate OK: scaffold_page.py + page.tsx.tmpl (same pipeline stage)
  • Preview via desktop-local-preview / /preview (operator) or offline site-page-analyze on fixture — shows locked direction
  • Brief forbid constraints visible in all previews
  • mix_variant.py adds hybrid H/ and diversity_gate.py still exits 0
  • archive_run.py moves run to archived/; regenerate uses a new run-*
  • Agent C tests pass: scripts/run_tests.sh tests/skills/test_design_variant_picker.py -q