ux:prototype
Compatibility: If
AskUserQuestionis unavailable, present options as a numbered list and wait for the user's reply. IfTaskis unavailable, run parallel steps sequentially. Thecontext: forkandagent:frontmatter fields are Claude Code-specific — on OpenCode and VS Code Copilot they are ignored and the skill runs inline using the current model.
Scaffold a production-quality SvelteKit prototype with feature-slice architecture, shadcn-svelte components, zod validation, fake auth, and a consistent factory pattern.
Critical Principles
- A prototype that only works with perfect data is a lie. Every component that receives data must render a loading skeleton, an error message, and an empty state — not just the list of items.
- If it's not in the README, the reviewer will guess. Each feature README must document the public API (props and events the feature exposes outward), not just the component tree.
- Fake data is still data. Hard-coded factories must use realistic names, plausible lengths, and diverse content — placeholder text trains reviewers to ignore details that matter.
Step 0: Parse Args
PROTOTYPE_NAME = first non-flag argument
PROTOTYPE_SLUG = slugified PROTOTYPE_NAME (lowercase, hyphens, no special chars)
BG_MODE = true if --bg present
SILENT = true if --silent present
If PROTOTYPE_NAME is absent, ask: "What are we prototyping?"
Slugify: lowercase, replace spaces/underscores with hyphens, strip non-alphanumeric-hyphen chars, collapse consecutive hyphens.
Step 1: Choose Location
Use AskUserQuestion:
question: "Where should the prototype live?"
header: "Location"
multiSelect: false
options:
- label: "In-repo -- single package"
description: "prototypes/{PROTOTYPE_SLUG}/ at project root -- works when there's one prototype"
- label: "In-repo -- monorepo (pnpm workspaces)"
description: "Add as a workspace package; all prototypes share root node_modules"
- label: "Outside repo"
description: ".codevoyant/[project]/prototypes/{PROTOTYPE_SLUG}/ -- isolated from main codebase"
Derive PROTOTYPE_DIR from the answer:
- Single package:
prototypes/{PROTOTYPE_SLUG}/ - Monorepo:
prototypes/{PROTOTYPE_SLUG}/-- additionally, ifpnpm-workspace.yamldoes not already includeprototypes/*, add it to the workspace packages list. - Outside repo:
.codevoyant/{PROJECT_SLUG}/prototypes/{PROTOTYPE_SLUG}/wherePROJECT_SLUGis derived from the current project's directory name.
Record the prototype in codevoyant.json (create if it doesn't exist):
{
"prototypes": [
{
"name": "PROTOTYPE_SLUG",
"path": "PROTOTYPE_DIR",
"location": "in-repo|out-of-repo",
"created": "TIMESTAMP"
}
]
}
See references/utils.md for the codevoyant.json read/write pattern.
Step 2: Gather Style Direction
If the user has not already described style inspiration, use AskUserQuestion:
question: "What's the visual style direction for this prototype?"
header: "Style"
multiSelect: false
options:
- label: "Describe my own direction"
description: "Free text -- I'll describe the aesthetic"
- label: "Linear / Vercel"
description: "Dark, minimal, sharp, monospace accents"
- label: "Notion / Craft"
description: "Clean, off-white, rounded, document-like"
- label: "Stripe / Resend"
description: "Light, professional, subtle gradients, trustworthy"
- label: "Shadcn default"
description: "Neutral, clean slate -- I'll customize later"
Store the result as STYLE_DIRECTION. This informs color palette, border-radius, and font choices in Step 6.
If user selects "Describe my own direction", ask them to describe the aesthetic in free text.
Step 3: Gather Feature List
Ask: "What features should this prototype include? List them (e.g. auth, dashboard, settings, blog)."
Parse the response into FEATURES[] -- slugify each feature name. These become the feature-slice directories.
Example: "auth, dashboard, settings" becomes ["auth", "dashboard", "settings"].
Step 4: Scaffold SvelteKit
Follow references/sveltekit-setup-guide.md for the complete setup procedure.
cd {parent of PROTOTYPE_DIR}
npx sv create {PROTOTYPE_SLUG} --template minimal --types ts --no-add-ons
Install dependencies:
cd {PROTOTYPE_DIR}
pnpm install
Install Tailwind:
pnpm dlx sv add tailwindcss
Install shadcn-svelte:
pnpm dlx shadcn-svelte@latest init
Accept defaults for shadcn-svelte init. This creates src/lib/components/ui/ and components.json.
Install zod:
pnpm add zod
Step 5: Set Up Feature-Slice Structure
Follow references/feature-slice-pattern.md for the full specification.
Create the directory structure:
mkdir -p src/app
mkdir -p src/libs/layout
mkdir -p src/libs/ui
mkdir -p src/libs/factories
mkdir -p src/libs/validators
for FEATURE in "${FEATURES[@]}"; do
mkdir -p "src/libs/features/feature-${FEATURE}/{components,view-models,state,actions}"
done
Create barrel files (index.ts) for each feature and each shared lib directory. Each barrel file exports nothing initially -- it's a placeholder for the public API.
Update svelte.config.js to add path aliases:
alias: {
'$app': './src/app',
'$libs': './src/libs',
'$features': './src/libs/features',
'$ui': './src/libs/ui',
'$layout': './src/libs/layout',
'$factories': './src/libs/factories',
'$validators': './src/libs/validators',
}
Create a README.md for each feature following the template in references/feature-slice-pattern.md.
Step 6: Configure Theme
Apply theme based on STYLE_DIRECTION. Edit src/app.css to set CSS custom properties:
--color-primary,--color-background,--color-foreground,--color-muted,--color-accent,--color-border--radius(border-radius scale)- Font family (use a Google Font if appropriate; load via
src/app.html<link>tag)
Configure Tailwind to reference CSS custom properties so utility classes use the theme.
Follow the theming approach in references/sveltekit-setup-guide.md.
Style presets
- Linear / Vercel: Dark background (#0a0a0a), sharp corners (radius: 0.25rem), monospace accents (JetBrains Mono), high-contrast text
- Notion / Craft: Off-white (#fafafa), generous radius (0.75rem), serif or clean sans-serif (Inter), muted borders
- Stripe / Resend: Light (#ffffff), medium radius (0.5rem), professional sans-serif (Inter), subtle gradients and shadows
- Shadcn default: Use shadcn-svelte's default theme as-is
Step 7: Implement Layout First
Before any feature, implement the responsive layout system:
src/libs/layout/Container.svelte-- max-width wrapper with responsive paddingsrc/libs/layout/Stack.svelte-- vertical flex with configurable gapsrc/libs/layout/Grid.svelte-- responsive CSS gridsrc/libs/layout/Sidebar.svelte-- collapsible sidebar (if appropriate for the prototype)src/libs/layout/index.ts-- barrel file exporting all layout components
Then implement the root layout and error page:
src/app/+layout.svelte-- root layout using layout lib componentssrc/app/+error.svelte-- styled error page
Layout must be responsive from the start. Use Tailwind responsive prefixes (sm:, md:, lg:).
Follow references/feature-slice-pattern.md for layout lib conventions.
Step 8: Implement Features
For each feature in FEATURES[], in order:
- Scaffold feature skeleton -- ensure components/, view-models/, state/, actions/, index.ts, README.md all exist
- Write view-model factory in
src/libs/factories/{feature}.tsfollowingreferences/factory-patterns.md - Write hard-coded data -- inline in the feature's
state/directory or as a mock data file. All mock data must be typed via the entity's zod schema -- noany. - Implement routes:
src/routes/{feature}/+page.server.ts-- loads data, runs through factory, returns view modelsrc/routes/{feature}/+page.svelte-- pure UI, receives view model as prop
- Use shadcn-svelte components for all UI elements. Install as needed:
pnpm dlx shadcn-svelte@latest add {component} - Fake auth (if
authis in FEATURES): accept any non-empty email + password; store session in a server-sideMap; no JWT, no hashing, no database. Provide login/logout routes.
Use Svelte's built-in animation where appropriate (transition:, animate: directives). Do not add third-party animation libraries.
Three-state rule (required for every data-bound component): Every component that receives a list, async result, or fetchable resource must implement all three states using shadcn-svelte primitives:
- Loading:
<Skeleton>with the same layout as the loaded state - Error:
<Alert variant="destructive">with the error message and a retry action - Empty: purposeful empty state with a call to action (not a blank div)
No component that receives external data is complete until all three states render correctly.
Accessibility baseline (WCAG 2.1 AA — required):
- Interactive elements:
aria-labelon icon-only buttons;roleon custom interactive elements - Images:
alton every<img>; decorative images usealt="" - Forms: every
<input>and<select>has an associated<label>(viaforor wrapping) - Color: do not use color as the only indicator of state (add an icon or text label)
- Focus: all interactive elements must be keyboard-reachable in logical tab order
After each feature: update the feature's README.md with component connections and public API.
Step 9: Validation Pass
cd {PROTOTYPE_DIR}
pnpm run check # svelte-check
pnpm run build # ensure no build errors
Fix any type errors or build failures before proceeding.
Before marking the prototype complete, run these checklists:
State audit — for each data-bound component:
- Loading state renders without errors
- Error state renders with a descriptive message and retry action
- Empty state renders with a call to action (not blank)
- Happy path renders with realistic (non-placeholder) data
Data realism audit:
- No "Lorem ipsum" or "John Doe" in factory data
- At least one factory item has a long string value (40+ chars for names, 200+ for descriptions)
- At least one factory item has a short/minimal value
- Lists have at least 5 items (enough to test overflow behavior)
Accessibility audit:
- All icon-only buttons have
aria-label - All
<img>elements havealt - All form inputs have associated labels
- Tab through the prototype — every interactive element is reachable
See references/prototype-quality.md for detailed guidance on each checklist item.
Start the dev server and report the URL:
pnpm run dev
Step 10: Report + Notify
Report to user:
Prototype scaffolded: {PROTOTYPE_DIR}
Features: {FEATURES joined by ', '}
Dev server: pnpm run dev (in {PROTOTYPE_DIR})
Recorded in codevoyant.json
If BG_MODE=true and SILENT=false, send desktop notification:
npx @codevoyant/agent-kit notify --title "ux:prototype complete" --message "Prototype '{PROTOTYPE_SLUG}' ready at {PROTOTYPE_DIR}"
See references/utils.md for the notification pattern.
More from cloudvoyant/codevoyant
mem:help
Use when the user asks about available mem commands or needs help choosing a skill. Triggers on: \"mem help\", \"help mem\", \"what can mem do\", \"mem commands\", \"list mem skills\", \"mem reference\". Lists all mem commands with descriptions, arguments, and usage guidance.
14dev:plan
Use when planning architecture for a project or feature. Triggers on: "dev plan", "architecture plan", "plan architecture", "design architecture", "technical design", "system design for". Produces draft plan artifacts in .codevoyant/plans/{slug}/. Use /dev:approve to promote to docs/architecture/.
14em:review
Use when reviewing an engineering roadmap for quality and realism. Triggers on: "em review", "review roadmap", "sanity check roadmap", "em check", "review this plan". Checks capacity realism, dependency gaps, missing risks, and phasing quality. Auto-launched after em:plan.
13dev:explore
Use when researching technical approaches before building. Triggers on: "explore options", "what are my options for", "research approaches", "compare solutions", "dev explore", "generate proposals", "help me decide between". Runs parallel proposal generation via subagents and outputs to .codevoyant/explore/.
13em:plan
Use when planning a project (epic) or initiative with Linear as tracker.
13pm:plan
Plan a product roadmap for a quarter, half-year, or year. Writes a draft roadmap to .codevoyant/roadmaps/ using capability tiers. Triggers on: "pm plan", "product roadmap", "plan a roadmap", "quarterly roadmap", "annual plan".
13