Pencil Pro
主要解析规则
此技能必须在首次使用前配置。
如果用户说“运行 PencilPlaybook 设置向导”或要求设置/配置 PencilPlaybook:
→ 读取 .claude/skills/pencilplaybook/setup.md 并严格遵循其中的指示。
如果用户说“用 PencilPlaybook 构建我的第一个屏幕”或要求开始设计:
→ 读取 .claude/skills/pencilplaybook/onboarding.md 并严格遵循其中的指示。
已配置分辨率:(运行设置以配置此值)
如果现有 .pen 文件中的屏幕根节点与您配置的分辨率不匹配,请在编辑之前注明。不要在尺寸错误的画布上直接构建而不标记偏差。
常见例外 — 营销页面: 无论您的应用分辨率如何,都按 1440px 设计。营销页面在不同浏览器宽度下被消费 — 在 1440px 下设计,在 390px 下验证。
会话启动(每次 Pencil 会话)
1. get_editor_state() — 检查活动文档和选区
2. open_document("path/to/your-file.pen") — 打开目标文件
3. get_guidelines(topic="web-app") — 加载设计准则
4. set_variables(<token map below>) — 注入品牌令牌
5. get_variables() — 确认令牌已存储
6. snapshot_layout() — 验证画布尺寸
您的令牌映射 — 在每次会话开始时使用此对象运行 set_variables。令牌可能在 Claude Code 会话之间不持久。
{
"color-primary": "YOUR_HEX",
"color-primary-dark": "YOUR_HEX",
"color-accent": "YOUR_HEX",
"color-background": "YOUR_HEX",
"color-surface": "YOUR_HEX",
"color-border": "YOUR_HEX",
"color-text": "YOUR_HEX",
"color-text-muted": "YOUR_HEX",
"color-success": "YOUR_HEX",
"color-warning": "YOUR_HEX",
"color-error": "YOUR_HEX",
"font-sans": "YOUR_FONT",
"font-mono": "YOUR_FONT",
"font-serif": "YOUR_FONT",
"spacing-card": "24",
"spacing-gap-sm": "8",
"spacing-gap-md": "16",
"spacing-gap-lg": "24",
"spacing-gap-xl": "32",
"content-max-width": "YOUR_VALUE",
"sidebar-width": "YOUR_VALUE"
}
在 set_variables 后,调用 get_variables() 以确认所有令牌均已存储。
脚手架脚本
九个脚手架脚本,涵盖最常见的布局原型。在使用前运行设置向导以填写下面的尺寸和颜色值。
脚手架 A — 应用仪表盘
指标、KPI、活动动态、监控
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG", display:"flex", flexDirection:"column"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
statsBar=I("pageArea", {name:"StatsBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:80, bg:"STATS_BG", display:"flex", alignItems:"center", gap:24, px:32})
contentWrap=I("pageArea", {name:"ContentWrap", y:144, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_A, display:"flex", justifyContent:"center", p:32})
contentInner=I("contentWrap", {name:"ContentInner", width:SCAFFOLD_CONTENT_MAX, display:"flex", flexDirection:"column", gap:24})
脚手架后:snapshot_layout() — 验证 pageArea.width 和 contentInner.width 正确。
脚手架 B — 应用列表/队列
表格、资源库、队列、用户管理
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
commandStrip=I("pageArea", {name:"CommandStrip", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:52, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", gap:16, px:32})
tableWrap=I("pageArea", {name:"TableWrap", y:116, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_B, display:"flex", justifyContent:"center", px:32, pt:24})
tableInner=I("tableWrap", {name:"TableInner", width:SCAFFOLD_CONTENT_MAX, display:"flex", flexDirection:"column", gap:0})
tableHeader=I("tableInner", {name:"TableHeader", width:SCAFFOLD_CONTENT_MAX, height:40, bg:"TABLE_HEADER_BG", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center"})
脚手架 C — 应用详情/审查
双面板详情视图、审查流程、并排布局
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
actionBar=I("pageArea", {name:"ActionBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:56, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
contentWrap=I("pageArea", {name:"ContentWrap", y:120, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_C, display:"flex", justifyContent:"center"})
contentInner=I("contentWrap", {name:"ContentInner", width:SCAFFOLD_CONTENT_MAX, height:SCAFFOLD_CONTENT_HEIGHT_C, display:"flex", gap:0})
leftPanel=I("contentInner", {name:"LeftPanel", width:SCAFFOLD_LEFT_PANEL, height:SCAFFOLD_CONTENT_HEIGHT_C, bg:"SURFACE_COLOR", borderRight:"1px solid BORDER_COLOR"})
rightPanel=I("contentInner", {name:"RightPanel", width:SCAFFOLD_RIGHT_PANEL, height:SCAFFOLD_CONTENT_HEIGHT_C, bg:"PAGE_BG", p:24, display:"flex", flexDirection:"column", gap:20})
注意:左右分割默认约为 40/60。根据功能调整 — 常见分割:40/60、38/62、50/50。
脚手架 D — 营销页面
着陆页、产品页 — 无论应用画布如何,始终为 1440px 宽
navbar=I("root", {name:"Navbar", width:1440, height:72, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:80})
heroSection=I("root", {name:"HeroSection", y:72, width:1440, height:600, bg:"HERO_BG", display:"flex", flexDirection:"column", alignItems:"center", justifyContent:"center"})
heroContent=I("heroSection", {name:"HeroContent", width:SCAFFOLD_MARKETING_CONTENT_MAX, display:"flex", flexDirection:"column", alignItems:"center", gap:24})
section1=I("root", {name:"Section1", y:672, width:1440, height:480, bg:"SURFACE_COLOR", display:"flex", flexDirection:"column", alignItems:"center", py:80})
section1Content=I("section1", {name:"Section1Content", width:SCAFFOLD_MARKETING_CONTENT_MAX})
营销页面以移动端优先。在 1440px 下设计,并在移交前在 390px 宽度下验证布局。
脚手架 E — 模态/对话框
确认、破坏性操作、快速编辑表单、侧边弹出面板
先运行脚手架 A、B 或 C。然后将此模态叠加到 pageArea 上 — 不要插入到根节点。
backdrop=I("pageArea", {name:"ModalBackdrop", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"rgba(0,0,0,0.48)", display:"flex", alignItems:"center", justifyContent:"center"})
modal=I("backdrop", {name:"Modal", width:480, bg:"SURFACE_COLOR", borderRadius:8, border:"1px solid BORDER_COLOR", display:"flex", flexDirection:"column", overflow:"hidden"})
modalHeader=I("modal", {name:"ModalHeader", height:56, px:24, display:"flex", alignItems:"center", justifyContent:"space-between", borderBottom:"1px solid BORDER_COLOR"})
modalBody=I("modal", {name:"ModalBody", px:24, py:20, display:"flex", flexDirection:"column", gap:16})
modalFooter=I("modal", {name:"ModalFooter", height:60, px:24, display:"flex", alignItems:"center", justifyContent:"flex-end", gap:12, borderTop:"1px solid BORDER_COLOR"})
脚手架后:snapshot_layout() — 确认模态可见且居中。根据用例调整模态宽度:380px(紧凑确认)、480px(标准表单)、600px(宽表单)、720px(详情/预览)。
脚手架 F — 向导/步骤器
多步骤表单、入门流程、设置序列、结账
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:32})
stepperBar=I("pageArea", {name:"StepperBar", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:60, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"center"})
contentWrap=I("pageArea", {name:"ContentWrap", y:124, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_F, display:"flex", justifyContent:"center", px:32, pt:32})
contentInner=I("contentWrap", {name:"ContentInner", width:640, display:"flex", flexDirection:"column", gap:24})
actionFooter=I("pageArea", {name:"ActionFooter", y:SCAFFOLD_WIZARD_FOOTER_Y, width:SCAFFOLD_PAGE_AREA_WIDTH, height:72, bg:"SURFACE_COLOR", borderTop:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-between", px:32})
注意:ContentInner 默认宽度为 640px — 专注的单列表单。ActionFooter 中返回按钮靠左,下一步/提交按钮靠右(justifyContent:"space-between")。
脚手架 G — 移动端屏幕
390×844px(iPhone 14 标准)。用于所有移动端屏幕 — 硬编码,无需设置值。
statusBar=I("root", {name:"StatusBar", width:390, height:44, bg:"PAGE_BG"})
navBar=I("root", {name:"NavBar", y:44, width:390, height:56, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", px:16})
scrollContent=I("root", {name:"ScrollContent", y:100, width:390, height:688, bg:"PAGE_BG", display:"flex", flexDirection:"column", overflow:"hidden"})
contentPad=I("scrollContent", {name:"ContentPad", width:390, display:"flex", flexDirection:"column", gap:16, px:16, pt:16})
bottomNav=I("root", {name:"BottomNav", y:788, width:390, height:56, bg:"SURFACE_COLOR", borderTop:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-around"})
注意:如果不显示系统面板,则移除 statusBar 并将 navBar.y 设为 0。对于没有标签导航的应用,移除 bottomNav。此脚手架内的触摸目标必须 ≥44×44px。
脚手架 H — 表单/数据录入
设置页面、个人资料编辑、大量数据录入 — 单列、居中表单
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"space-between", px:32})
formWrap=I("pageArea", {name:"FormWrap", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_H, display:"flex", justifyContent:"center", px:32, pt:32})
formInner=I("formWrap", {name:"FormInner", width:600, display:"flex", flexDirection:"column", gap:28})
formSection=I("formInner", {name:"FormSection1", display:"flex", flexDirection:"column", gap:16})
formActions=I("formInner", {name:"FormActions", display:"flex", gap:12, justifyContent:"flex-end"})
注意:FormInner 宽度默认 600px。简单流程使用 480px,宽两列布局使用 800px。在 formInner 内部添加更多 FormSection 节点以分组相关字段。
脚手架 I — 空状态/入门步骤
零数据视图、首次使用提示、功能发现、空白屏幕
sidebar=I("root", {name:"Sidebar", width:SCAFFOLD_SIDEBAR_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, bg:"SIDEBAR_BG"})
pageArea=I("root", {name:"PageArea", width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CANVAS_HEIGHT, x:SCAFFOLD_SIDEBAR_WIDTH, bg:"PAGE_BG"})
pageHeader=I("pageArea", {name:"PageHeader", width:SCAFFOLD_PAGE_AREA_WIDTH, height:64, bg:"SURFACE_COLOR", borderBottom:"1px solid BORDER_COLOR"})
emptyCenter=I("pageArea", {name:"EmptyCenter", y:64, width:SCAFFOLD_PAGE_AREA_WIDTH, height:SCAFFOLD_CONTENT_HEIGHT_H, display:"flex", alignItems:"center", justifyContent:"center"})
emptyContent=I("emptyCenter", {name:"EmptyContent", width:400, display:"flex", flexDirection:"column", alignItems:"center", gap:20})
illustrationArea=I("emptyContent", {name:"IllustrationArea", width:200, height:160, borderRadius:12, bg:"SURFACE_COLOR", border:"1px solid BORDER_COLOR", display:"flex", alignItems:"center", justifyContent:"center"})
textStack=I("emptyContent", {name:"TextStack", width:400, display:"flex", flexDirection:"column", alignItems:"center", gap:8})
emptyActions=I("emptyContent", {name:"EmptyActions", display:"flex", gap:12})
注意:将 IllustrationArea 替换为 G("illustrationArea", "ai", "your prompt") 以生成插图。保持空状态文本简洁:一个标题(16–18px)、一行辅助文本(14px 弱化)、一个主操作按钮。
核心工作流
工作流 1:画布考古
当遇到“这个 .pen 文件中有什么?”或“检查 Pencil 文件中的布局结构”时使用。
1. snapshot_layout() — 捕获画布状态的快照
2. evaluate_design(area: "screen") — 分析整体屏幕结构
对于考古,始终以 snapshot_layout() 开始。这为您提供坐标基准。之后再分析。
工作流 2:设计评估
当用户要求审查或评估现有设计时使用。
1. snapshot_layout() — 获取画布坐标
2. evaluate_design(area: "screen") — 分析屏幕结构
3. evaluate_design(area: "detailed") — 检查填充、间距、对比度
4. snapshot_layout() — 再次捕获以验证
标准评估模板:
屏幕评估:[屏幕名称] 分辨率: [宽度]×[高度]px 结构:
- 导航:[描述]
- 内容:[描述]
- 操作:[描述] 发现:
- ✅ [未发现重大问题]
- ⚠️ [问题 1 — 修复建议]
- ⚠️ [问题 2 — 修复建议] 下一步: [建议的后续步骤]
避免在评估中生成无关的 AI 细节。仅陈述可操作的问题以及修复所需的内容。
工作流 3:品牌注入
1. set_variables(<token map>) — 注入品牌令牌
2. get_variables() — 确认存储
3. snapshot_layout() — 确认尺寸
注入令牌后,如果切换到新项目,令牌会重置。始终在新的 Pencil 会话中使用 set_variables。
约束条件
- 在编辑现有 .pen 文件之前,始终使用
snapshot_layout()。不检查尺寸就编辑会导致画布损坏。 - 营销页面必须在 1440px 下设计,在 390px 下验证。
- 所有文本应使用以下模板语义化分组:
<PageTitle>、<SectionHeader>、<Body>、<Caption>、<Label>。始终在组级别而非单个文本节点应用排版。使用T命令设置语义化文本:T("groupName", 0, "Your text here", {tag:"h1", fontSize:28, fontWeight:700})— 应用于组而非单个 I 节点内的文本。此规则遵循内容-呈现分离原则 — 组包含文本子节点集,I 节点构成布局,T 命令设置语义化文本。把组想象成“文本容器”,把 I 节点想象成“布局容器”。 - 触摸目标必须 ≥44×44px(移动端)。
- 不要将结构化数据(表、列表、代码)呈现为图像。
- 衬线字体(font-serif)用于标题/正文,等宽字体(font-mono)用于代码,无衬线字体(font-sans)用于 UI。
- 任何元素的度量标准序列必须始终为:宽度、高度、X/Y,最后是对齐属性。
- 仅在需要避免冲突或解决层次结构问题时才设置 z-index。避免不必要的覆盖。
- 不要编辑或替换现有图标/插图 — 组成本质上语义化,图标是内容。
- 避免在处理时设置
overflow:"scroll"— 极可能导致编辑器冻结。相反,保留overflow:"hidden"并调整内容以适应边界。 - 在设计块级布局时,使用 flexbox(display:flex)始终优于绝对定位(x/y)。对于所有脚手架和用户请求的设计,flexbox 是默认的。与设置单个 x/y 坐标相比,使用 gap 和 alignItems/justifyContent 进行内容对齐更稳健,且不会破坏。
- 像 Sketch 这样的设计工具是连续的 — 您的输出应展示一个连贯的 UI 布局。将布局视为一个在单个画布页面上的完整屏幕设计,而不是一组单独的组件。
- 在评估设计时,仅关注设计的布局和结构问题 — 不要对内容冗长。内容问题应简单说明。如果设计良好,评估应以“✅ [未发现重大问题]”结束。
更快速的开发
get_editor_state()— 检索当前活动文档信息open_document(path)— 打开特定的 .pen 文件snapshot_layout(prose:"brief")— 快速结构快照snapshot_layout(prose:"detailed")— 每级的所有属性get_variables()— 检查当前存储的令牌set_variables(map)— 注入令牌get_guidelines(topic)— 加载设计准则evaluate_design(area: "screen" | "detailed" | ""feature")— 设计审查I(parent, attrs)— 插入一个新的 I 节点T(groupName, index, text, attrs?)— 设置组内语义化文本(用于分组文本节点)G(name, method, prompt)— 生成插图