Validate WCAG 2.1 Level AA compliance and accessibility best practices. Use when performing accessibility audits and WCAG certification.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Create distinctive, production-grade Svelte/TypeScript frontends with exceptional design quality
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
This skill guides the creation of distinctive, production-grade Svelte frontends that combine Svelte's reactive elegance with exceptional design quality. It integrates all design frameworks: intentional thinking, typography, color, motion, spatial composition, and anti-pattern awareness.
Before writing any code, establish intentional design direction:
The Four Critical Questions:
Deliberately reject these patterns:
Typography:
Color & Theme:
Layout & Space:
Motion:
Always use TypeScript in Svelte components:
<script lang="ts">
import type { ComponentProps } from 'svelte'
interface Props {
title: string
count: number
onAction?: () => void
}
let { title, count, onAction }: Props = $props()
</script>
$:Leverage Svelte's reactive declarations for dynamic styling and state:
<script lang="ts">
let theme: 'light' | 'dark' = $state('light')
let isHovered = $state(false)
// Reactive computed values
let backgroundColor = $derived(
theme === 'light' ? 'var(--color-bg-light)' : 'var(--color-bg-dark)'
)
let shadowIntensity = $derived(isHovered ? '0.2' : '0.1')
</script>
Svelte's scoped styles are default. Use CSS custom properties for theming:
<style>
:global(:root) {
--color-primary: #8b4513;
--color-accent: #d4a574;
--color-bg: #faf8f3;
--font-display: 'Playfair Display', serif;
--font-body: 'IBM Plex Sans', sans-serif;
--spacing-unit: 8px;
}
.card {
background: var(--color-bg);
padding: calc(var(--spacing-unit) * 3);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, var(--shadow-intensity));
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.card:hover {
--shadow-intensity: 0.15;
transform: translateY(-4px);
}
</style>
Use Svelte's built-in transitions for elegant animations:
<script lang="ts">
import { fade, fly, scale, slide } from 'svelte/transition'
import { cubicOut, elasticOut } from 'svelte/easing'
let isVisible = $state(true)
let showDetails = $state(false)
</script>
<!-- Fade in on mount -->
<div in:fade={{ duration: 300 }} out:fade={{ duration: 200 }}>
Content
</div>
<!-- Orchestrated entrance with stagger -->
<div
in:fly={{ y: 50, duration: 600, delay: 100, easing: cubicOut }}
out:fly={{ y: 20, duration: 300 }}
>
Hero section
</div>
<!-- Elastic expand on interaction -->
{#if showDetails}
<div
in:scale={{ start: 0.95, duration: 400, easing: elasticOut }}
out:scale={{ duration: 200 }}
>
Detailed content
</div>
{/if}
<!-- Slide for list items (staggered) -->
<ul>
{#each items as item (item.id)}
<li
in:slide={{ duration: 400, delay: index * 50 }}
out:slide={{ duration: 200 }}
>
{item.name}
</li>
{/each}
</ul>
Use Svelte stores for theme, animations, and global UI state:
<!-- lib/stores/theme.ts -->
import { writable, derived } from 'svelte/store'
export const isDarkMode = writable(false)
export const themeVariables = derived(isDarkMode, ($isDarkMode) => ({
bgColor: $isDarkMode ? '#1a1a1a' : '#faf8f3',
textColor: $isDarkMode ? '#f5f5f5' : '#333333',
accentColor: '#d4a574',
shadows: $isDarkMode ? 'rgba(0,0,0,0.4)' : 'rgba(0,0,0,0.1)',
}))
<!-- Usage in component -->
<script lang="ts">
import { isDarkMode, themeVariables } from '$lib/stores/theme'
</script>
<div style:background-color={$themeVariables.bgColor}>
Content
</div>
Svelte's approach to accessibility:
<script lang="ts">
let isMenuOpen = $state(false)
let focusedIndex = $state(-1)
</script>
<!-- Semantic structure -->
<nav aria-label="Main navigation">
<button
aria-expanded={isMenuOpen}
aria-controls="main-menu"
aria-label="Toggle navigation menu"
>
Menu
</button>
<ul id="main-menu" role="menubar" hidden={!isMenuOpen}>
{#each menuItems as item (item.id)}
<li role="none">
<a href={item.href} role="menuitem">
{item.label}
</a>
</li>
{/each}
</ul>
</nav>
<!-- Form accessibility -->
<form>
<label for="email">Email address</label>
<input
id="email"
type="email"
required
aria-required="true"
aria-describedby="email-hint"
/>
<small id="email-hint">We'll never share your email.</small>
</form>
Use Svelte's class directives and media queries:
<script lang="ts">
let viewport: 'mobile' | 'tablet' | 'desktop' = $state('mobile')
let windowWidth = $state(0)
$effect(() => {
if (windowWidth < 640) viewport = 'mobile'
else if (windowWidth < 1024) viewport = 'tablet'
else viewport = 'desktop'
})
</script>
<svelte:window bind:innerWidth={windowWidth} />
<div class="container" class:is-mobile={viewport === 'mobile'}>
<header class:is-compact={viewport === 'mobile'}>
<!-- Mobile-optimized header -->
</header>
</div>
<style>
.container {
padding: calc(var(--spacing-unit) * 4);
}
.container.is-mobile {
padding: calc(var(--spacing-unit) * 2);
}
header.is-compact {
font-size: 18px;
}
@media (min-width: 640px) {
header {
font-size: 24px;
}
}
</style>
Input: Feature requirements, target users, problem statement
Actions:
Deliverable: Design brief with clear direction
Input: Design brief and tone direction
Actions:
Deliverable: Design tokens in CSS variables and Svelte stores
<!-- $lib/styles/tokens.css -->
:root {
/* Typography */
--font-display: 'Playfair Display', serif;
--font-body: 'IBM Plex Sans', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
--size-display: 88px;
--size-h1: 48px;
--size-h2: 28px;
--size-body: 16px;
--size-small: 12px;
/* Colors */
--color-bg: #faf8f3;
--color-text: #2a2a2a;
--color-accent: #d4a574;
--color-accent-dark: #8b4513;
/* Motion */
--easing-out: cubic-bezier(0.16, 0.04, 0.04, 1);
--easing-elastic: cubic-bezier(0.34, 1.56, 0.64, 1);
--duration-quick: 200ms;
--duration-standard: 400ms;
--duration-slow: 600ms;
}
Input: Design tokens and feature requirements
Actions:
Deliverable: Typed component structure
<!-- lib/components/Button.svelte -->
<script lang="ts">
import { cubicOut } from 'svelte/easing'
interface Props {
variant?: 'primary' | 'secondary' | 'outline'
size?: 'small' | 'medium' | 'large'
disabled?: boolean
ariaLabel?: string
onclick?: () => void
}
let {
variant = 'primary',
size = 'medium',
disabled = false,
ariaLabel,
onclick,
}: Props = $props()
</script>
<button
class="button {variant} {size}"
{disabled}
aria-label={ariaLabel}
on:click={onclick}
in:scale={{ start: 0.95, duration: 200, easing: cubicOut }}
>
<slot />
</button>
Input: Component structure and design tokens
Actions:
Deliverable: Transition patterns and animation sequences
Input: Component library and motion patterns
Actions:
Deliverable: Responsive component library
Input: Design tokens and component library
Actions:
Deliverable: Fully themed component system
Input: All components and interactions
Actions:
Deliverable: Fully accessible component library
Input: Complete feature implementation
Actions:
will-change, GPU acceleration)Deliverable: Production-ready application
Use these checks before finalizing any design or component:
Typography:
Color & Theme:
Layout & Space:
Motion & Animation:
Svelte-Specific:
<script lang="ts">$:<script lang="ts">
import { fly, scale } from 'svelte/transition'
import { cubicOut, elasticOut } from 'svelte/easing'
let isHovered = $state(false)
interface Props {
title: string
description: string
image?: string
}
let { title, description, image }: Props = $props()
</script>
<article
in:fly={{ y: 40, duration: 500, easing: cubicOut }}
class="card"
on:mouseenter={() => (isHovered = true)}
on:mouseleave={() => (isHovered = false)}
>
{#if image}
<img src={image} alt="" class="card-image" />
{/if}
<div class="card-content">
<h3>{title}</h3>
<p>{description}</p>
{#if isHovered}
<button
in:scale={{ start: 0.8, duration: 300, easing: elasticOut }}
class="card-action"
>
Learn More
</button>
{/if}
</div>
</article>
<style>
.card {
background: var(--color-bg);
border-radius: 12px;
overflow: hidden;
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
cursor: pointer;
}
.card:hover {
transform: translateY(-12px);
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.15);
}
.card-image {
width: 100%;
height: 240px;
object-fit: cover;
}
.card-content {
padding: calc(var(--spacing-unit) * 3);
}
h3 {
font-family: var(--font-display);
font-size: var(--size-h2);
font-weight: 700;
margin: 0 0 calc(var(--spacing-unit) * 2) 0;
color: var(--color-text);
}
p {
font-family: var(--font-body);
font-size: var(--size-body);
line-height: 1.6;
color: rgba(0, 0, 0, 0.7);
margin: 0;
}
.card-action {
margin-top: calc(var(--spacing-unit) * 2);
padding: calc(var(--spacing-unit) * 1.5) calc(var(--spacing-unit) * 3);
background: var(--color-accent);
color: white;
border: none;
border-radius: 6px;
font-family: var(--font-body);
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease-out;
}
.card-action:hover {
background: var(--color-accent-dark);
transform: scale(1.05);
}
</style>
<script lang="ts">
import { slide } from 'svelte/transition'
import { cubicOut } from 'svelte/easing'
interface ListItem {
id: string
label: string
}
interface Props {
items: ListItem[]
}
let { items }: Props = $props()
</script>
<ul class="list">
{#each items as item, index (item.id)}
<li
in:slide={{
duration: 400,
delay: index * 50,
easing: cubicOut,
}}
out:slide={{ duration: 200 }}
>
<span class="list-number">{index + 1}</span>
<span class="list-label">{item.label}</span>
</li>
{/each}
</ul>
<style>
.list {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: flex;
align-items: center;
padding: calc(var(--spacing-unit) * 2) calc(var(--spacing-unit) * 3);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
transition: background-color 0.3s ease-out;
}
li:hover {
background-color: rgba(0, 0, 0, 0.02);
}
.list-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
margin-right: calc(var(--spacing-unit) * 2);
background: var(--color-accent);
color: white;
border-radius: 50%;
font-weight: 600;
font-size: 13px;
}
.list-label {
font-family: var(--font-body);
font-size: var(--size-body);
color: var(--color-text);
}
</style>
$derived for computed values and $effect for side effectssvelte/transition for all animations:global() sparinglywritable for theme, animation state, and global UI statebind: carefully, memoize expensive computations with $derivedReady to build distinctive, intentional Svelte frontends? Start with Phase 1: Design Thinking & Intent Definition. Never skip the pre-coding work.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Validate WCAG 2.1 Level AA compliance and accessibility best practices. Use when performing accessibility audits and WCAG certification.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Analyze feature requirements, dependencies, and security considerations. Use when starting feature implementation from GitHub issues to understand scope, technical feasibility, and risks.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Run SQL queries against psql, BigQuery, or MySQL from the terminal, including natural-language-to-SQL and schema exploration. Use when analyzing data, inspecting DB state, or debugging tables. Trigger on "query the database", "SQL", "show me data from", "explore table".
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Design REST APIs or function contracts with clear request/response specifications, error handling patterns, authentication strategies, and comprehensive documentation.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Generate comprehensive API endpoint tests for REST and GraphQL APIs. Creates tests for all HTTP methods, status codes, authentication, and validation.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Design component architecture and module structure using established architectural patterns for clean, maintainable, and scalable systems.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.