design

Local design mockup workflow for any frontend project. Triggers when the user wants to design, redesign, or mockup a UI component, page, or feature. Discovers the project's actual design system (tokens, fonts, components, framework), generates a standalone HTML mockup that uses those tokens verbatim, asks for approval, then implements the approved design as code in the project's stack. Works with React, Vue, Svelte, Solid, Astro, or plain HTML; with Tailwind v3/v4, CSS modules, styled-components, Panda, vanilla CSS, or any combination. No external service or paid API needed.

design

A six-step workflow that produces high-quality, design-system-faithful UI mockups locally — and then implements them as real components in whatever stack the project is using.

The skill's quality depends entirely on how aggressively it discovers the project's actual design system before generating anything. Do not skip Step 1. Do not invent tokens. Do not assume framework, theme, or styling library.

Invocation

The user will run this skill with a request like:

  • /design a stats card showing earnings
  • /design --creativity high redesign this modal [screenshot]
  • /design --c low fix the spacing on the sidebar nav

Parse $ARGUMENTS for:

  • A creativity level flag (see Step 2)
  • An output directory flag: --out <path> (defaults to .design-mockups/)
  • The request itself (everything else)

Step 1 — Discover the project's design system

This step is mandatory and must run before any generation. The output of this step is a "design system snapshot" you will use throughout the rest of the workflow. Do not generate a single line of HTML until you have it.

1a. Detect the framework and styling system

Read package.json (or equivalent: Cargo.toml, deno.json, composer.json, requirements.txt, etc.). Note:

  • Framework: React/Next.js/Remix, Vue/Nuxt, Svelte/SvelteKit, SolidJS, Astro, Qwik, Angular, plain HTML, etc.
  • Styling system (in priority order):
    1. Tailwind CSS — check version (v3 vs v4 differ significantly):
      • tailwind.config.{js,ts,cjs,mjs} → likely v3
      • @import 'tailwindcss' + @theme block in a CSS file → v4
    2. Panda CSS — panda.config.*
    3. UnoCSS — uno.config.*
    4. CSS Modules — *.module.css files
    5. styled-components / emotion — imports in component files
    6. Vanilla CSS / Sass — .css / .scss files with custom properties
    7. CSS-in-JS framework other than above
  • Component library / primitives:
    • Radix UI, Headless UI, Reach UI (unstyled primitives)
    • shadcn/ui (often present as components/ui/)
    • Material UI, Chakra, Mantine, Ant Design, NextUI
    • Component-only libraries (Lucide, Heroicons, Phosphor for icons)
  • Class merge utility: search for one of clsx, cn, classnames, tailwind-merge, cva (class-variance-authority)

1b. Locate design tokens

This is the most important sub-step. Tokens are usually one of:

  1. CSS custom properties in a global stylesheet:

    # Find candidate files
    glob: **/{globals,global,theme,tokens,variables,index,app,main,style,styles}.{css,scss,sass,less}
    glob: **/styles/**/*.{css,scss}
    glob: **/src/**/{theme,tokens,variables}.*
    

    Read the matches and extract every --* custom property declared in :root, [data-theme], .dark, .light, etc.

  2. Tailwind config theme (v3): read tailwind.config.*, extract theme.colors, theme.extend.colors, theme.fontFamily, theme.borderRadius, theme.spacing if customized.

  3. Tailwind v4 @theme block: parse the @theme { ... } block in the global CSS file. The keys (--color-*, --font-*, --radius-*) become Tailwind utility classes.

  4. JS/TS theme objects: search for files named theme.{ts,js}, tokens.{ts,js}, design-tokens.{ts,js}, or any file exporting an object with keys like colors, fonts, spacing. Common in styled-components, Chakra, Mantine, Tamagui.

  5. Figma tokens / Style Dictionary output: look for tokens/ or design-tokens/ directories, JSON files matching W3C token format.

Capture as a snapshot:

[design-system-snapshot]
- framework: <detected>
- styling: <detected>
- token-source: <file path(s) you read tokens from>
- background-tokens: <list with values, e.g. --bg-page: oklch(0.13 0.02 145)>
- text-tokens: <list with values>
- border-tokens: <list with values>
- accent-tokens: <list with values>
- brand-color-scale: <list, e.g. --brand-01 through --brand-10>
- neutral-scale: <list>
- radius: <value(s)>
- font-stack: <list, e.g. Inter, JetBrains Mono>
- icon-library: <detected>
- theme: <light | dark | both>
- class-merge-util: <e.g. cn from @/lib/utils, or none>
- component-pattern: <e.g. CVA + Radix, or plain function components>

1c. Find a baseline component to anchor on

Find ONE existing component to use as a stylistic anchor. Prefer in this order:

  1. A Button component (button.{tsx,vue,svelte,jsx} in components/ui/, src/components/, lib/components/, etc.)
  2. A Card component
  3. Any component the user explicitly references in their request
  4. The most recently modified file under any components/ directory

Read it. Note:

  • How props are typed
  • How class names are merged
  • Whether variants are defined declaratively (CVA/tv) or with conditionals
  • File header conventions ('use client', exports style, etc.)

1d. Detect the theme mode

  • If you only find dark token values → dark-only
  • If you find both :root and .dark selectors → both, light default
  • If you find [data-theme="dark"] and [data-theme="light"]both, switchable
  • If only light token values → light-only

The mockup must render in the project's default theme. If both themes exist, generate two side-by-side variants (one per theme) unless the user specifies otherwise.

1e. Show the snapshot to the user

Before proceeding, briefly show the user what you discovered:

Design system detected: Framework: Next.js (React) · Styling: Tailwind v4 · Theme: dark-only · Tokens: 47 CSS vars in app/globals.css · Radius: 2px · Fonts: Inter, JetBrains Mono · Class merge: cn from @/lib/utils · Anchor component: components/ui/button.tsx (CVA + Radix)

If detection fails for any field, say so explicitly and ask the user to point you to the right file.


Step 2 — Resolve creativity level and clarify the request

Creativity level

Parse $ARGUMENTS for a creativity flag. Accept these forms anywhere in the argument string:

  • --creativity low|medium|high
  • --c low|medium|high
  • The bare words low, medium, high if they appear unambiguously

If no creativity level is specified, ask before proceeding:

"What creativity level? low (layout only), medium (layout + tokens + data), or high (full reimagination)?"

What each level means

low — Layout-only refinement

Stay within the existing component's structure. Permitted:

  • Reorder, resize, reposition existing elements
  • Adjust spacing, padding, gap values
  • Fix alignment or visual rhythm
  • Correct token misuse (e.g. wrong background level, wrong text token)
  • Improve hover / active / focus / disabled states

Not permitted: new UI elements, different data points, color/token shifts beyond correcting misuse, structural changes.

medium — Purposeful redesign

Rethink presentation while keeping the component's purpose identical. Includes everything in low, plus:

  • Different layout patterns (horizontal ↔ vertical, grid ↔ list)
  • Adjust which data points are shown or how they're labelled
  • Use a different part of the existing token scale (e.g. promote a subtle to a brand accent)
  • Add or remove supporting UI (icons, labels, dividers)
  • Change visual weight hierarchy

Not permitted: changing what the component fundamentally does, inventing data that doesn't exist, introducing new component types not already in the project.

high — Full reimagination

Treat the existing design as context only. Anything goes within the project's design system:

  • Completely new layout, structure, visual language
  • New information architecture (groupings, hierarchy, progressive disclosure)
  • New interaction patterns (replace a slider with input + presets, add toggles)
  • New visual motifs (large typographic stats, progress arcs, badges)
  • Richer data presentation (inline charts, comparison views)
  • Micro-interaction concepts (described in HTML comments)

Must still respect: the project's discovered token system (no raw hex), the discovered radius scale, the discovered theme, the existing component library (no new npm packages in the implementation step).

Additional clarifications

If $ARGUMENTS doesn't already answer these, ask:

  1. What is being designed? (component, page section, modal, table, form…)
  2. What data/content should it show?
  3. Viewport — desktop, mobile, both?
  4. Interaction states to render — default, hover, loading, empty, error?
  5. Nearest existing component it should feel consistent with? (optional)

If $ARGUMENTS is clear, proceed without asking — but list your assumptions.


Step 3 — Write a design brief

Show the user a brief before generating any HTML:

  • Surface: what is being designed and where it would live
  • Goal: primary user action or information communicated
  • Creativity level: resolved level + one sentence on what it permits here
  • Token mapping: which discovered tokens map to which visual roles
  • Constraints: discovered radius, theme, accent color
  • Changes planned: a specific bullet list of changes scoped to the creativity level. Be concrete — "move the fee summary above the slider", not "reorder elements"
  • States to render: which interaction states will be shown
  • Assumptions: anything inferred from incomplete input

Step 4 — Generate the HTML mockup

Generate ONE standalone HTML file. It must use the discovered tokens verbatim. Never invent values. Never use raw hex.

Required scaffold

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>[Component name]</title>

  <!-- FONTS: load whatever fonts the project actually uses -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="<google fonts URL for the discovered font stack>" rel="stylesheet">

  <!-- ICONS: only if an icon library is in the project -->
  <!-- e.g. Phosphor: <script src="https://unpkg.com/@phosphor-icons/web"></script> -->
  <!-- e.g. Lucide: <script src="https://unpkg.com/lucide@latest"></script> + lucide.createIcons() -->

  <!-- TAILWIND CDN if Tailwind is used in the project -->
  <script src="https://cdn.tailwindcss.com"></script>

  <style>
    /* === DESIGN TOKENS — copied verbatim from the discovered token source === */
    :root {
      /* paste the actual :root block (or equivalent) from the project here */
    }
    /* If the project has a .dark or [data-theme="dark"] block, paste it too */
  </style>

  <script>
    /* If Tailwind is used, configure it to alias the token names so utility
       classes work the same as in the project. Skip this if not using Tailwind. */
    tailwind.config = {
      theme: {
        extend: {
          fontFamily: { /* from discovery */ },
          borderRadius: { /* from discovery — match the project exactly */ },
          colors: {
            /* map every discovered semantic token name to its CSS var */
          }
        }
      }
    }
  </script>
</head>
<body class="<root background utility>" style="font-family: <discovered sans>;">
  <!-- COMPONENT MOCKUP HERE -->
</body>
</html>

Visual rules for the mockup

These rules are universal — they apply regardless of the discovered stack:

  1. Use only discovered tokens. Never hardcode hex/rgb/oklch values. If a token doesn't exist for what you need, use the closest discovered token and note the gap in the brief.
  2. Use the discovered radius scale. If the project uses 2px, every corner is 2px. If it uses 12px, every corner is 12px. Don't mix.
  3. Use the discovered accent color for primary actions, active states, and emphasized values.
  4. Use the discovered font stack. Use any monospace font found for numbers, addresses, IDs, percentages, monetary values.
  5. Render multiple states side-by-side when the request involves interaction (default + hover + loading + empty, etc.).
  6. Prefer gap-* utilities or flexbox/grid gap over child margins.
  7. No new component primitives. If a component type isn't in the project (e.g. no Slider exists), don't invent one — use existing patterns.
  8. Render at the discovered theme. If both light and dark exist, render both side-by-side.
  9. Annotate design decisions in a small footer block at the bottom of the mockup, listing what changed and why (especially for medium and high creativity).

Save the artifact

Determine the output directory:

  • --out <path> flag from $ARGUMENTS, OR
  • .design-mockups/ (default — create if missing)

Save to:

{output-dir}/runs/{ISO-timestamp-slug}/design.html

Write {output-dir}/latest.json:

{
  "id": "{ISO-timestamp-slug}",
  "createdAt": "{ISO timestamp}",
  "prompt": "{the description of what was designed}",
  "creativity": "{resolved level}",
  "designHtmlPath": "{output-dir}/runs/{id}/design.html",
  "framework": "{detected framework}",
  "stylingSystem": "{detected styling}",
  "transport": "local"
}

The slug is the first ~40 chars of the prompt, lowercased, non-alphanumerics replaced with -, collapsed.


Step 5 — Present and verify (HARD GATE)

Show the user:

  1. The design brief from Step 3
  2. The path to the saved HTML file
  3. The key decisions you made (token choices, layout approach, omissions)
  4. The verification prompt:

"Open {path} in your browser to review. Reply with feedback or 'looks good' to proceed to implementation."

You must wait for explicit approval before Step 6. This gate is the entire reason this skill produces good output instead of mediocre output. If the user gives feedback, revise the same HTML file in place, summarize what changed, and ask again. Iterate until approved.


Step 6 — Implement in the project's stack

Once approved, port the design to real code. The implementation must match the discovered framework and conventions exactly.

Universal rules

  • Use only the discovered class merge utility. If the project uses cn from @/lib/utils, use that. If it uses clsx, use that. If it uses none, use template literals carefully.
  • Use only the discovered token names. If the project's Tailwind aliases tokens as bg-bg-base, write bg-bg-base. Don't translate to bg-zinc-900.
  • Match the discovered component pattern. If the anchor component uses CVA + forwardRef + Radix, do the same. If it uses plain function components, do the same. Don't impose patterns the project doesn't use.
  • Use only icons from the discovered icon library. If Lucide is installed, use Lucide. If Phosphor is installed, use Phosphor. Don't add a new icon package.
  • Don't add new dependencies. If the design needs something not in the project, build it from primitives that already exist.
  • Match file placement conventions. Find where similar components live in the project and put new files there.

Framework-specific notes

React / Next.js

  • Match the project's file extension (.tsx vs .jsx)
  • Match the export style (named vs default)
  • If the project uses 'use client' directives, add them where appropriate
  • Use forwardRef if other primitives in the project do

Vue / Nuxt

  • Match the SFC style (<script setup> vs Options API)
  • Match the script lang (ts vs plain JS)
  • Match the style block convention (scoped vs unscoped vs <style module>)

Svelte / SvelteKit

  • Match Svelte 4 vs Svelte 5 runes syntax based on what the project uses
  • Use the project's prop typing convention

Astro

  • Decide between .astro and the project's framework component flavor
  • Match slot conventions

After implementing

  1. Show the diff of files created or modified
  2. Note any props the caller needs to pass
  3. Note any assumptions about existing components/utilities
  4. Suggest a usage example in context
  5. Don't run the project or commit unless the user asks

Anti-patterns to avoid

Don'tDo
Skip discovery and use generic Tailwind colorsRead the project's actual tokens
Invent token names like bg-primary-500Use exactly what's in :root
Use rounded-xl because it looks niceMatch the project's actual radius scale
Add a new icon package "for variety"Use only what's already installed
Hardcode #46E841 because it's the brandReference var(--brand-05)
Generate React when the project is VueMatch the discovered framework
Implement before the user approves the mockupWait for explicit "looks good"
Wrap the design in a custom design systemUse the project's existing system
Add dark: variants when tokens are already darkTrust the discovered theme