关于 stitch-svelte-components
该技能将 Stitch 屏幕、HTML 文件或 URL 转换为采用 Svelte 5 runes API 的组件,面向 SvelteKit 和独立 Svelte 5 项目。流程还涵盖样式、动效、无障碍检查与开发验证。
主要功能
- 01转换 HTML 为 Svelte 组件
- 02采用 Svelte 5 runes API
- 03映射 SvelteKit 文件路由
- 04使用作用域 CSS 与设计令牌
- 05添加转场并考虑减少动效
- 06检查无障碍并验证开发环境
适用场景
- 01将 Stitch 屏幕实现为 Svelte 页面
- 02把本地 HTML 转为可复用组件
- 03将网页 URL 转为 Svelte 界面
MCP 相关
仅从 Stitch 屏幕获取设计数据和 HTML 时需要 Stitch MCP;本地文件和 URL 输入不需要 MCP。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gabelul/ stitch-kit --skill stitch-svelte-components安装后在 Claude Code 中输入/stitch-svelte-components确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
resources/architecture-checklist.mdcomponent-template.sveltescripts/fetch-stitch.sh详细介绍
Stitch → Svelte 5 / SvelteKit 组件
你是一名 Svelte 5 工程师。你将 HTML 源文件——Stitch 屏幕、本地文件或 URL——转换为符合 Svelte 惯例的组件,并使用 runes API($state、$props、$derived、$effect),而不是旧版 Options API。组件使用带自定义属性的作用域 CSS 进行主题设置,使用 Svelte 内置过渡效果实现动画,并默认采用无障碍标记。
注意: 这是唯一面向 Svelte 的 Stitch 技能。官方
react-components技能面向 Vite/React。项目使用 SvelteKit 时,请使用此技能。
何时使用此技能
在以下情况下使用此技能:
- 目标项目使用 SvelteKit 或独立的 Svelte 5
- 你看到
.svelte文件、svelte.config.js或+page.svelte约定 - 用户提到
svelte、sveltekit、$state、$props或runes
前提条件
HTML 源文件。以下任意一种都可以:
- Stitch 屏幕——需要 Stitch MCP 访问权限和已生成的屏幕
- 本地 HTML 文件——无需 Stitch 账号
- URL——无需 Stitch 账号
此外:
- 目标项目使用 Svelte 5(已启用 runes)——检查
package.json中是否有"svelte": "^5"
第 1 步:解析源文件
后续所有步骤都会读取同一个文件:temp/source.html。根据用户提供的内容,选择相应方式将 HTML 放到该文件中,然后继续第 2 步——无论标记来自哪里,技能的其余部分都相同。
来自 Stitch 屏幕:
- 发现命名空间——使用
list_tools查找 Stitch MCP 前缀 - 获取元数据——调用
[prefix]:get_screen获取设计 JSON - 下载 HTML——GCS URL 需要使用可靠的下载器:
bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html" - 视觉审核——重写前检查
screenshot.downloadUrl。在该 URL 后追加=s0以获取完整分辨率;无论 API 报告的width/height是多少,不带参数的 URL 都会返回 512px 缩略图。
来自本地 HTML 文件:
mkdir -p temp && cp "path/to/design.html" temp/source.html
来自 URL:
bash scripts/fetch-stitch.sh "https://example.com/page" "temp/source.html"
尽管名称如此,该脚本是通用的强化型下载器——它会跟随重定向、重试暂时性失败、处理 gzip,并在结果为空时明确报错。它不关心 URL 是否指向 Stitch。
**来自屏幕截图:**目前没有上传途径——Stitch MCP API 没有图像上传工具。你可以通过 stitch-mcp-generate-screen-from-text 根据文本提示词重建设计,也可以手动编写 HTML,然后使用上面的本地文件途径。
只有 Stitch 途径需要 API 密钥。转换本地文件或 URL 完全不需要 Google 账号。
第 2 步:SvelteKit 文件约定
SvelteKit 使用基于文件的路由。将 Stitch 屏幕映射到以下结构:
src/
├── routes/
│ ├── +layout.svelte ← Persistent shell (nav, footer)
│ ├── +layout.ts ← Layout load function (optional)
│ ├── +page.svelte ← Route page component
│ ├── [route]/
│ │ ├── +page.svelte ← Sub-route page
│ │ └── +page.ts ← Page load function (server-side data)
├── lib/
│ ├── components/ ← Reusable components
│ │ └── [Name].svelte
│ ├── data/
│ │ └── mockData.ts ← Decoupled static content
│ └── types/
│ └── index.ts ← Shared types
static/ ← Static assets
关键规则:
- 页面以
+page.svelte的形式放在src/routes/中 - 可复用组件放在
src/lib/components/中 $lib/是src/lib/的别名——务必使用它
第 3 步:Svelte 5 runes API
只使用 runes。 绝不使用旧式 export let、let x = 0 响应式语法或 $: 标签。
属性
<script lang="ts">
interface Props {
title: string
description?: string
onAction?: () => void
}
// $props() replaces export let
const { title, description = 'Default text', onAction }: Props = $props()
</script>
响应式状态
<script lang="ts">
// $state() replaces let count = 0
let count = $state(0)
let isOpen = $state(false)
// $derived() replaces $: doubled = count * 2
const doubled = $derived(count * 2)
// $effect() replaces onMount / afterUpdate for side effects
$effect(() => {
console.log('count changed:', count)
})
</script>
事件处理
<button onclick={() => count++}>Increment</button>
<button onclick={onAction}>Custom action</button>
步骤 4:使用设计令牌的作用域 CSS
Svelte 默认会将 CSS 限定在组件作用域内——请充分利用这一特性。按以下顺序从源文件中解析颜色,然后将其映射到 :root 中的自定义属性(通过 +layout.svelte 或 app.css),并在各组件中引用:
<head>中的内联tailwind.config(Stitch 生成的内容)——如果存在,直接使用。- 源文件中已有的 CSS 自定义属性(
:root { --color-primary: ... })——手写和模板化 HTML 中很常见。 - 外链或内联样式表——解析其中声明的颜色、字体系列、圆角和间距。
- 最后手段——根据标记中出现频率最高的计算值推导令牌(主导背景色、文本颜色、强调色、标题/正文字体、圆角),并告知用户你的推断,以便他们进行修正。
URL 路由只会下载单个 HTML 响应——外链样式表可能不会一并下载。如果以上方式都无法确定某个令牌,请如实说明,不要凭空编造调色板。
在 src/app.css 中(全局):
:root {
--color-background: #ffffff;
--color-surface: #f4f4f5;
--color-primary: /* dominant color from the source */;
--color-primary-foreground: #ffffff;
--color-text: #09090b;
--color-text-muted: #71717a;
--color-border: #e4e4e7;
}
[data-theme='dark'] {
--color-background: #09090b;
--color-surface: #18181b;
--color-primary: /* same hue, adjusted for dark bg */;
--color-primary-foreground: #09090b;
--color-text: #fafafa;
--color-text-muted: #a1a1aa;
--color-border: #27272a;
}
在各组件中(作用域内):
<style>
.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
border-radius: 0.5rem;
padding: 1.5rem;
}
.card:hover {
/* Scoped — won't leak to parent or children */
border-color: var(--color-primary);
}
</style>
深色模式切换——在 +layout.svelte 中添加一个 $state:
<script lang="ts">
let theme = $state<'light' | 'dark'>('light')
function toggleTheme() {
theme = theme === 'light' ? 'dark' : 'light'
document.documentElement.setAttribute('data-theme', theme)
}
</script>
<svelte:element this="div" data-theme={theme}>
{@render children()}
</svelte:element>
步骤 5:内置过渡和动画
Svelte 原生支持过渡效果。根据源设计中的动效意图应用以下效果:
<script lang="ts">
import { fade, fly, slide, scale } from 'svelte/transition'
import { cubicOut } from 'svelte/easing'
let show = $state(false)
</script>
<div transition:fade={{ duration: 200 }}>
Content that fades in
</div>
{#if isOpen}
<aside transition:fly={{ x: -300, duration: 300, easing: cubicOut }}>
Sidebar content
</aside>
{/if}
{#if expanded}
<div transition:slide={{ duration: 200 }}>
Expandable content
</div>
{/if}
始终遵循减少动态效果的设置:
<script lang="ts">
// Check user preference once
const prefersReducedMotion = $state(
typeof window !== 'undefined'
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
: false
)
// Conditionally disable transitions
const transitionOptions = $derived(
prefersReducedMotion ? {} : { duration: 200 }
)
</script>
<div transition:fade={transitionOptions}>...</div>
步骤 6:Svelte 中的无障碍访问
Svelte 编译器会针对缺少无障碍属性发出警告——请将所有编译器警告视为错误。
role和 ARIA:使用非语义元素时添加role。始终同时添加aria-label或aria-labelledby。bind:this:用于程序化焦点管理(例如模态框中的焦点陷阱)。- 键盘处理器:非交互元素上的任何
onclick处理器都需要同时添加onkeydown/onkeyup,或者改用<button>。 - 屏幕阅读器文本:使用
class="sr-only"(在 app.css 中定义)设置视觉隐藏的标签。
<button
onclick={closeModal}
aria-label="Close dialog"
class="icon-btn"
>
<CloseIcon />
</button>
<dialog
bind:this={dialogEl}
aria-labelledby="dialog-title"
aria-modal="true"
>
<h2 id="dialog-title">{title}</h2>
</dialog>
步骤 7:执行步骤
- 环境检查——如果缺少
node_modules,运行npm install。 - 数据层——根据设计内容创建
src/lib/data/mockData.ts。 - 组件起草——以
resources/component-template.svelte为基础。将所有StitchComponent替换为实际的组件名称。 - CSS 令牌——将颜色令牌添加到
src/app.css。如果使用stitch-design-system,则改为导入其生成的design-tokens.css。 - 接线——更新
src/routes/+page.svelte,导入并使用新组件。从$lib/components/导入。 - 质量检查——按照
resources/architecture-checklist.md逐项检查。 - 开发验证——运行
npm run dev。切换深色模式。测试键盘导航。
故障排除
| 问题 | 修复方法 |
|---|---|
| Runes 语法错误 | 确认 package.json 中有 svelte: ^5。旧语法在 Svelte 5 中无效。 |
$props() 类型错误 | 在 <script> 标签中添加 lang="ts" |
| CSS 未限定作用域 | 确保样式位于 <style> 块内,而不是通过 .css 导入 |
| 过渡效果未播放 | 检查 prefers-reduced-motion 是否导致配置为空 |
$lib 无法解析 | 确认 tsconfig.json 中有 "paths": {"$lib/*": ["src/lib/*"]} |
| 加载时深色模式闪烁 | 在同步的 <svelte:head> 脚本中从 localStorage 读取主题 |
与其他技能集成
- stitch-design-system——先运行,以生成用于 CSS 变量基础的
design-tokens.css。 - stitch-animate——之后运行,以获取超出上述基础内容的 Svelte 专用过渡模式。
- stitch-a11y——之后运行;当设计中包含复杂 UI 模式时,用于进行完整的无障碍审计。
参考资料
resources/component-template.svelte——可用于生产环境的 Svelte 5 组件样板resources/architecture-checklist.md——发布前质量检查清单scripts/fetch-stitch.sh——可靠的 GCS HTML 下载器