1 ---
2 name: mockup-sandbox
3 description: "Use when the user wants to create, preview, or iterate on any web UI content on the canvas. This is the only way to show live rendered components on the board — all other canvas shapes are static. Activate for: designing or prototyping components on the canvas, comparing design variants side-by-side, showing responsive previews (mobile/tablet/desktop), previewing component states (loading/error/empty), comparing dark vs light mode, or any request that involves putting rendered web content on the board. Sets up a vite dev server with isolated component preview URLs for iframe embedding. For variant exploration (2+ design alternatives), includes subagent orchestration patterns for parallelizing work with DESIGN subagents. Never embed the main app URL directly — always use this skill. Read the entire skill carefully — it contains critical path conventions, image handling rules, and subagent delegation patterns that cause silent failures when skipped. For two specific workflows, also activate the companion skill: use mockup-extract when the user wants to pull an existing component from the main app onto the canvas, and mockup-graduate when the user approves a mockup and wants it integrated into the main app."
4 ---
5 # Mockup Sandbox Skill
6
7 The **`artifacts/mockup-sandbox/`** folder is an isolated frontend sandbox for rapid UI prototyping. Components are rendered in isolation via a vite dev server, and each component gets a `/preview/ComponentName` route that can be embedded as an iframe shape on the workspace canvas.
8
9 ## When to Use
10
11 Activate this skill when the user wants to:
12
13 - Show any web UI component on the canvas ("create a card on the canvas", "put a form on the board")
14 - Prototype or mockup a design ("design a landing page", "mockup a dashboard")
15 - Compare design variants side-by-side ("show me 3 options for the hero section")
16 - Preview responsive behavior ("how does this look on mobile?", "show me mobile and desktop")
17 - Preview component states ("show me loading, error, and empty states")
18 - Compare themes ("dark mode vs light mode", "what about a warmer color scheme?")
19 - Show a multi-page flow, **only when the user explicitly requests multiple pages** ("preview the signup flow: landing → signup → dashboard")
20 - Iterate on an existing component's design on the canvas (also activates mockup-extract)
21
22 **Rule of thumb:** if the result should be rendered HTML/CSS/React on the canvas, use this skill. If it's just shapes, text, or diagrams, the canvas skill handles it directly.
23
24 ## Extract First, Then Iterate
25
26 **When the user wants to redesign, improve, or create variants of something that already exists in their app, always start by extracting the real component code** using {{skill("mockup-extract")}}. Never rebuild an existing component from scratch by hand-coding approximations — you will get dimensions, colors, spacing, icon sizes, opacity values, and other details wrong. The real source code has the exact values; use them.
27
28 The correct workflow for redesigning existing UI:
29
30 1. **Extract** the real component into the mockup sandbox (preserves exact values)
31 2. **Label it "Current"** on the canvas as the baseline
32 3. **Duplicate and modify** to create design variants
33
34 The incorrect workflow (do not do this):
35
36 1. ~~Look at the app and hand-code a simplified version from memory~~
37 2. ~~Guess at dimensions, colors, spacing, and other values~~
38 3. ~~Iterate on an inaccurate approximation~~
39
40 This applies whenever the component being redesigned already exists as code in the main app — even if the user doesn't explicitly say "extract". If they say "redesign my sidebar", "improve the onboarding flow", or "show me alternatives for the settings page", the code already exists and must be extracted, not approximated.
41
42 ## Gathering Requirements
43
44 If the user's request is vague (e.g., "make some variants", "create a mockup"), ask them to clarify **what specific component or page** they want to prototype. Examples: "a pricing card", "a login form", "a dashboard header", "a product listing".
45
46 Once you know what to build, you can proceed and make reasonable decisions about layout, colors, and content.
47
48 ## How It Works
49
50 1. A vite dev server runs in a `artifacts/mockup-sandbox/` folder, separate from the main app
51 2. A custom Vite plugin (`mockupPreviewPlugin`) uses `fast-glob` and file watching to discover components in `artifacts/mockup-sandbox/src/components/mockups/`
52 3. The plugin writes a generated component registry at `src/.generated/mockup-components.ts`
53 4. Each component is served at `/preview/{folder}/{ComponentName}` as a standalone page
54 5. If a relevant preview request returns 404 before file watching settles, the dev server rescans automatically and the next iframe retry picks up the update
55 6. Components use Tailwind and shadcn/ui -- changes hot-reload instantly
56
57 ## Setup
58
59 ### Step 1: Set up the mockup sandbox
60
61 Create the mockup sandbox using `createArtifact` (see {{skill("artifacts")}} for full details):
62
63 ```javascript
64 const result = await createArtifact({
65 artifactType: "mockup-sandbox",
66 slug: "mockup-sandbox",
67 previewPath: "/__mockup/",
68 title: "Mockup Sandbox"
69 });
70 ```
71
72 Then start its dev server **before** creating any components or placing iframes on the canvas:
73
74 ```javascript
75 await restartWorkflow({ workflowName: "artifacts/mockup-sandbox: Component Preview Server" });
76 ```
77
78 The dev server must be running first so that component files are picked up by the Vite plugin and preview URLs resolve correctly. Preview URLs use path-based routing: `https://${REPLIT_DOMAINS}/__mockup/preview/{folder}/{ComponentName}` — no port number needed.
79
80 ### Step 2: Create mockup components
81
82 **Verify the component directory first.** Before creating any files, list `artifacts/mockup-sandbox/` to confirm that `src/components/mockups/` exists. Use the verified path for all component creation and subagent delegation.
83
84 Create components in `artifacts/mockup-sandbox/src/components/mockups/`:
85
86 ```tsx
87 // artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Minimal.tsx
88 export function Minimal() {
89 return (
90 <div className="min-h-screen bg-background p-8">
91 <h1 className="text-2xl font-bold text-foreground">Basic Plan - $9/mo</h1>
92 </div>
93 );
94 }
95 ```
96
97 ### Step 3: Embed on the canvas
98
99 Create `iframe` shapes on the workspace canvas.
100 Preview URLs follow the pattern `https://${REPLIT_DOMAINS}/__mockup/preview/{folder}/{ComponentName}` — no port number.
101
102 **Reserved design frames.** A reserved design frame is a client-placed Building iframe with a preassigned `shape_id` that exists before your agent run starts. Your job is to update that exact iframe; do not create a replacement shape for it. If the `pending_canvas_frames` block for the current user turn lists frames, use those exact `shape_id` values for the first N mockup iframes you produce. Ignore `pending_canvas_frames` blocks attached to earlier turns. For additional variants beyond the reserved count, use the normal create flow described below. The `updates` payload for iframe updates uses flat top-level fields because the canvas callback validates `updates` directly.
103
104 Example -- a pricing card is a "Card / Panel", so use a snug iframe (see [Iframe Sizing Guide](#iframe-sizing-guide)):
105
106 ```json
107 {
108 "type": "create",
109 "shapeId": "pricing-minimal",
110 "shape": {
111 "type": "iframe",
112 "x": 100, "y": 100, "w": 500, "h": 450,
113 "url": "https://<your-domain>.replit.dev/__mockup/preview/pricing-cards/Minimal",
114 "componentPath": "artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Minimal.tsx",
115 "componentName": "Minimal Pricing Card"
116 }
117 }
118 ```
119 ### Step 4: Layout and focus
120
121 Before embedding iframes, call `getCanvasState()` to see what already exists on the board and find empty space. Then place your iframes in an unoccupied region.
122
123 If an iframe is created while the workflow is still booting, rely on the canvas host's iframe retry behavior plus the dev server's automatic 404 rescan to recover. Do not ask the user to refresh the whole board.
124
125 **Variant grid layout.** Arrange multiple variants in a horizontal row. Place them at approximate positions, then clean up the layout with `align` + `distribute` in the same `applyCanvasActions` batch -- do not hand-compute 50px gutters across 3+ iframes. See the canvas skill's "Align and Distribute Shapes" section for recipes. Do not add text labels above iframes -- the iframe title bar already shows the `componentName`. Use descriptive `componentName` values instead (e.g. "Minimal Pricing Card", "Bold Pricing Card").
126
127 **Multi-viewport layouts.** When showing the same component at different screen sizes, place them in a row using the viewport presets (Mobile: 390x844, Tablet: 768x1024, Desktop: 1280x720). Use `align` (top) + `distribute` (horizontal) in the same batch to line them up instead of hand-computing 50px gutters.
128
129 **Empty-canvas exception.** If `getCanvasState` shows the canvas is empty — `focusedShapes`, `blurryShapes`, **and** `peripheralClusters` all empty (the `summary` count alone misses off-screen content) — follow the placement with one `focusCanvasShapes` call on the placeholder IDs in the same execution. Otherwise default rule (`presentArtifact` only). For 3+ placeholders, layer on `align`/`distribute` per the "Variant grid layout" paragraph above; for 1-2 placeholders skip them — `align` requires 2+ shapes and `distribute` requires 3+, so an unconditional batch fails before any placeholder is shown.
130
131 ```javascript
132 const ids = ["coffee-artisan", "coffee-modern", "coffee-warm"];
133 await applyCanvasActions({ actions: ids.map((id, i) => ({
134 type: "create",
135 shapeId: id,
136 shape: { type: "iframe", x: i * 1380, y: 0, w: 1280, h: 900,
137 state: "building", componentName: `Variant ${i + 1}` },
138 })) });
139 await focusCanvasShapes({ shapeIds: ids, animateMs: 500 });
140 ```
141
142 **Clean up the layout before presenting.** Before the final `presentArtifact` call (Step 5), align and distribute any row or column of 3+ iframes you placed. This produces a pixel-perfect layout that hand-computed coordinates usually miss by a few units, and it's what the user first sees when they focus on your work. For a 2-shape pair (e.g. before/after), align the shared edge but set the gap on create -- `distribute` rejects 2 shapes.
143
144 **Do not call `suggestDeploy()`.** The mockup sandbox is a local prototyping tool and is not meant to be deployed — if the user asks to publish or deploy canvas/mockup content, integrate/graduate it into a real app artifact first.
145
146 **Never share dev domain URLs in chat.** Dev URLs (`*.replit.dev`, `$REPLIT_DEV_DOMAIN`) are internal — use them only in tool calls (iframe shapes, subagent tasks), never in user-facing messages.
147
148 # Step 5: Verification and Presentation
149
150 **Check system logs.** Always check the system logs to ensure no iframe previews are broken, since broken iframes cause an error overlay across the canvas. If you see iframe-related errors, fix them before proceeding and restart the workflow.
151
152 **CRITICAL — Always present after canvas work.** After all mockups are embedded, you MUST call `presentArtifact` with the shape IDs. This is how the user navigates to your work — without it, they cannot find the shapes you placed. Never skip this step. Never ask the user if they want to see the shapes — just present.
153
154 ```javascript
155 // ALWAYS call this after creating or updating canvas shapes.
156 await presentArtifact({ artifactId, shapeIds: ["shape-id-1", "shape-id-2"] });
157 ```
158
159 ## Architecture
160
161 ```text
162 artifacts/mockup-sandbox/ # Isolated from main app
163 ├── package.json # Dependencies (React, Tailwind, shadcn/ui, cartographer)
164 ├── vite.config.ts # Vite config
165 ├── mockupPreviewPlugin.ts # Vite plugin for component discovery + automatic 404 rescan
166 ├── tsconfig.json # TypeScript config for tsgo type checking
167 ├── components.json # shadcn/ui config
168 ├── .npmrc
169 ├── index.html
170 └── src/
171 ├── main.tsx # Entry point
172 ├── App.tsx # Landing page
173 ├── index.css # Tailwind v4 styles
174 ├── .generated/
175 │ └── mockup-components.ts # Auto-generated component registry
176 ├── components/
177 │ ├── ui/ # 50+ shadcn/ui components (pre-installed)
178 │ └── mockups/ # YOUR MOCKUP COMPONENTS GO HERE
179 ├── lib/
180 │ └── utils.ts
181 └── hooks/
182 ```
183
184 ## Folder Structure
185
186 The folder structure in `mockups/` automatically organizes components:
187
188 ```text
189 components/mockups/
190 ├── pricing-cards/ # Single-component variants
191 │ ├── _group.css # Group-level tokens + fonts (optional)
192 │ ├── Minimal.tsx # imports './_group.css'
193 │ ├── Bold.tsx # imports './_group.css'
194 │ └── Gradient.tsx # imports './_group.css'
195 ├── crm-dashboard/ # Multi-page project (only when user explicitly requests multiple pages)
196 │ ├── _shared/ # Shared layout (not preview targets)
197 │ │ ├── AppLayout.tsx
198 │ │ ├── Navbar.tsx
199 │ │ └── Sidebar.tsx
200 │ ├── _group.css
201 │ ├── Dashboard.tsx
202 │ ├── UserList.tsx
203 │ └── Settings.tsx
204 ├── login-forms/
205 │ ├── Simple.tsx
206 │ └── Dark.tsx
207 └── QuickIdea.tsx # Ungrouped (loose files)
208 ```
209
210 Files prefixed with `_` are not preview targets by convention. `_shared/` holds helper components imported by sibling page files. `_group.css` holds group-level CSS overrides — tokens, font `@import`s, `@font-face` blocks — that every component in the group explicitly imports (see [Fonts](#fonts)).
211
212 ## Working with Assets
213
214 ### Icons
215
216 `lucide-react` is pre-installed with 1000+ icons:
217
218 ```tsx
219 import { ShoppingCart, Star, ArrowRight } from "lucide-react";
220
221 <ShoppingCart className="w-6 h-6 text-gray-600" />
222 ```
223
224 ### Images
225
226 Two approaches -- **do not mix them**:
227
228 #### Option 1: Public folder (URL reference)
229
230 Place images in `artifacts/mockup-sandbox/public/images/` and reference by URL path:
231
232 ```tsx
233 <img src="/__mockup/images/hero.png" alt="Hero" />
234 ```
235
236 #### Option 2: Import via `@/assets/` (bundled by Vite)
237
238 Place images in `artifacts/mockup-sandbox/src/assets/` and import them:
239
240 ```tsx
241 import heroImg from "@/assets/hero.png";
242
243 <img src={heroImg} alt="Hero" />
244 ```
245
246 The `@` alias maps to `artifacts/mockup-sandbox/src/`, so `@/assets/hero.png` resolves to `artifacts/mockup-sandbox/src/assets/hero.png`.
247
248 **Important — pick one approach per image and do not cross them:**
249
250 - Files in `src/assets/` **must** be imported (`import img from "@/assets/hero.png"`). Referencing them by URL path (`<img src="/src/assets/hero.png" />`) will 404 — Vite does not serve `src/` files as static assets.
251 - Files in `public/images/` are served as-is at `/__mockup/images/…`. Do not import them.
252
253 For mockups, **prefer Option 1 (public folder)** — it is simpler and avoids the most common mistake.
254
255 To generate images for mockups, use the `media-generation` skill:
256
257 ```javascript
258 await generateImage({
259 images: [{
260 prompt: "Modern product photo of wireless headphones",
261 outputPath: "artifacts/mockup-sandbox/public/images/headphones.png",
262 aspectRatio: "1:1"
263 }]
264 });
265 ```
266
267 Then reference: `<img src="/__mockup/images/headphones.png" />`.
268
269 **Path warning:** The `outputPath` must start with `artifacts/mockup-sandbox/public/` -- NOT just `public/`. The main app's public folder is not served by the mockup dev server. Using `outputPath: "public/images/hero.png"` (without the `artifacts/mockup-sandbox/` prefix) will 404 in mockup iframes.
270
271 ### Fonts
272
273 **Bundled fonts.** `index.html` preloads 25+ Google Font families. Use them directly in any component:
274
275 ```tsx
276 <h1 className="font-['Playfair_Display']">Heading</h1>
277 ```
278
279 **Custom fonts.** For fonts outside the bundled set, add a non-blocking `<link>` tag to `artifacts/mockup-sandbox/index.html`. Do not use CSS `@import url(...)` — it is render-blocking and will delay all Tailwind styles until the font finishes downloading.
280
281 ```html
282 <!-- in artifacts/mockup-sandbox/index.html <head> -->
283 <link rel="stylesheet" media="print" onload="this.media='all'"
284 href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;600&display=swap">
285 ```
286
287 Then use it in components:
288
289 ```tsx
290 <h1 className="font-['Cormorant_Garamond'] text-6xl">Heading</h1>
291 ```
292
293 Or override the default font via a CSS variable in a component's own CSS file:
294
295 ```css
296 /* editorial-hero/tokens.css */
297 :root { --font-serif: 'Cormorant Garamond', serif; }
298 ```
299
300 Missing fonts fail silently — no console error, no build failure, just a fallback font with the wrong weight and width. Verify typography visually.
301
302 ## Adding Packages
303
304 The `packager_install_tool` only works for the main project. To add packages to the mockup sandbox:
305
306 1. Edit `artifacts/mockup-sandbox/package.json` directly and add the dependency
307 2. Run `npm install` from the `artifacts/mockup-sandbox/` directory
308 3. Restart the "artifacts/mockup-sandbox: Component Preview Server" workflow to pick up the change
309
310 ## shadcn/ui Components
311
312 All shadcn/ui components are pre-installed and ready to use:
313
314 ```tsx
315 import { Button } from "@/components/ui/button";
316 import { Card, CardContent } from "@/components/ui/card";
317 import { Input } from "@/components/ui/input";
318 ```
319
320 **Available components:** accordion, alert, alert-dialog, aspect-ratio, avatar, badge, breadcrumb, button, button-group, calendar, card, carousel, chart, checkbox, collapsible, command, context-menu, dialog, drawer, dropdown-menu, empty, field, form, hover-card, input, input-group, input-otp, item, kbd, label, menubar, navigation-menu, pagination, popover, progress, radio-group, resizable, scroll-area, select, separator, sheet, sidebar, skeleton, slider, sonner, spinner, switch, table, tabs, textarea, toast, toaster, toggle, toggle-group, tooltip
321
322 ## Component Best Practices
323
324 - **One preview entry point per file** -- each file should export one top-level component that the preview route resolves as the preview target. But define as many local helper components inside the file as you need -- a `Dashboard.tsx` with internal `StatsCard`, `ActivityFeed`, and `QuickActions` components all composed into one exported `Dashboard` function is ideal. This keeps mockups self-contained and readable without file sprawl.
325 - **Match the CSS wrapper to the content type** -- see the [Iframe Sizing Guide](#iframe-sizing-guide) for how to pair component CSS with iframe dimensions.
326 - **Use design tokens for the baseline** -- When recreating the app's existing look or building the "Current" version, use semantic color classes like `bg-background`, `text-foreground`, `text-muted-foreground` so the mockup matches the main app's theme. When creating design variations, use whatever colors express the variant's visual direction -- hardcoded colors like `bg-indigo-950`, `text-amber-200` are expected and necessary. That's the whole point of exploring alternatives.
327 - **Use realistic data** -- show how the component looks with real content, not lorem ipsum.
328 - **Name clearly** -- use descriptive names that communicate the variant's design hypothesis (e.g., `ComparisonTable.tsx`, `ProgressiveDisclosure.tsx`, `FeatureLed.tsx`). For simple aesthetic variants, names like `Minimal.tsx` or `DashboardDark.tsx` are fine.
329 - **Include states** -- create separate mockup files for loading, empty, and error states.
330
331 ## Design Variation Guidelines
332
333 When the user asks for variations, alternatives, "show me options," or any request that implies divergent exploration (e.g., "try 3 different approaches," "what else could this be?"), read {{skill("design-exploration")}} first. It provides a structured comprehension → brief → delegation workflow that produces meaningfully diverse output instead of superficial reskins.
334
335 When asked to generate variations, your first task is to **understand the design before changing it**.
336
337 ### Step 1: Analyze the component
338
339 Read the source code and determine:
340
341 - **Purpose:** What user need does this component serve? What task does it support?
342 - **Constraints:** What must stay fixed? (data shape, required actions, accessibility, brand)
343 - **Degrees of freedom:** What could meaningfully change without breaking the component's purpose?
344
345 ### Step 2: Select variation axes based on the analysis
346
347 Choose 2-3 axes that would give the user the most insight into their solution space. Axes ordered from most impactful to least:
348
349 1. **Structural:** Different layouts, information hierarchies, component compositions (e.g., pricing as cards vs. comparison table vs. progressive disclosure)
350 2. **Content strategy:** What's foregrounded vs. backgrounded, information density, copy approach (e.g., feature-led vs. social-proof-led vs. price-led)
351 3. **Interaction model:** Different interaction patterns, progressive disclosure, state handling (e.g., modal vs. inline expansion vs. dedicated page)
352 4. **Conceptual:** The underlying metaphor or mental model (e.g., dashboard-as-cockpit vs. dashboard-as-feed vs. dashboard-as-scorecard)
353 5. **Visual treatment:** Typography, color, spacing, depth, mood (e.g., minimal vs. bold vs. editorial)
354
355 Default to higher-impact axes unless the user specifically requests aesthetic exploration (e.g., "try different color schemes" or "explore visual styles"). For visually-driven or structurally simple components (cards, heroes, buttons), aesthetic variation is a strong first-round choice alongside structural variation.
356
357 ### Step 3: Generate variations as distinct design hypotheses
358
359 Each variation should represent a meaningfully different answer to the question "how should this component work?" Variations should be diverse enough that the user can identify emerging preferences and narrow their direction.
360
361 ### Process notes
362
363 - Functionality and data shape should stay consistent across variants (same API contract)
364 - Layout, hierarchy, content emphasis, and visual treatment ARE all fair game
365 - Name variants descriptively by their design hypothesis (e.g., `ComparisonTable.tsx`, `ProgressiveDisclosure.tsx`) not just their aesthetic (e.g., `Bold.tsx`)
366 - Create each variant as an independent component
367
368 ## Subagent Orchestration
369
370 For design variation tasks (2+ alternatives of the same component or page), use DESIGN subagents to parallelize work. The parent agent orchestrates setup, building placeholders, and canvas layout; subagents handle individual variant creation and mark iframes live when done. Multi-page fan-out (building separate pages in parallel) should only be used when the user explicitly requests multiple pages.
371
372 ### Building placeholders
373
374 Every mockup request -- whether handled directly or via subagents -- should show immediate visual feedback on the canvas using the iframe `state` field. When creating a new iframe for a component that doesn't exist yet, set `state: "building"`. The canvas renders a native building indicator -- no URL is needed at this point.
375
376 **Flow for new components (0 → 1):**
377
378 1. Read the canvas state to find empty space
379 2. Immediately place iframe(s) with `state: "building"` and `componentName` at the expected sizes
380 - **Reserved frames:** if the `pending_canvas_frames` block for the current user turn is present, use those exact `shape_id`s with `type: "update"` actions instead of creating placeholders for the first N variants.
381 - **Empty-canvas only:** if the canvas was empty before this batch, follow the placement with a `focusCanvasShapes` on the new placeholder IDs in the same execution. See [Step 4 → Empty-canvas exception](#step-4-layout-and-focus) for the precise emptiness check.
382 3. Proceed with component development.
383 - For direct builds, set the iframe `state: "live"` once the component is ready, then screenshot the component to confirm it renders.
384 - For subagent builds, ask the subagent to set the iframe `state: "live"` AND verify with a screenshot before reporting — broken iframes are invisible to the user until someone checks. The subagent's prompt has the screenshot tool mechanics; the parent only needs to include a verification instruction in the task (e.g. "Screenshot the preview to verify it renders before reporting").
385 4. Check the system logs for iframe-related issues, fix any problems, and restart the workflow once all components are created.
386
387 **Flow for modifying existing components:**
388
389 1. Set `state: "modifying"` on the iframe before editing
390 2. Edit the component file in place
391 3. Set `state: "live"` on the iframe when done
392
393 **Building iframe example:**
394
395 ```json
396 {
397 "type": "create",
398 "shapeId": "pricing-bold",
399 "shape": {
400 "type": "iframe",
401 "x": 600, "y": 100, "w": 500, "h": 450,
402 "state": "building",
403 "componentName": "Bold Pricing Card"
404 }
405 }
406 ```
407
408 Then once the component is built, set the URL and mark it live:
409
410 ```json
411 {
412 "type": "update",
413 "shapeId": "pricing-bold",
414 "updates": {
415 "shapeType": "iframe",
416 "url": "https://<dev-url>/__mockup/preview/pricing-cards/Bold",
417 "componentPath": "artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Bold.tsx",
418 "state": "live"
419 }
420 }
421 ```
422
423 **Reserved Building iframe example:**
424
425 ```json
426 {
427 "type": "update",
428 "shapeId": "shape:<reserved-id>",
429 "updates": {
430 "shapeType": "iframe",
431 "componentName": "Bold Pricing Card"
432 }
433 }
434 ```
435
436 Then once the component is built, set the URL and mark it live. Keep the reserved `shapeId`:
437
438 ```json
439 {
440 "type": "update",
441 "shapeId": "shape:<reserved-id>",
442 "updates": {
443 "shapeType": "iframe",
444 "url": "https://<dev-url>/__mockup/preview/pricing-cards/Bold",
445 "componentPath": "artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Bold.tsx",
446 "componentName": "Bold Pricing Card",
447 "state": "live"
448 }
449 }
450 ```
451
452 ### When to use subagents
453
454 Use subagents when the task involves **2+ design variants** of the same component or page. Also use a single DESIGN subagent for any single-page app or full-page mockup (landing pages, homepages, portfolios, etc.) — the DESIGN subagent produces higher-quality visual output, unless the user asks you to handle it yourself. For a single small component (card, button, form) or a modification to an existing mockup, do the work directly.
455
456 **Do not create multiple pages unless the user explicitly asks.** When the user says "design a dashboard" or "build a CRM", build it as a single page — do not proactively split it into Dashboard, UserList, Settings, etc. Only fan out into multiple page files when the user specifically requests separate pages (e.g., "design a CRM with dashboard, users, and settings pages").
457
458 **Single-page apps are single components.** When the user asks for a landing page, homepage, or any single-page app, create it as **one component file** — do not split sections (hero, features, pricing, footer, etc.) into separate component files or separate screens. A landing page is one scrollable page rendered in one iframe, unless the user explicitly asks for separate screens or sections as independent components. For landing pages and similar content-rich pages, prioritize generating images (hero visuals, product shots, background art, illustrations) — placeholder boxes and generic stock imagery make landing pages look unfinished. Use `generateImage` to create custom visuals that match the page's mood and brand direction.
459
460 **Which specialization?** Use **DESIGN** subagents (`specialization: "DESIGN"`) for all mockup creation work. DESIGN subagents are tuned for creative visual output — they produce better, more diverse designs when given a brief mood/direction rather than prescriptive specs. Do not use GENERAL subagents for mockup component creation; they lack the design sensibility and carry unnecessary overhead (task lists, context management).
461
462 **For extract and graduate workflows, use GENERAL subagents** if parallelization is needed. These are engineering tasks (import graph tracing, production code transformation) — DESIGN subagents lack the codebase navigation skills they require. See the companion skills for details.
463
464 | Scenario | Subagents? | Specialization | Pattern |
465 | --- | --- | --- | --- |
466 | "Design a pricing card" | No | — | Direct |
467 | "Design a landing page" | Yes (1) | DESIGN | Single DESIGN subagent (one file) |
468 | "Design a single-page app" | Yes (1) | DESIGN | Single DESIGN subagent (one file) |
469 | "Make the header bigger" | No | — | In-place modification |
470 | "Extract my existing component" | If parallelizing | GENERAL | Direct or fan-out (mockup-extract) |
471 | "Graduate / apply this mockup to my app" | If parallelizing | GENERAL | Direct or fan-out (mockup-graduate) |
472 | "Redesign my navbar with 2 options" | Yes | DESIGN | Variants fan-out |
473 | "Show me 3 options for the hero" | Yes | DESIGN | Variants fan-out |
474
475 ### Pattern: Direct (no subagent)
476
477 Use for single small components (cards, buttons, forms) or modifications to existing mockups. For single full-page mockups (landing pages, homepages, single-page apps), delegate to a single DESIGN subagent instead — unless the user asks otherwise. Follow the standard setup steps (Steps 3-6), with building placeholders for instant feedback.
478
479 ```text
480 Parent: Place iframe(s) with state: "building" on canvas
481 → Create component file
482 → Restart workflow
483 → Update iframe with URL + state: "live"
484 → presentArtifact with shapeIds
485 ```
486
487 For modifications to existing mockups, set `state: "modifying"` on the iframe, edit the file in place, then set `state: "live"` when done. **Do not** create a new file for modifications. If the user wants to preserve the old version for comparison, *then* duplicate the file into a new variant first.
488
489 ### Pattern A: Design variants (fan-out)
490
491 Use when the user wants multiple visual options for the same component or page.
492
493 ```text
494 Parent: Place iframes with state: "building" on canvas (one per variant, in a row)
495 Parent: Establish requirements, seed each variant direction
496 ├──→ DESIGN subagent: "Minimal" variant
497 ├──→ DESIGN subagent: "Bold" variant
498 └──→ DESIGN subagent: "Gradient" variant
499 Parent: Check system logs, fix issues and restart workflow once all subagents complete
500 ```
501
502 **Parent responsibilities:**
503
504 1. Run the design-exploration comprehension steps (analyze component, identify constraints, select variation axes) and compose a structured design brief
505 2. Create the folder (e.g., `mockups/pricing-cards/`)
506 3. Place iframes with `state: "building"` in a horizontal row on the canvas, one per variant, with stable shape IDs.
507 - **Reserved frames:** assign the provided `shape_id`s to specific variants and do not create replacements. Keep the reserved frames at their client-provided positions and sizes; do not move, resize, align, or distribute them.
508 - **Additional variants:** for variants beyond the reserved count, create new Building iframes. For 3+ newly created frames, place them at rough positions and use `align` (top) + `distribute` (horizontal) in the same batch rather than hand-computing gutters.
509 4. Seed each subagent with: the design brief, target file path, shape ID to update, dev URL, and the specific design hypothesis for this variant. If the shape ID came from the `pending_canvas_frames` block for the current user turn, explicitly tell the subagent to update that exact ID rather than create a replacement. **Tell each subagent not to edit `index.css`** — multiple subagents run in parallel and will overwrite each other's changes.
510 5. After all subagents complete: restart workflow, call `presentArtifact` with all shape IDs.
511
512 **Subagent task format:**
513
514 ```text
515 Create a mockup component at artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Bold.tsx
516
517 ## Design Brief
518
519 Component analysis: A pricing card that presents a subscription tier to help users
520 compare plans and choose one. Displays plan name, price, feature list, and a CTA.
521
522 Fixed constraints: Must include plan name, monthly price, feature list, and CTA button.
523 Data shape stays consistent across variants.
524
525 Variation axes:
526 - Content hierarchy (what leads the user's eye)
527 - Visual treatment (mood and material quality)
528
529 ## This Variant's Hypothesis
530
531 Name: Bold
532 Hypothesis: High-contrast, large typography, and strong color blocking to create urgency
533 and confidence. Foregrounds the price as the dominant visual element with features
534 as supporting evidence.
535
536 Each variation should be a distinct design hypothesis. Do not produce variations that
537 differ only in color, font, or spacing unless the brief specifically calls for
538 aesthetic exploration.
539
540 The exported function name must match the filename: export function Bold().
541 Use Tailwind + shadcn/ui.
542
543 ## CSS rules
544 Do NOT edit index.css — other subagents are running in parallel and will overwrite
545 your changes. All styles must be self-contained within your component:
546 - Use Tailwind utility classes and inline styles for all visual styling
547 - For custom fonts, use Google Fonts <link> tags in a wrapper <div> or inline @import
548 - If you need CSS custom properties or @keyframes, create a _group.css in the
549 component folder and import it in your .tsx file
550
551 When done, update the canvas iframe to show the real preview:
552 Shape ID: pricing-bold
553 If this Shape ID came from the pending_canvas_frames block for the current user turn, update exactly this ID; do not create a replacement.
554 URL: https://<dev-url>/__mockup/preview/pricing-cards/Bold
555 componentPath: artifacts/mockup-sandbox/src/components/mockups/pricing-cards/Bold.tsx
556 state: "live"
557 ```
558
559 **Parent responsibilities:**
560
561 1. Place iframes with `state: "building"` on the canvas with stable shape IDs. For reserved frames, assign the provided `shape_id`s to specific pages and do not create replacements.
562 2. Create the project folder and `_shared/` subfolder
563 3. Build shared layout components (`AppLayout.tsx` with a content slot, `Navbar.tsx`, `Sidebar.tsx`, etc.)
564 4. Fan out DESIGN subagents for each page, passing `_shared/` file paths, shape ID, and dev URL. If the shape ID came from the `pending_canvas_frames` block for the current user turn, explicitly tell the subagent to update that exact ID rather than create a replacement. **Tell each subagent not to edit `index.css`** — multiple subagents run in parallel and will overwrite each other's changes.
565 5. After all subagents complete: restart workflow, call `presentArtifact` with all shape IDs.
566
567 **Multi-page subagent task format (only when user explicitly requests multiple pages):**
568
569 ```text
570 Create a mockup page at artifacts/mockup-sandbox/src/components/mockups/crm-dashboard/Dashboard.tsx
571
572 This is the main dashboard page of a CRM application. Import the shared layout:
573 import { AppLayout } from "./_shared/AppLayout";
574
575 Wrap your page content inside <AppLayout>. The layout already renders the nav and sidebar --
576 you only need to build the page content area.
577
578 User constraints: Show key metrics (revenue, users, conversion), recent activity feed,
579 and a quick-actions panel.
580
581 The exported function name must match the filename: export function Dashboard().
582 Use Tailwind + shadcn/ui.
583
584 ## CSS rules
585 Do NOT edit index.css — other subagents are running in parallel and will overwrite
586 your changes. All styles must be self-contained within your component:
587 - Use Tailwind utility classes and inline styles for all visual styling
588 - For custom fonts, use Google Fonts <link> tags in a wrapper <div> or inline @import
589 - If you need CSS custom properties or @keyframes, create a _group.css in the
590 component folder and import it in your .tsx file
591
592 When done, update the canvas iframe to show the real preview:
593 Shape ID: crm-dashboard
594 If this Shape ID came from the pending_canvas_frames block for the current user turn, update exactly this ID; do not create a replacement.
595 URL: https://<dev-url>/__mockup/preview/crm-dashboard/Dashboard
596 componentPath: artifacts/mockup-sandbox/src/components/mockups/crm-dashboard/Dashboard.tsx
597 state: "live"
598 ```
599
600 ### Pattern C: Multi-page with multiple variant directions
601
602 Use when the user wants to compare multiple complete design directions for a multi-page application ("show me 2 different takes on this CRM").
603
604 Each variant gets its own folder with its own `_shared/` components. One DESIGN subagent builds an entire variant (shared components + all pages), giving it full creative control over the design direction.
605
606 ```text
607 Parent: Place iframes with state: "building" in a variant × page grid on canvas
608 Parent: Define page list, seed each variant direction
609 ├──→ DESIGN subagent: Build entire crm-minimal/
610 ├──→ DESIGN subagent: Build entire crm-bold/
611 └──→ DESIGN subagent: Build entire crm-playful/
612 Parent: Checked the system logs and restart the workflow once all components are created
613
614 ```
615
616 ```text
617 mockups/
618 ├── crm-minimal/
619 │ ├── _shared/
620 │ │ ├── AppLayout.tsx
621 │ │ └── Navbar.tsx
622 │ ├── Dashboard.tsx
623 │ ├── UserList.tsx
624 │ └── Settings.tsx
625 ├── crm-bold/
626 │ ├── _shared/
627 │ │ ├── AppLayout.tsx
628 │ │ └── TopNav.tsx
629 │ ├── Dashboard.tsx
630 │ ├── UserList.tsx
631 │ └── Settings.tsx
632 ```
633
634 **Canvas layout for variant × page grids:**
635
636 Arrange as a matrix with text label shapes for headers. Variants as rows, pages as columns:
637
638 ```text
639 Dashboard UserList Settings
640 Minimal [iframe] [iframe] [iframe]
641 Bold [iframe] [iframe] [iframe]
642 Playful [iframe] [iframe] [iframe]
643 ```
644
645 Use `geo` text shapes for row and column headers. Space iframes with ~50px gutters.
646
647 **Subagent task format:**
648
649 ```text
650 Build a complete multi-page mockup variant at artifacts/mockup-sandbox/src/components/mockups/crm-minimal/
651
652 Direction: Minimal and restrained -- lots of whitespace, muted colors, thin borders, subtle typography.
653
654 Pages to create: Dashboard.tsx, UserList.tsx, Settings.tsx
655
656 First create a _shared/ subfolder with shared layout components (AppLayout, Navbar, Sidebar or
657 similar). Then create each page file importing from _shared/ for visual consistency.
658
659 Each exported function name must match its filename. Use Tailwind + shadcn/ui.
660
661 When done, update the canvas iframes to show real previews (set state: "live" on each):
662 Shape ID: crm-minimal-dashboard → URL: https://<dev-url>/__mockup/preview/crm-minimal/Dashboard
663 Shape ID: crm-minimal-userlist → URL: https://<dev-url>/__mockup/preview/crm-minimal/UserList
664 Shape ID: crm-minimal-settings → URL: https://<dev-url>/__mockup/preview/crm-minimal/Settings
665 If any Shape ID came from the pending_canvas_frames block for the current user turn, update exactly that ID; do not create a replacement.
666 ```
667
668 **Important:** The multi-page pattern above should only be used when the user explicitly requests separate pages. If the user says "design a CRM" or "design a dashboard" without specifying separate pages, build everything as a single page component.
669
670 ### General orchestration rules
671
672 1. **Always place building iframes first.** Before starting any component work, create iframes with `state: "building"` at the expected positions and sizes. No URL is needed yet -- the canvas shows a native building indicator. Skip this only for in-place modifications (set `state: "modifying"` on the existing iframe instead).
673
674 2. **Subagents mark their own iframes live.** The parent places building iframes with stable shape IDs, then tells each subagent which shape ID to update and the dev URL to use. Subagents set the real preview URL and `state: "live"` when their component is ready. This gives progressive reveal -- iframes light up as subagents finish, rather than all at once.
675
676 3. **Parent restarts the workflow once after all subagents complete** -- not once per subagent. A single restart discovers all new components and the iframes load the real content.
677
678 4. **Verify paths before delegating.** Before passing file paths to subagents, list `artifacts/mockup-sandbox/` to confirm `src/components/mockups/` exists and pass the verified full path. Getting this wrong means files land in a directory the Vite plugin never scans.
679
680 5. **Tell subagents the image path convention.** Always include this in the subagent task: "Place all images in `artifacts/mockup-sandbox/public/images/` and reference them as `<img src="/__mockup/images/filename.jpg" />`. Do NOT put images in `src/assets/` and reference them by URL path — Vite does not serve `src/` as static assets and they will 404. For `generateImage`, use `outputPath` starting with `artifacts/mockup-sandbox/public/images/`."
681
682 6. **Give subagents creative freedom.** Subagents produce better designs when given high-level requirements, not prescriptive specs. Pass:
683 - Target file path and exported function name
684 - Shape ID + dev URL for iframe update
685 - Shared file paths to import (for multi-page projects)
686 - Functional requirements only (what the page must contain, not how it should look)
687 - A brief mood/direction seed (1-2 words: "minimal", "bold and dark", "warm editorial")
688
689 Do NOT pass specific color values, font choices, spacing values, detailed layout instructions, CSS class names, or references to other variants. The subagent has its own design sensibility -- constraining it to exact specs produces generic results and defeats the purpose of generating diverse alternatives.
690
691 **Exception:** For multi-page apps (only when the user explicitly requests multiple pages), the parent defines the design system in `_shared/` and the subagent works within it. Creative freedom applies to page content and layout, not the shared chrome.
692
693 7. **Match specialization to the task type.** Use `DESIGN` for creative mockup creation (building new components, designing variants) — it's tuned for visual output and produces better, more diverse designs. Use `GENERAL` for engineering tasks (extract, graduate) — it's built for codebase navigation, dependency tracing, and architecture-aware transformations. Never use DESIGN for extract/graduate or GENERAL for mockup creation.
694
695 ## Related Skills
696
697 - **{{skill("mockup-extract")}}** -- Pull an existing component from the main app into the sandbox for redesign. Use when the user wants to iterate on something that already exists.
698 - **{{skill("mockup-graduate")}}** -- Move an approved mockup into the main app. Use when the user picks a variant and wants it integrated.
699
700 ## Iframe Sizing Guide
701
702 Size the iframe to fit the content -- a landing page needs a full desktop viewport, a button needs a compact frame. Classify what you're building and pick dimensions accordingly.
703
704 ### Content-aware sizing
705
706 Size the iframe to fit the content. A full page needs a desktop-sized viewport; a button or card needs a compact frame. Don't put small components in huge iframes -- they'll look lost in whitespace. For cards, forms, and small components, center them with `flex items-center justify-center min-h-screen` and use a snug iframe. For page sections, skip `min-h-screen` and let content determine the height.
707
708 ### Full-page mockups
709
710 For landing pages and multi-section pages, use larger iframe dimensions:
711
712 - **Landing page (desktop):** 1280 × 900 -- shows hero + start of next section, user scrolls within iframe
713 - **Landing page (full):** 1280 × 2400 -- shows entire page without scrolling (screenshot-style review)
714 - **Multi-page app (desktop):** 1280 × 800 -- standard app viewport
715 - **Multi-page app (mobile):** 390 × 844 -- iPhone viewport
716
717 When comparing full landing pages side-by-side, use 1280 × 900 and arrange horizontally with 50px gutters. The user scrolls within each iframe to see the full page.
718
719 ### Responsive comparison presets
720
721 When showing the **same component** at multiple screen widths, use these standard viewport sizes and arrange them in a row with ~50px gutters:
722
723 - Mobile: 390 × 844
724 - Tablet: 768 × 1024
725 - Desktop: 1280 × 720
726
727 ## Common Pitfalls
728
729 ### Keep mockups self-contained
730
731 Each mockup component must be fully self-contained. Prefer inlining small sub-components (nav bars, footers, cards) directly in the mockup file rather than importing from elsewhere. This keeps mockups isolated and editable without risk of breaking other variants.
732
733 **Exception: multi-page `_shared/` imports.** For multi-page projects (only when the user explicitly requests multiple pages — see [Subagent Orchestration](#subagent-orchestration)), pages import shared layout components from their sibling `_shared/` folder. This is intentional -- the shared shell ensures visual consistency across pages. The rule still applies within each page: don't import from other project folders or from other pages.
734
735 ### No variant switchers inside components
736
737 Mockups are displayed as individual iframes on the canvas -- the canvas itself is the variant switcher. Do not build tabs, dropdowns, or navigation inside a mockup component to switch between variants. Each variant should be its own file rendered in its own iframe.
738
739 ### Sync design tokens with the main app
740
741 When extracting existing components, create `_group.css` in the extraction's group folder with the main app's `:root` and `.dark` CSS variable blocks plus any font `@import`s the app uses. Each extracted component imports `./_group.css` explicitly. Do not edit the global `artifacts/mockup-sandbox/src/index.css` — that would leak one app's tokens into every unrelated mockup group in the sandbox. See the {{skill("mockup-extract")}} skill for the full process.
742
743 ### Fixing broken previews
744
745 If a mockup shows a blank iframe or fails to render:
746
747 1. Check the workflow console logs for `Failed to resolve import` errors.
748 2. Verify the missing file exists under `artifacts/mockup-sandbox/src/` (not the main app).
749 3. Ensure the file exports at least one function component (named or default).
750 4. Restart the workflow if you changed `vite.config.ts` or `package.json`.