Index of every page on this site: llms.txt
All skills
harlan-zw avatar

/nuxt-frontend-design

@9c94eb4
Run it yourself

Build or polish Nuxt UI v4+ pages and design systems. Use for landing pages, dashboards, tokens, motion, or generic-looking UX.

Use this Skill: https://skilld.dev/gh/harlan-zw/harlan-agent-kit/nuxt-frontend-design

Nothing lands on disk. Nothing to clean up.

Fork this Skill

Edit a local copy. It keeps the author and licence.

SKILL.md

≈37 tokens for metadata: the name and description. ≈5.8k when used: this file. ≈43k more on demand in 30 files.

Description uses 1.9% of example budget

Before choosing a Skill, your Agent reads its name and description. All available Skills share that space.

  • A shorter description leaves more room for other Skills. This entry exceeds our 1% size suggestion.

In our Claude Code example, all Skill names and descriptions share 8,000 characters. This Skill uses ≈150 characters, or 1.9%.

The 1% threshold is a size suggestion. Longer descriptions can still fit.

Your model, settings, and other Skills decide how much text your Agent can read.

Example settings and source

The example uses a 200k-token context and default Claude Code settings. The count includes the name, description, separators, and when_to_use when present. Codex also counts local file paths.

Skit's source and limits: Codex 0.160.1, Claude Code 2.1.292.

Nuxt Frontend Design

Full lifecycle frontend skill: setup, build, polish. Detects the right phase from project state.

Worktree isolation

Before any edit, follow the worktree isolation contract.

Job artifacts, contract format, dev server, checkpointing, and the handoff schema live in references/workflow.md. Read it before Phase 2 or Phase 3.

Project State

!bash "${CLAUDE_SKILL_DIR}/scripts/project-state.sh"

Phase Detection

$ARGUMENTS is the text after the invocation, e.g. /nuxt-frontend-design frost landing page → "frost landing page". Parse it for both a theme name and an action; that example means ensure the frost theme, then build the landing page.

IS_NUXT=false: this skill needs a Nuxt project (nuxt.config.ts). Say so and stop.

State Phase
HAS_COLORS / HAS_THEME / HAS_GUIDELINES all false Phase 1 (setup)
Mixed (some true, some false) Phase 1 (repair a corrupted setup)
$ARGUMENTS names a theme the design system doesn't use Phase 1 with that theme
PRIOR_REVIEW with FAIL verdict Repair pass (below)
$ARGUMENTS asks for new pages Phase 2 (build)
$ARGUMENTS asks to refine/polish, or existing pages need work Phase 3 (polish)
No arguments, design system exists Phase 3 (audit existing pages)

Repair pass: read the full {JOB_DIR}/review-report.md, not just the verdict line. Fix every [HARD REJECT] and [RUBRIC] item at its referenced file:line, then re-emit the handoff with updated contract_criteria_status. Reuse the existing job ID.

Phase 2 depends on a complete design system. If any of the three indicators is missing, run Phase 1 first and tell the user you're doing so.

After Phase 1, emit the handoff and continue into Phase 2 when pages were asked for. Offer a fresh conversation with /nuxt-frontend-design {page} only after repair passes or for multi-page builds.

Content & Asset Rules

Apply across Phase 2 and Phase 3. Review treats violations as hard rejects.

Every Element Earns Its Place

Each visible element does one job:

  • Inform: data the reader acts on or decides with.
  • Teach: something the reader does not know yet and needs now.
  • Orient: navigation, wayfinding, current location.
  • Brand: an element the site's DESIGN.md registers as a brand asset.

If an element has no job, delete it. Noise is any element that fails this test.

Show, don't tell. If a sentence describes what the UI does, show the UI doing it with a real component, real data, or a working demo. This applies to dashboards and empty states too.

No text decoration. These fail the test unless DESIGN.md registers them as brand:

  • Eyebrows: a small label above a heading.
  • Subtitles or taglines that restate the heading.
  • Labels that restate the value ("Status: Active" becomes "Active").
  • Counts or facts that do not vary ("Watching 3 of 3 sites"). For table columns, see Hierarchy in craft-rules.md.
  • Decorative icons beside headings, cards, or list items. A per-metric icon that encodes its data, a trend direction or a status, informs. The same constant icon on every card carries no data and fails.
  • Section numbers where the order means nothing.
  • Metadata lines joined with "·" that nobody acts on.

If a section reads flat after removal, fix it with separation, scale, or layout. Do not add the decoration back. Sanctioned replacements: a data line below the heading, a hairline with a directional action, numbering where order is real, emphasis on one lead item.

Start with less. Build the first version with the fewest elements. Each addition names its job. Never pad with placeholder sections, dummy stats, filler copy, icon grids, or logo bars. Ask before you add content the contract did not name.

Subtraction pass. Before handoff, list each visible element with its job. Delete the ones with none. Show before and after screenshots.

AI Slop Ban List

Hard rejections unless the user explicitly asked for them:

  • Aggressive gradient backgrounds (purple/blue hero gradients, full-page meshes)
  • Cards with a coloured left-border accent stripe
  • Illustrations drawn inline with SVG shapes (use a real asset or a labelled placeholder)
  • Emoji in UI copy unless the brand system registers emoji as a token
  • Generic stat blocks ("10M+ users, 99.9% uptime, 24/7 support")
  • Overused sans stacks: Inter, Roboto, Open Sans, Lato, Montserrat, Arial, any bare system-ui / sans-serif fallback as the only font
  • SaaS-landing cliché serifs (Fraunces, Playfair, DM Serif) used without commitment, i.e. paired with a generic sans for body copy as decoration only. A theme that genuinely commits to an editorial, paper-craft, or literary aesthetic (kinetic-paper, flow, monograph) is right to use an editorial serif. The ban targets "add a serif heading for personality" tokenism.

Placeholder Over Fake

A labelled placeholder beats a bad attempt at the real thing.

  • Missing hero image: a neutral block reading 600×400 hero image, not a hand-drawn SVG mountain
  • Missing avatars: https://api.dicebear.com/9.x/initials/svg?seed={name} or https://ui-avatars.com/api/?name={name}
  • Missing product screenshots: solid block at the real aspect ratio with a short label
  • Missing logos: https://logo.clearbit.com/{domain} for real brands, otherwise a labelled box

Never leave broken <img> tags or unstyled fallback boxes. Placeholders should look intentional.

Scope: placeholders suit internal tools, dashboards, and prototypes. Landing and marketing pages want real product demos, screenshots, and named logos per "Show, don't tell" above; a labelled grey box on a hero kills the sale. Fall back to placeholders only when real assets genuinely don't exist yet.

Minimum Scales

Surface these in the build contract as testable criteria.

  • Body copy ≥ 16px; never below 14px
  • Mobile tap targets ≥ 44×44px (buttons, links, icon triggers, form controls)
  • Form input height ≥ 40px desktop, ≥ 44px mobile
  • Contrast: WCAG AA for all text against its background

Phase 1: Design System Setup

Establish the visual foundation. Needed when no design system exists or a new theme is requested. No job ID: design system artifacts are shared, not job-scoped.

Design Philosophy

Commit to an aesthetic direction that serves the content before coding. Define one design principle as a tradeoff statement: "We prioritize X over Y" (e.g. "readability over visual impact", "tactile depth over minimalism"). Record it in DESIGN.md.

What to set up

  1. Color palette: primary, neutral, accent via app.config.ts
  2. Typography: font selection, registration via Nuxt Fonts, --font-* in @theme
  3. Icon system: collection matching the aesthetic via @nuxt/icon
  4. Semantic overrides: --ui-bg, --ui-text, --ui-radius for light/dark
  5. Component theming: global overrides via app.config.ts slots/variants
  6. Extended colors: registering custom theme colors in nuxt.config.ts

Override, don't invent. Use Nuxt UI's existing tokens (bg-muted, text-default, --ui-bg, --ui-radius) and Tailwind's built-in utilities (shadow-md, rounded-xl). Customize by overriding those in app.config.ts and main.css rather than creating generic duplicates. Before naming a new token, check whether an existing --ui-* variable or Tailwind utility already covers it.

Theme signature tokens are the exception: when a theme's voice depends on an effect Tailwind can't express (--shadow-brutal, --shadow-clay, --shadow-paper, --shadow-glass, mesh/glow variables), define it. The ban targets generic duplicates (--shadow-soft, --radius-card), not theme-specific voice.

References

Available themes: frost, clay, blueprint, nebula, zen, neon, teenage-engineering, kinetic-paper, flow, devtool, monograph (the live list is injected above).

Read exactly one theme file: ${CLAUDE_SKILL_DIR}/references/themes/{chosen-theme}.md. Reading several for comparison burns context without improving the choice. With no theme specified, default to frost for dark mode projects and zen for light mode; ask only when the choice is genuinely ambiguous.

After Setup: Emit DESIGN.md

Emit DESIGN.md at the project root after writing app.config.ts, main.css, and nuxt.config.ts:

  1. Collision guard: if DESIGN.md exists, ask before overwriting. Offer to merge (keeping the decisions log) or abort.
  2. Read the template: templates/DESIGN.md
  3. YAML front matter: the chosen theme file already carries a DESIGN.md-compatible YAML block. Copy it, then apply user-specific customisations (brand name, swapped primary hex, additional registered colours, extra component surfaces). Prefer token refs ({colors.primary}, {rounded.md}) over restating hex/px values.
  4. Prose sections: fill every section below the front matter from the decisions just made, no placeholders.
  5. Write to DESIGN.md at the project root.
  6. Verify placeholders removed: grep -cE '\{\{|TODO|placeholder' DESIGN.md returns 0. (Single-brace {colors.primary} token refs are legitimate and stay.)
  7. Verify tokens lint: run pnpm dlx @google/design.md lint DESIGN.md without hiding stderr or piping away its exit status. Require a successful exit and zero reported errors. If the linter crashes, preserve the diagnostic and repair its input before retrying. For raw.match is not a function, quote floats and convert rgba() values to 8-digit hex. Record intentional button-primary contrast tradeoffs in docs/design-decisions.md.
  8. Verify budget: DESIGN.md is at or under 300 lines, and every section is at or under 40. The caps and the audit live in the root docs contract.

Modifying an existing design system: update DESIGN.md in place.

DESIGN.md binds craft-rules.md to the project's components. It never restates those rules.

After Setup: COPY.md is the other half

DESIGN.md owns the pixels. It does not own the words, and a page built with no decision about its words ships whatever sentence each agent liked that day.

After emitting DESIGN.md, check for COPY.md at the project root. If the project has user-visible strings and no COPY.md, say so and offer to run the installed Brundlefly copywriting Skill init workflow. Do not write one from inside this skill: it bootstraps from the strings that already ship, and that is a different harvest from the one done here.

When COPY.md exists, read it before writing a single label, heading, empty state or error, and keep DESIGN.md pointing at it rather than restating voice rules. DESIGN.md's Voice section is one line: which file owns this.

Setup Recovery

Phase 1 failing mid-setup (build error, malformed config) means fixing the config before anything else. Verify all three indicators pass (colors: in app.config.ts, @theme in main.css, DESIGN.md with no placeholders) before moving to Phase 2. A DESIGN.md with unfilled template sections is worse than none.

Setup Gotchas

  • Font selection: avoid the top 5 web fonts (Inter, Roboto, Open Sans, Lato, Montserrat) and system-ui. Pick fonts that reinforce the design principle.
  • Button visibility: primary CTAs need visible backgrounds. Set colors.primary plus button.defaultVariants.variant: 'solid' in app.config.ts. Secondary actions (icon triggers, overflow menus, table row actions) can use ghost or outline; see components/feedback.md.
  • No fake UI: if it looks interactive, wire it up.

Phase 2: Build Pages

Compose pages and UI patterns with Nuxt UI v4+. Requires a design system.

Run the dev server setup and contract steps in references/workflow.md before the first smoke test.

Build recovery: build-progress.md present without build-handoff.json means a previous build was interrupted. Read the progress file for which pages completed and which criteria remain, resume from the last incomplete page, and re-run dev server setup since the old process is gone.

Read the Foundation

If not already in context from Phase 1:

  1. Read the DESIGN.md core.
  2. Read the topic file its load map names for the layer you work in. Skip the others.
  3. Read COPY.md.
  4. Grep GLOSSARY.md for each noun you will render. Do not read it whole.
  5. Open main.css, app.config.ts or nuxt.config.ts only to look up a token you need.

Every string the page renders comes from COPY.md and GLOSSARY.md, in that order: the noun from the glossary, the sentence around it from the copy file. Inventing either while building a component is how a product ends up describing itself four ways.

Use the project's semantic tokens, fonts, and component overrides. Never hardcode colors, shadows, or radii that bypass the design system. For a design variation, override an existing Nuxt UI token rather than introducing a new one.

References

Load the reference matching what you're building. Loading several before writing any code costs context without improving the first page; pull the next one when you reach a new component type.

Building… Reference
Landing / marketing page pages/landing.md
Dashboard / admin pages/dashboard.md
Forms components/forms.md
Data tables components/tables.md
Navigation components/navigation.md
Feedback / overlays components/feedback.md
Charts, dashboards, sparklines, stat cards polish/data-viz.md
Lists, tables, async states, custom CSS classes craft-rules.md

When The User Asks For Variations

For 2+ options of the same page or component, vary across concrete dimensions rather than producing near-duplicates. Pick at least three of:

  • Scale: hero type at 48px vs 96px vs 144px
  • Fill vs outline: solid surfaces vs bordered/ghost
  • Layout structure: stacked vs split vs asymmetric grid
  • Visual rhythm: uniform cards vs feature + supporting mix
  • Type treatment: display serif vs utility sans, tight vs wide tracking
  • Texture and layering: flat vs shadowed vs offset/overlapping
  • Density: airy vs compact

Start the first variation by-the-book, then escalate: each successive variation pushes further on one or two axes. Three variations differing only in accent colour are the same design three times.

Expose variations via route (/pages/index-a.vue, /pages/index-b.vue) or a ?variant= query param with v-if blocks so the user can A/B them in one tab.

Build Gotchas

Framework traps that grep won't reveal:

  • v4 component renames: ButtonGroup → UFieldGroup, PageMarquee → UMarquee. Old names silently render nothing.
  • UPageHero needs a parent section: wrap in UPageSection or a max-width container.
  • Form validation timing: UForm with Zod validates on blur by default. validate-on="input" for inline.
  • UTable empty state: without an explicit empty slot, an empty table shows nothing.
  • SSR boundary: wrap client-only animations in ClientOnly, not entire page sections.
  • Component locality: a new app/components/Foo.vue claims app-wide ownership (global auto-import, rename blast radius, collision risk). Default to colocating as _Foo.vue next to its page; the _ prefix opts out of auto-import. Promote to app/components/ once ≥2 unrelated features consume it. Review hard-rejects single-caller globals.

Review's hard rejection list is the authoritative rubric; see /nuxt-frontend-review.


Phase 3: Polish

Refine existing interfaces against the project's own design system, not generic best practices. If $ARGUMENTS names an area (typography, motion, color), go straight to that reference.

Read the foundation files from Phase 2 if they aren't in context.

Audit Foundation Tokens

Missing tokens cause inconsistency downstream. Fix gaps before elevating.

Token category Where defined What to check
Colors app.config.ts colors primary and neutral set? Additional theme colors registered?
Fonts @theme --font-* At least --font-sans? Display/mono if used?
Semantic overrides :root / .dark --ui-* --ui-bg, --ui-text, --ui-border customized?
Component overrides app.config.ts ui.* Key components themed? defaultVariants set?
Unnecessary tokens @theme Custom tokens duplicating Tailwind builtins or --ui-*? Remove and use the existing token.

Observe Before Changing

Polish modifies an existing voice. Read 2-3 key .vue files first and state what the interface is currently saying: copy tone, shadow and card treatment, density, hover and focus states, animation style, rhythm between sections. The goal is to match and elevate that vocabulary. Not being able to describe the existing voice in one sentence means you are not ready to polish.

Audit Consistency

Review's mechanical checks are the authoritative list (hardcoded hex/rgb, slate-/gray-/zinc-/stone- outside the configured neutral, bg-white/text-black, banned font families, custom @theme tokens duplicating --ui-*). See harlan-agent-kit:nuxt-frontend-review → references/mechanical-checks.md. Fix hits before handoff; review re-grades the same patterns.

Lead with the class-token inventory, the same command review runs:

pnpm dlx @ripast/cli css-class-scan --glob 'app/**' --sort count-desc --json

Look for:

  • Synonym clusters: bg-gray-100 + bg-slate-100 + bg-zinc-100 all filling one semantic role (bg-muted). Each cluster is a conformity fix.
  • One-off tokens (count = 1): usually a hand-tuned value that should map to a token.
  • Low-count spellings near a high-count one: drift from the canonical class.

With an obvious token map, apply it via ripast css-class-rename --map tokens.json --apply (dry-run first) rather than hand-editing call sites.

Beyond the mechanical list: inconsistent shadow/radius choices across similar components (pick one per component type in app.config.ts), inline style=, raw HTML where a Nuxt UI component exists, and anything in DESIGN.md the implementation contradicts.

Audit Confirmation

Present findings before changing anything:

**Audit findings:**

Token issues (will fix):
1. Hardcoded `bg-slate-100` in HeroSection.vue:42 → should use `bg-muted`

Aesthetic observations (need your input):
2. Hero text feels small for a landing page → increase size? [intentional / fix]
3. Cards all use identical treatment → add hierarchy? [intentional / fix]
  • Token and consistency violations are objectively wrong per the design system: present as "will fix".
  • Aesthetic judgments (sizing, hierarchy, rhythm, visual weight) need user input. Do not assume they are problems.
  • Read the decisions log first: docs/design-decisions.md, or ## Design Decisions in DESIGN.md if the repo has not split. Anything already ruled on is settled; present only new observations. If all of them are covered, fix the token issues and move to Elevate.
  • Wait for the user to mark each aesthetic item "intentional" or "fix".

After confirmation, append each "intentional" choice to docs/design-decisions.md with a date. If it changes a standing rule, edit that rule in DESIGN.md in one sentence. Never add dated text to DESIGN.md. Follow the root docs budgets.

Fix only approved items.

Elevate

Once foundation and consistency are solid and the audit is confirmed. Read by symptom:

Symptom Reference
Feels flat/static polish/interactions.md
No entrance animations polish/motion.md
Typography feels generic polish/typography.md
Layout cramped or boring polish/spatial.md
Colors dull or inconsistent polish/color.md
Not responsive enough polish/responsive.md
Copy unclear or generic polish/ux-writing.md
Reaching for JS/custom tokens for native CSS work polish/css-toolkit.md
Chart/dashboard noisy, dishonest, or low data-ink polish/data-viz.md

For "make it better" or "polish everything": start with interactions.md + motion.md + color.md (highest impact), add spatial.md, typography.md, responsive.md, ux-writing.md only where the audit found issues, and consult css-toolkit.md whenever you are about to invent a token, add a JS scroll observer, or hand-code a popover, since the native CSS equivalent is usually one line.

Verify the Route Still Loads

With $DEV_PORT / $DEV_LOG allocated (see workflow reference):

curl -sf "http://localhost:$DEV_PORT/{route}" > /dev/null && echo OK || echo FAIL
grep -nE '^\s*(\[error\]|\[warn\]|ERROR|WARN|✖|✘|Hydration |Cannot find|Failed to (resolve|compile))' "$DEV_LOG" \
  || echo "dev server log clean"

That is the whole self-verification at this stage. Visual and interaction verification is review's job; duplicating it here wastes context.

Polish Rules

  • Keep what already works and is distinctive.
  • "Same product, elevated execution", not "this is different".
  • Refine rather than replace wholesale.
  • Polish what's there; adding features is scope creep.
  • Over-polishing kills distinctiveness. Pick 1-2 areas to elevate, leave the rest.

Polish Gotchas

  • Motion-v SSR hydration: ClientOnly wrapper or onMounted for entrance animations
  • OKLCH browser support: @supports fallback for older Safari
  • Font loading flash: register fonts via Nuxt Fonts, not CSS @import
  • Container queries: need container-type: inline-size on the parent
  • Don't refactor while polishing: polish is visual refinement, not code cleanup

Polish work emits the same handoff as a build; see references/workflow.md.


Reka UI

For components Nuxt UI doesn't cover, or where it is too prescriptive, use Reka UI: unstyled, accessible Vue primitives you style with Tailwind.

Source: SKILL.md on GitHub

skilld matched fixed text patterns in SKILL.md and file names. Patterns miss obfuscated code.

skilld run checks every file with the same patterns. It asks for approval before it loads a Skill with a behavior marked Needs approval.

1 warning3mo3 checks · Risk MEDIUM
  • Gen Agent Trust Hub3mo

    The skill utilizes dynamic context injection to probe the local environment and executes external CLI tools via npx, including an unverified package for CSS analysis.

  • Socket3mo

    No alerts

  • Snyk3mo

    Risk: LOW · No issues

Signed by skilld at 9c94eb4. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Activeupdated last month
argument-hint
[component/page/area]
effort
max

README badge

README badge for harlan-zw/harlan-agent-kit/nuxt-frontend-design