关于 wireframe-generator
wireframe-generator 是一项为 LLM 提供 Wire DSL 语法与组件参考的技能,用于生成线框图和交互式 UI 原型代码。它涵盖布局、事件与校验规则,适合将界面需求转换为完整的 .wire 文件。
主要功能
- 01Wire DSL 语法与语法规则
- 0230 种组件目录
- 03多种布局容器模式
- 04交互事件与动作规则
- 05代码生成校验清单
适用场景
- 01生成线框原型 .wire 文件
- 02将 UI 需求转换为 DSL 代码
- 03制作带点击交互的流程
- 04构建多屏表单或仪表板
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wire-dsl/ wire-dsl --skill wireframe-generator安装后在 Claude Code 中输入/wireframe-generator确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/best-practices.mdcommon-patterns.mdcomponents-catalog.mdcore-syntax.mdlayouts-guide.md详细介绍
Wire DSL 代码生成器
为线框图和交互式 UI 原型生成语法正确的 Wire DSL 代码。
此技能的作用
此技能通过提供以下内容,让 LLM 能够生成有效且最新的 Wire DSL:
- 完整的语法参考和语法规则
- 全部 30 种可用组件的目录
- 布局容器模式(stack、grid、split、panel、card、tabs、modal)
- 代码生成最佳实践
- play test 使用的事件和交互规则
与分支同步的更改
此技能已针对 feature/add-event-system 中的更改进行更新,包括:
- 支持组件和布局事件处理程序的事件系统
- 新增操作:
enable(id)和disable(id)(以及navigate、show、hide、toggle、setTab) - 新增布局:
layout tabs(...)和layout modal(...) component Modal替换为layout modal(...)component Tabs现在支持initialActive和tabsIdlayout card(...)支持onClickCheckbox、Radio和Toggle支持clickable: false,用于非交互式渲染
何时使用此技能
在以下情况下使用此技能:
- 为线框图原型生成
.wire文件 - 使用声明式语法创建 UI 模型
- 为 play test 流程添加可点击交互
- 构建多屏应用线框图
- 设计表单、仪表板、产品目录或管理界面
- 将 UI 需求转换为 Wire DSL 代码
核心概念
结构: 每个 Wire DSL 文件都遵循以下层级结构:
project -> [style|colors|mocks|define] -> screen -> layout -> children
语法风格: 使用带花括号的块声明式语法,类似于 CSS/HCL:
project "App Name" {
style { ... } // optional
screen ScreenName {
layout <type> { ... }
}
}
关键规则:
- 字符串值必须加引号:
text: "Hello" - 数字、布尔值和枚举值不加引号:
height: 200、checked: true、variant: primary - 属性格式:
key: value - 注释:单行注释使用
//,块注释使用/* */
代码生成说明
第 1 步:从项目结构开始
先编写项目包装结构。style 块为可选项。省略时将应用默认值(density: "normal"、spacing: "md"、radius: "md"、stroke: "normal"、font: "base")。
project "Project Name" {
style {
density: "compact" // compact | normal | comfortable
radius: "lg" // none | sm | md | lg | full
}
// screens go here
}
第 2 步:创建屏幕
每个屏幕代表应用中的一个独立视图:
screen ScreenName {
layout <type> {
// content
}
}
命名: 屏幕名称使用大驼峰命名法(例如:UsersList、ProductDetail、Dashboard)。
第 3 步:选择布局容器
根据 UI 结构选择合适的布局:
| 布局 | 使用场景 | 子项 | 示例 |
|---|---|---|---|
| stack | 线性排列 | 多个 | 表单、列表、垂直/水平分区 |
| grid | 多列(12 列) | 单元格 | 仪表板、产品网格、响应式布局 |
| split | 双列区域 | 恰好 2 个 | 管理面板、导航 + 内容 |
| panel | 带边框的容器 | 恰好 1 个 | 突出显示的分区、表单组 |
| card | 内容卡片 | 多个 | 产品卡片、用户资料、信息框 |
| tabs | 选项卡内容面板 | tab 块 | 设置页面、个人资料选项卡、分步流程 |
| modal | 覆盖层对话框 | 多个(或 body/footer) | 确认对话框和表单对话框 |
第 4 步:添加组件
从按 8 个类别组织的 30 种可用组件中选择:
文本: Heading、Text、Label、Paragraph、Code
输入: Input、Textarea、Select、Checkbox、Radio、Toggle
操作: Button、IconButton、Link
导航: Topbar、SidebarMenu、Sidebar、Breadcrumbs、Tabs
数据: Table、List、Stat、Chart
媒体: Image、Icon
布局: Card、Divider、Separate
反馈: Badge、Alert
步骤 5:添加事件和操作(按需)
事件是用于播放测试交互的元数据。
支持的事件属性:
onClick:Button、IconButton、Link 和layout card(...)onChange或onActive+onInactive:Toggle、Checkbox、RadioonItemsClick:SidebarMenuonItemClick:ListonRowClick:TableonClose:layout modal(...)
支持的操作:
navigate(ScreenName)show(id)/hide(id)/toggle(id)enable(id)/disable(id)setTab(tabsId, index)- 自身定位请使用
self:hide(self)、show(self)、toggle(self)、enable(self)、disable(self)
操作链:
component Button text: "Delete"
onClick: hide(listModal) & show(confirmModal) & disable(submitBtn)
步骤 6:输出前进行验证
输出前,请检查:
- 所有字符串都带有引号
- 数字、布尔值和枚举值都未加引号
- 所有大括号都已闭合
- 必需属性均已提供
- 组件名称完全匹配(区分大小写)
- Split 有 2 个子项,Panel 有 1 个子项
- Grid 单元格的
span值有效(1-12) tabsId指向同一屏幕中现有的layout tabs(id: ...)show/hide/toggle/enable/disable的目标存在于同一屏幕中(或使用self)onChange未与onActive/onInactive组合使用layout modal(...)未将body/footer区段与直接子项混用
参考文件
| 文件 | 用途 |
|---|---|
| ../../docs/DSL-SYNTAX.md | 当前语言语法和事件规则 |
| ../../docs/COMPONENTS-REFERENCE.md | 当前组件属性和事件支持 |
| ../../docs/CONTAINERS-REFERENCE.md | 当前布局/容器规则(tabs、modal、card onClick) |
| ../../specs/VALIDATION-RULES.md | 事件、模态框和语义验证规则 |
| core-syntax.md | 技能内语法摘要 |
| components-catalog.md | 技能内组件目录 |
| layouts-guide.md | 技能内布局指南 |
| best-practices.md | 验证清单、常见错误和注意事项 |
| common-patterns.md | 表单、仪表板、导航和卡片的可复用模式 |
示例
示例 1:交互式模态框 + 启用/禁用
project "Confirm Action" {
style {
density: "normal"
spacing: "md"
radius: "md"
stroke: "normal"
font: "base"
}
screen Main {
layout stack(direction: vertical, gap: md, padding: lg) {
component Input id: reasonInput label: "Reason" disabled: true
component Checkbox label: "I understand the consequences"
onActive: enable(reasonInput) & enable(deleteBtn)
onInactive: disable(reasonInput) & disable(deleteBtn)
component Button id: deleteBtn text: "Delete Item" variant: danger disabled: true
onClick: show(confirmDelete)
layout modal(id: confirmDelete, title: "Delete item?", visible: false, onClose: hide(self)) {
body {
component Text text: "This action cannot be undone."
}
footer {
component Button text: "Cancel" variant: secondary onClick: hide(self)
component Button text: "Confirm Delete" variant: danger onClick: hide(self)
}
}
}
}
}
示例 2:与 Tabs 布局关联的标签页
project "Profile Settings" {
style {
density: "normal"
spacing: "md"
radius: "md"
stroke: "normal"
font: "base"
}
screen Settings {
layout stack(direction: vertical, gap: md, padding: lg) {
component Tabs items: "Profile,Security,Billing" initialActive: 0 tabsId: settingsTabs
layout tabs(id: settingsTabs) {
tab {
component Heading text: "Profile"
component Input label: "Full name"
component Input label: "Email"
}
tab {
component Heading text: "Security"
component Toggle label: "Two-factor auth"
component Button text: "Go Billing" onClick: setTab(settingsTabs, 2)
}
tab {
component Heading text: "Billing"
component Table columns: "Date,Amount,Status" rows: 4
}
}
}
}
}
示例 3:可点击卡片 + 侧边栏导航
project "Admin" {
style {
density: "normal"
spacing: "md"
radius: "md"
stroke: "normal"
font: "base"
}
define Component "MainMenu" {
layout stack(direction: vertical, gap: md, padding: md) {
component SidebarMenu items: "Dashboard,Users,Settings"
onItemsClick: "DashboardScreen,UsersScreen,SettingsScreen"
active: prop_active
}
}
screen DashboardScreen {
layout split(left: 260, gap: md) {
component MainMenu active: 0
layout grid(columns: 12, gap: md, padding: md) {
cell span: 6 {
layout card(padding: md, gap: md, onClick: navigate(UsersScreen)) {
component Heading text: "Users"
component Text text: "Open users section"
}
}
}
}
}
screen UsersScreen {
layout split(left: 260, gap: md) {
component MainMenu active: 1
layout stack(direction: vertical, gap: md, padding: lg) {
component Heading text: "Users"
}
}
}
screen SettingsScreen {
layout split(left: 260, gap: md) {
component MainMenu active: 2
layout stack(direction: vertical, gap: md, padding: lg) {
component Heading text: "Settings"
}
}
}
}
快速提示
默认内边距: 布局的默认内边距为 0px。请显式添加 padding。
网格系统: 12 列网格。cell span 必须为 1-12。
ID: 使用有效标识符:[a-zA-Z_][a-zA-Z0-9_]*。
CSV 列表: 使用带引号的逗号分隔字符串:items: "Home,Users,Settings"。
标签页关联: component Tabs tabsId: X 必须与同一屏幕中的 layout tabs(id: X) 匹配。
模态框模型: 使用 layout modal(...),而非 component Modal。
布尔控件: Checkbox、Radio 和 Toggle 支持在需要时设置 clickable: false。
应避免的常见错误
- 忘记给字符串加引号:
text: Hello->text: "Hello" - 给数字/枚举值加引号:
rows: "8"->rows: 8 - 组件大小写错误:
button->Button - 使用
component Modal-> 应使用layout modal(...) - 缺少
tabsId或与之匹配的layout tabs(id: ...) - 在 Tabs 上将
active用作设计时默认值 -> 优先使用initialActive - 在同一控件上混用
onChange和onActive/onInactive - 在
show/hide/toggle/enable/disable中引用未知 ID - Split 包含 3 个子项 -> 必须恰好有 2 个
- Panel 包含多个子项 -> 必须恰好有 1 个
- 在同一模态框中混用
body/footer与直接子项
输出指南
生成 Wire DSL 代码时:
- 输出前始终验证语法
- 返回完整、可运行的
.wire文件(而非部分代码片段) - 使用真实的名称和数据
- 确保组件名称和属性名称准确无误
- 明确设置布局间距(
gap、padding) - 对于交互流程,确保 wire ID 和事件保持一致
- 仅在有助于说明不明显的结构时使用注释
交互示例代码片段
layout stack(direction: vertical, gap: md, padding: md) {
component Input id: nameInput label: "Name" disabled: true
component Button text: "Unlock" onClick: enable(nameInput)
component Button text: "Lock" onClick: disable(nameInput)
component Button text: "Open confirm" onClick: show(confirmModal)
layout modal(id: confirmModal, title: "Confirm?", visible: false, onClose: hide(confirmModal)) {
body {
layout stack(direction: vertical, padding: sm) {
component Text text: "Proceed?"
}
}
footer {
layout stack(direction: vertical, padding: sm) {
component Button text: "Close" onClick: hide(confirmModal)
}
}
}
}