shop-design-concept
The DRAW-FIRST gate — draw a real, self-contained HTML mockup of the target page (homepage for a full build; the page being redesigned; the section being edited) for the user to APPROVE before any code is written. Proactive on every visual task (build/redesign/clone/page-edit/section-edit), not opt-in. Authored in the store's Tailwind utility vocabulary (shop-core-rules §G.2) + token colors so the platform can inject the store's real CSS and the mockup renders in the real design system. Emit it wrapped in ⟦MOCKUP⟧…⟦/MOCKUP⟧; the FE shows it for approve / revise / draw-another-direction / skip; the approved HTML becomes the measurable §B reference and the build matches it section-by-section, top to bottom, with §D verification.
The user states an intent ("build me a website for my vegan restaurant", "redesign the homepage", "make this section look better"). Instead of building blind and re-styling for hours, DRAW a real HTML mockup of the target page for approval first. Once approved, the mockup IS the design reference: every shop-core-rules rule (§A–§M) applies as if the user had handed you a design — and because the mockup is authored in the SAME Tailwind vocabulary the build uses (and rendered with the store's real CSS), a mockup region looks like its built section.
This skill is mode "mockup" in the agent runner: you draw ONE mockup and STOP. The looping (approve / revise / draw-another / skip) is orchestrated by the front-end — each click re-runs you in mockup mode with the right instruction, or kicks off the build.
0. When to use / when NOT
- Use — proactively, for any VISUAL task: a full site build (draw the homepage), a redesign/restyle (draw the target page), a clone (draw the reproduction of the captured reference), a single-page edit (draw that page), a section edit (draw that section). The platform offers the gate with a skip-the-gate escape; you just draw when asked.
- Do NOT draw: a one-property tweak where there's nothing to look at first ("make the button green", "fix a price", change a meta title) — those go straight to the edit. Copy-only / SEO / i18n / pricing / QA tasks. If the user already declined the mockup in this thread, don't redraw.
1. Brief — you already have it
By the time you draw, the funnel has gathered the direction: a sparse build first proposes 2–3 text directions (the idea step) and the user picked one; a build with a stated direction skipped that. The chosen direction and the palette/brand hints arrive in your brief. Don't re-ask — draw. If something essential is genuinely missing, pick a sensible premium default and name it in your summary so the user can correct it via a revise request.
2. Draw the HTML mockup (the quality-deciding part)
STREAM the page IN PARTS, region by region, wrapped in these markers (each marker ALWAYS on its OWN line), as the final part of your message. This is NOT one giant blob: emit the HEAD, then one ⟦SECTION <slug>⟧ block per region, then close. The platform captures each region the instant you close it, so a long page can't be lost to a single truncated turn — and the user watches it draw top-to-bottom:
⟦MOCKUP⟧
<!doctype html><html lang="…"><head>… meta, Google-fonts, Lucide CDN, <style>:root{--accent/--ink/--paper/--cream/--mute/--line/--font-display/--font-sans}</style> + any @keyframes. NO Tailwind CDN — the platform injects the store's real bundle …</head>
<body class="…">
⟦SECTION header⟧
<header data-mock-region="header"> … logo + nav + working hamburger … </header>
⟦SECTION hero⟧
<section data-mock-region="hero"> … </section>
…one ⟦SECTION <slug>⟧ + its block for EVERY region, top to bottom…
⟦SECTION footer⟧
<footer data-mock-region="footer"> … </footer>
<script> … shared JS: lucide.createIcons(); hamburger; scroll-reveal …</script>
</body></html>
⟦/MOCKUP⟧
- Everything after
⟦MOCKUP⟧and before the first⟦SECTION⟧is the HEAD (doctype,<head>, opening<body>). Write it once. - Before EACH region write a
⟦SECTION <slug>⟧line on its own line (<slug>= that region'sdata-mock-regionvalue); finish each region's block fully before the next. - The shared
<script>+</body></html>go at the END of the LAST region's block, right before⟦/MOCKUP⟧. - ⚠️ If your message is CUT OFF before
⟦/MOCKUP⟧, a follow-up turn asks you to CONTINUE: re-emit⟦SECTION <slug>⟧for the region you stopped on (redraw it fully) and every region after it, then the shared<script>,</body></html>, and⟦/MOCKUP⟧. Don't re-emit the head or finished regions — the platform stitches the parts together by slug.
Author with the STOREFRONT'S OWN Tailwind — so the build reproduces the mockup 1:1 (this is the whole point):
- ⚠️ DO NOT load the Tailwind Play CDN. The platform INJECTS the store's REAL bundle (
assets/theme.css+assets/tailwind.css— the exact CSS the live storefront ships) into your mockup preview, so what you draw renders in the SAME engine the built store uses (WYSIWYG). A class that's in the bundle renders identically once built; a class that isn't renders UNSTYLED (you SEE it break) — the signal to fix it, because the build can't reproduce it. The bundle is STATIC (no JIT). - USE the bundle's vocabulary (
shop-core-rules§G.2): standard utilities (flex grid grid-cols-1..12 gap-* p/px/py-* m-* w-* h-* max-w-7xl text-xs..9xl font-semibold rounded-xl shadow-md object-cover+sm:/md:/lg:+hover:/focus-visible:) PLUS the store's brand utilities (py-section/px-gutter,shadow-1/2/3,font-display/font-sans). - ⚠️ COLORS THROUGH TOKENS ONLY — non-negotiable (build's themelint REJECTS any other color, and the bundle has no other colors):
bg-accent/text-ink/bg-paper/bg-cream/text-mute/border-line/bg-accent-soft(+-white/-black). Choose the palette by defining the tokens once in<style>:root{--accent:#1B3A5B;--accent-soft:#…;--ink:#…;--paper:#…;--cream:#…;--mute:#…;--line:#…;--font-display:'<display family>',sans-serif;--font-sans:'…',sans-serif}</style>— thenbg-accentrenders that hex,font-displaythat font. The BUILD reads these SAME tokens →set_global_settingswith the identical hex/fonts → exact color match. One Google-fonts<link>for the pairing — and the:rootfamilies MUST actually be IN that link (an unloaded family renders a browser fallback = the "wrong font" bug; the platform checks this). ⚠️ FONT BANS (§G.1, checked): theFraunces+Space Groteskpairing is the tell-tale AI cliché — banned outright; do NOT default the DISPLAY font toInter/Poppins/Montserrat/DM Sans/Sora/Plus Jakarta Sans/Space Groteskeither. Pick a distinctive display face (Bricolage Grotesque, Instrument Serif, Spectral, Newsreader, Cormorant…) with the store's language subset (verify it on the family's Google Fonts page). - ⚠️ NO arbitrary values, NO hex/default-palette classes:
bg-[#1B3A5B],py-[83px],w-[673px],text-[42px],bg-blue-600,text-red-500DO NOT EXIST in the static bundle → render NOTHING (and color literals are rejected at build). One-off exact size → inlinestyle="width:673px", never a[...]class. Colors → always a token, never a literal. - CDN libraries are FINE (no CSP): GSAP for rich scroll/timeline, or vanilla JS + CSS — your call. (Only the Tailwind CDN is excluded — the store bundle is the Tailwind.)
- ⚠️ CONTENT VISIBLE BY DEFAULT — animation is enhancement, never a gate. NEVER leave an element at
opacity:0/translated-out in CSS waiting for a scroll trigger; in the preview that trigger may not fire → invisible element → empty-looking section (the #1 empty-section bug). Set the hidden start-state via JS (hides only when JS runs + will reveal) + a reveal-on-load fallback. A blank section = fail. - Write efficiently, don't cap content — include as many sections as the design/business needs (a long rich page is fine, not capped); just reuse a few CSS classes / lean on terse Tailwind utilities instead of a big repeated inline style per element. Efficiency is HOW you write it, not cutting sections.
Content rules (core §B):
- Scope-aware (what to draw):
- Full build (whole store) → the COMPLETE HOMEPAGE, full page top→bottom, nothing missing: a real header (logo + full nav) → hero → 4–6 business-appropriate content sections → a real footer (link columns + contact). Header and footer are MANDATORY. ⚠️ ECOM shop = PRODUCT-LED home (if
get_contextshows commerce enabled): the content sections MUST center on PRODUCTS — include 2–3 product-showcase grids (featured/best-sellers, shop-by-category tiles, new arrivals) drawn as real product cards (image + name + price, optional rating/badge), plus 1–2 supporting sections (trust/USP strip, promo, newsletter). A shop home with only hero + about + testimonials and NO product grids is WRONG. The cards are placeholders (Pexels photos); the build binds them to the real catalog (a{% for %}loop, never hard-coded). - Page redesign / page edit → THAT page, wrapped in the store's header + footer chrome (real nav labels from the header's link blocks, the real store name in the logo) so it shows in real context, not a bare body. The page's own content sections sit between the header and footer. Richness floor: even a single-page mockup opens with a hero-grade block and carries ≥ 2–3 real content sections — one thin band between chrome is the thin-page fail.
- Section edit → JUST that one section (a single
<section>block), no chrome. A section-scoped chat can't introduce a new section type, so draw a RESTYLE of the existing block.
- Full build (whole store) → the COMPLETE HOMEPAGE, full page top→bottom, nothing missing: a real header (logo + full nav) → hero → 4–6 business-appropriate content sections → a real footer (link columns + contact). Header and footer are MANDATORY. ⚠️ ECOM shop = PRODUCT-LED home (if
- REAL brand name in logo + hero; real menu labels (read them); real button text — never lorem, never invent a different brand. Real copy in the user's language.
- One
⟦SECTION <slug>⟧+<section data-mock-region="<slug>">per design block, in the order the build will place them (hero, features, testimonials, faq, cta…). The⟦SECTION⟧slug and thedata-mock-regionMUST match; use short kebab-case slugs. These slugs ARE the section list the build follows, top to bottom — the FE reads them to drive the progressive preview. - Images — keep the mockup FAST: use
search_stock_images(Pexels) and drop the candidate photo URLs straight into<img src>, OR a coloured token block (<div class="bg-accent-soft …">+ a label) where you have no fitting photo. Stock photos only — never hand-draw or fake imagery. Never a broken external URL. (Re-hosting also happens in the build — a Pexels candidate URL embedded directly is fine here.) - Apply
shop-design-tasteFULLY: layout variance (no monotone equal-card grids), eyebrow→heading→body hierarchy, generous spacing rhythm, an asymmetric/featured section. Custom-designed, not a template. - ⚠️ CONTRAST (non-negotiable, the #1 broken-look bug): every text/icon MUST be legible on ITS OWN background. On a DARK or accent panel (dark footer, colored CTA band) the text/links/headings MUST be LIGHT (white/pale) — NEVER dark-ink-on-dark, NEVER pale-grey-on-white. A section's surface + its text color travel TOGETHER: flip a section to a dark/accent bg → flip its text to the light variant in the same rule. Check EACH section's text-vs-bg pair (a dark footer with dark links is the classic fail — do not ship it). WCAG AA with numbers (§G.1 — the platform MEASURES these on your
:roottokens and bounces violations back for a re-emit): body/small text ≥ 4.5:1, large headings (≥24px, or bold ≥19px) ≥ 3:1;--inkon--paper/--creamand--accent-inkon--accentmust each pass 4.5:1,--muteon--paper≥ 3:1. - COLOR DISCIPLINE: palette only — a bg, an ink, ONE accent used sparingly (CTAs/highlights), maybe one secondary. No low-contrast tint-of-bg text; no same-hue glyph on same-hue chip.
- Icons — FULL set via CDN: load Lucide (
<script src="https://unpkg.com/lucide@latest"></script>) then<i data-lucide="<name>"></i>+ alucide.createIcons()call → EVERY Lucide icon by name (maps 1:1 to the build's{% render 'icon' %}). Inline<svg>also fine (and required for brand/social glyphs — see the build skills). - ⚠️ NO EMOJI — anywhere in the mockup (core §G). Never use an emoji (🛒 ✨ 🔥 ✅ 🚀 ⭐ …) as an icon, in the eyebrow/heading/subhead, in a badge/pill/label, in button/CTA text, in body copy, list bullets, testimonials, FAQ, stats, or the footer. They render per-OS, break the type rhythm, and garble stacked diacritics. Use a Lucide glyph (or inline
<svg>) where you want a pictograph and plain text otherwise. A mockup with an emoji is a FAIL. - ⚠️ CONTAINER DISCIPLINE — content never bleeds past the page edge (a hard rule; "section tràn container" is a top failure). EVERY section wraps its CONTENT in a centered container:
<div class="max-w-7xl mx-auto px-5 md:px-8">(usemax-w-6xl/max-w-5xlfor text-heavy/narrow sections). A section may paint a full-bleed background (color/image spans edge-to-edge) but its TEXT/cards/grid stay inside that inner container — never glued to the viewport edge. The page body must NEVER scroll horizontally at any width: anything wide (a wide table, a code block, a horizontal-scroll row) is confined withoverflow-x-autoon ITS OWN wrapper, never by letting the section overflow. Don't set widths that exceed the container (w-screeninside a padded parent, fixedwidth:1400px, negative margins without a matching clip) — they cause the horizontal-overflow bug. - ♻️ RICH, PROFESSIONAL INTERACTION PATTERNS — use them where they fit (what pro sites do):
- Carousel / horizontal-scroll row for a flexible list (case studies, product highlights, logos, testimonials, a "judge us by what's live" panel strip): prefer CSS scroll-snap — a flex row in
overflow-x-auto snap-x snap-mandatorywith each cardsnap-start shrink-0 w-[80%] md:w-[360px]— it needs NO JS, ports 1:1, and never breaks the page width (the scroll is contained). For autoplay/arrows, add a small inline<script>. Great for turning a monotone equal grid into something with rhythm. - Hover-reveal / flip card — extra info appears on hover via CSS only: a
groupwrapper +group-hover:(slide a caption up, fade an overlay in, flip with[transform:rotateY(180deg)]on hover). Portable, no JS. - Scroll-reveal & parallax — entrance on scroll (GSAP/IntersectionObserver) and gentle parallax for depth (but content VISIBLE by default — animation is enhancement, never a gate; see the contrast/visibility rule below).
- Sticky / pinned column, marquee logo strip, before/after slider, count-up stats — apply tastefully where the content calls for it. Don't force every section to move; pick 2–4 signature interactions per page.
- Carousel / horizontal-scroll row for a flexible list (case studies, product highlights, logos, testimonials, a "judge us by what's live" panel strip): prefer CSS scroll-snap — a flex row in
- JS + libraries ALLOWED — real motion + interactivity: GSAP (CDN) for rich scroll/timeline, or a small inline
<script>with IntersectionObserver + CSS transitions. Hover, hero entrance, scroll-reveal. - Interactivity must actually WORK: the header nav and especially the MOBILE HAMBURGER must toggle open/closed for real (inline JS or CSS); tabs/accordion/slider must function. A dead hamburger = fail.
- Responsive ALL THREE: desktop + tablet (≤1024px) + mobile (≤768px) —
md:/lg:+@media, no horizontal overflow at any width, nav collapses to the working hamburger on mobile (the preview shows all three widths). - ⚠️ COMPLETE page, never partial: every region — header + EVERY content section + footer — as its own
⟦SECTION⟧block, fully laid out (a sketch, but a complete one). Never stop after the hero, never omit the footer, never leave a region as a bare heading. Keep each region TIGHT (shorter copy, lean utilities) so the whole page streams without running long — but keep ALL regions. - PORTABLE markup — the build REUSES this exact HTML/CSS/JS 1:1 (only static→dynamic), so write clean semantic structure (one
<section>per block, sensible class names).
After ⟦/MOCKUP⟧, add 2–4 short lines (in the user's language) naming the palette hex, the font pairing, and the section list — so the user reads WHAT they're approving. This short summary is the ONLY chat prose; do NOT narrate the HTML itself (it streams into the preview, not the chat).
2.5 Signature interaction patterns — the pro-web playbook (draw these into the mockup)
A flat page of equal grids reads as AI-generic. Motion is TWO SEPARATE LAYERS with different budgets — do not merge them:
- Layer 1 — hover/focus MICRO-INTERACTIONS (§B): MANDATORY & UNCAPPED. EVERY card, tile, image, button, link and icon reacts to the pointer (lift, 3D tilt, image zoom, reveal, underline-sweep…). A flat grid with no hover response is the dead-page failure. This is NOT part of the 2–4 budget — it goes on everything, every section, every brand (even quiet luxe: a soft lift + slow zoom).
- Layer 2 — SIGNATURE scroll/entrance moments (§A/§C/§D): pick 2–4 per page (not every section moves), matched to the content — THIS is the budgeted layer. In the MOCKUP you may use inline JS + CDN GSAP freely (the preview loads them) — but the build REUSES this markup, so prefer the CSS-only version (it ports 1:1 with no rewiring); JS-driven ones get rewired to the runtime's
data-anim/window.gsapin the build (shop-design-taste§6). Everything stays VISIBLE by default (animation is enhancement) and inside the container (§2 overflow rule).
A. Flexible lists → carousel / horizontal scroll (use instead of a cramped 5-across grid; great for case-studies, product highlights, testimonials, logos, steps — the "judge us by what's live" strip):
- ⚠️ ENOUGH ITEMS OR IT CAN'T SCROLL: a horizontal row only overflows — so swipe / drag / arrows actually move — when it holds MORE cards than fit across the viewport. Author ~2× the visible count: ≈3 cards show on desktop → put 6-8 real cards; a wide logo/testimonial strip → 8-12. Too few cards = the row fits on screen, never overflows, and the carousel is DEAD (arrows do nothing, no drag). Fill the extra slots with REAL items (or rotate real photos) — never blank/placeholder filler just to pad the count.
- Scroll-snap row (CSS-only, PREFERRED — ports clean, never breaks page width): a flex track
flex gap-6 overflow-x-auto snap-x snap-mandatory scroll-smooth [scrollbar-width:none] [-webkit-overflow-scrolling:touch] pb-4with each cardsnap-start shrink-0 w-[82%] sm:w-[60%] lg:w-[380px]. Add a hint (→ kéo ngang) + optional prev/next buttons thatscrollBy({left, behavior:'smooth'}). Bleed it to the edge intentionally: put the track full-width but keep the FIRST card aligned to the container's left gutter (pl-5 md:pl-8). - Pinned horizontal-scroll (JS, GSAP): the section pins while vertical scroll drives the row sideways (the cinematic version of the screenshot). Mockup: GSAP
ScrollTriggerpin +xtween; build:window.gsapguarded. Use for ONE hero-tier showcase, not routine lists. - Drag-to-scroll: add pointer-drag inertia on the scroll-snap track (small inline JS) for a tactile feel.
B. Hover micro-interactions (CSS-only, all port clean) — LAYER 1, apply to EVERY card/tile/image/button/link, NOT budgeted:
- Reveal-on-hover — caption/overlay hidden until hover: a
groupwrapper + childtranslate-y-full opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition duration-300(info slides up over an image card). - Flip card — front/back faces: wrapper
[perspective:1000px], inner[transform-style:preserve-3d] transition-transform duration-500 group-hover:[transform:rotateY(180deg)], faces[backface-visibility:hidden](back also[transform:rotateY(180deg)]). - Image zoom —
overflow-hidden rounded-2xl+img transition duration-500 group-hover:scale-105. - 3D tilt — a card tilts toward the cursor: wrapper
style="perspective:900px", cardtransition-transform, a tinypointermovehandler that reads the cursor offset and setstransform:rotateX(..)/rotateY(..)(reset onpointerleave); pair with a lifting shadow for depth. (A fixed-angle CSS-only version ongroup-hoverports even cleaner.) Great on feature/portfolio/product tiles. - Underline / arrow nudge on links/CTAs (
group-hover:translate-x-1on an arrow icon); lift on cards (hover:-translate-y-1 hover:shadow-xl transition). ⚠️ EVERY interactive element gets a hover state — a card/tile/image/button with none is a FAIL (anti-slop checklist).
C. Scroll choreography:
- Reveal on scroll — fade/slide-in as sections enter view (mockup: IntersectionObserver or GSAP; build:
data-anim="fade-up"+ containerdata-anim-stagger). NEVER leave content atopacity:0with no trigger in the preview (the empty-section bug) — set the hidden start-state via JS so it's visible if JS doesn't run. - Sticky / scrollytelling — a two-pane row where the media is
lg:sticky lg:top-24 self-startwhile the text column scrolls beside it (CSS-only). Premium for "how it works" / feature deep-dives. - Parallax depth — background layer drifts slower than foreground (GSAP
yon scroll, or a tastefulbg-fixedhero). Subtle only. - Count-up stats — numbers tick 0→target when the stats band reveals (small JS; pair with a big display-font number). Keep numbers organic (12+ years, 4,800+), not 99.99%.
D. Disclosure & layout rhythm:
- Accordion / tabs (FAQ, specs, "what's included") — CSS
<details>/:checkedor tiny JS; one open at a time. - Bento grid — an asymmetric tile mosaic (
grid-cols-12with mixedcol-span/row-span, one feature tile 2× the rest) instead of N equal cards (§2 layout variance). - Marquee — an infinite logo/keyword strip: a doubled track with
@keyframes marquee{to{transform:translateX(-50%)}}animation:marquee 30s linear infinite,hover:[animation-play-state:paused]. - Before/after slider, sticky CTA bar, scroll progress bar, magnetic/tilt buttons, cursor-spotlight cards — reach for these tastefully when the brand is bold; skip on a clean/minimal look.
Restraint applies to LAYER 2 ONLY (the signature scroll/entrance moments in §A/§C/§D): a clean minimal brand uses 1–2 quiet signatures, a bold/agency/launch brand earns 3–4 (carousel + sticky + count-up + flip). It does NOT cap LAYER 1 — the §B hover micro-interactions go on EVERY card/image/button/link no matter how quiet the brand (a luxe brand simply uses gentler ones: a soft lift + slow zoom rather than a flip). Motion must never gate content, fight contrast (§G.1), or cause horizontal page scroll (§2). Match the SIGNATURE pattern to the brand direction inferred in shop-design-taste §1.
3. The approval loop — FE-orchestrated, you draw ONE per run
After you emit the mockup the FE shows four choices; each re-runs you (or moves on):
- ✅ Approve → the FE freezes this HTML and kicks off the BUILD run with it as the reference. You're done.
- ✏️ Revise (the user describes a change) → you re-run with a "keep everything they didn't mention, change only X; previous HTML for reference" instruction → edit minimally, never rewrite from scratch (a rewrite drifts what they liked).
- 🔄 Another direction → you re-run with a "different direction, clean slate" instruction → a genuinely different palette + layout, not a variant.
- ⏭️ Skip, build directly → the gate is skipped; the normal build flow runs with no mockup reference.
Each run = ONE mockup + STOP. Never draw multiple variants at once.
3.5 Multi-page mode — one design language, many pages
For a whole-store build the platform may offer a page picker (a catalog of business-appropriate pages — about/contact/services/menu/lookbook…, plus the ecom template pages PDP/PLP/cart/search — recommended ones pre-ticked by the store's vertical, capped at ~6). The user's picked set becomes a SEQUENCE of draw runs, still one page per run:
- The HOMEPAGE draws first (exactly §2) and its approval LOCKS the design language: the
:roottokens, fonts, custom CSS, and the header/footer chrome. - Each remaining page is a separate run in CHROME-LOCKED mode: the platform SEEDS the approved homepage's
<head>+ header/footer server-side — you do NOT re-emit them and do NOT re-decide the direction/palette/fonts. Emit⟦MOCKUP⟧, then ONLY that page's own content regions as⟦SECTION <slug>⟧blocks (new slugs, no collisions with the homepage's), then⟦/MOCKUP⟧. Page-specific CSS goes in ONE<style>block right after⟦MOCKUP⟧(appended to the head — never redefine:rootor existing classes). Your creativity goes into THIS page's compositions WITHIN the locked language. - Page anatomy comes from the catalog (spliced into your instructions): a services page draws a statement block + services list + how-it-works + CTA; a listing/directory page draws a header band + filter rail + a records grid bound to the
contentDrop; contact/booking pages draw a real styled form. CMS pages port verbatim like the homepage. - The FE shows the drawn pages as preview TABS; each page revises individually (the revise seed is that page's full HTML). The final approve-all hands the whole set to the build: the homepage keeps its deterministic skeleton port; each sub-page's content regions ride the build prompt as its verbatim/restyle reference.
4. Handoff: VERBATIM HOLE-PUNCH — copy the markup, punch only the holes (do NOT re-design)
When the user approves, the platform splits the mockup into its data-mock-region blocks and injects each one as the literal source for one section (plus the head's :root palette). The build is a hole-punch port, not a re-creation — the agent does NOT re-author the look from memory:
- STEP 0 — lock the palette/fonts FIRST: read the mockup head's
:root(--accent/--ink/--paper/--cream/--mute/--line/--font-display/--font-sans) andset_global_settingswith those EXACT hex + fonts, sovar(--accent)/bg-accent/font-displayresolve to the mockup's design before any section. Skip it → base-theme default palette → a different look. - PORT each region's markup VERBATIM into a section — same Tailwind classes, same token colors, same spacing, same copy, same structure, character for character. Do NOT reword, restyle, re-lay-out, or "improve". Because the mockup is already in the §G.2 vocabulary (token colors, no arbitrary values), the markup is valid as-is and themelint passes — paste it, then change ONLY the holes.
- PUNCH only the dynamic holes (everything else stays verbatim): nav → the header/footer nav link blocks; any grid/list of real things → a
{% for %}loop over the LIVE object (thecontentDrop for a content type) reusing the mockup's per-card markup — ⚠️ create the data FIRST (content type + records) so the loop isn't empty; never keep the mockup's hard-coded placeholder cards (the empty-grid bug); inline<svg>/<i data-lucide>→{% render 'icon' %};<img>→ re-host (§C); any form → anis_formcontent type created first; wire interactions to realtheme.js(the mobile nav drawer +data-anim). Data-bound regions match the mockup's LAYOUT, not its placeholder content — that is NOT a §D mismatch. - Place each section atomically, top to bottom (
build_section→set_section_settingsimmediately, never batch — seeshop-build-section§3); set the templateorderto exactly the mockup's section ids and clear starter/default sections. If scope = full website, every OTHER page shares this same design language (chrome, palette, type, components). - Verify per §D against the mockup (the mockup IS the reference, so this build HAS a reference → screenshot-compare is REQUIRED): screenshot each built section (desktop + mobile, section-by-section) next to the region you ported, grade attribute-by-attribute (layout, colors vs tokens, fonts, spacing, copy), iterate ≤3 rounds until it matches. A mismatch = FAIL even if it "looks nice".
Anti-patterns (seen in real runs)
- Building before the user approves the mockup — violates §A.
- Inlining a CSS framework / hand-rolling a full stylesheet instead of the §G.2 utilities — the platform injects the store CSS; your job is the markup + the palette tokens, so the mockup matches the build.
- Non-token or arbitrary color classes (
bg-blue-600,bg-[#0a0a0a],w-[673px]) — they don't resolve and render unstyled; stay in the §G.2 vocabulary. - Drawing a multi-page board instead of the single target page/section.
- A page-redesign mockup with no header/footer chrome (looks like a bare body, not the real page).
- Narrating the HTML token-by-token in the chat instead of wrapping it in the markers.
- "Revising" by writing a brand-new mockup — loses what the user already approved.
- A mockup whose section order doesn't match what you then build.
- Verifying against "looks good" instead of against the approved mockup.
