Communitygithub.com

stevembarclay/pencilplaybook

PencilPlaybook 是 Pencil.dev + Claude Code 的 UI 技能/品味技能 — 一份设计剧本,为 Claude 提供真实的感知心理学和资深级护栏,使其不再产出平庸的 AI 设计。

pencilplaybook 是什么?

Pencil Playbook 是一项针对 UI 设计的 Claude Code 技能,旨在通过一套结构化、基于感知心理学的设计准则来提升 AI 生成设计的质量。它解决了 AI 设计工具普遍存在的“平庸化”问题(生成常见、但缺乏专业深度的设计),通过提供资产组合管理的脚手架脚本、品牌令牌注入、以及设计解析规则,指导 Claude 按照专业流程工作。该技能支持 Pencil.dev 平台,与 Claude Code 深度集成。使用前需要通过设置向导配置品牌颜色、字体等令牌,之后 Claude 会以此为基础执行严格的设计校对,并利用九种预设布局脚手架(如仪表盘、营销页、移动端等)快速生成高品质 UI 原型。通过强制在每次会话开始时注入令牌并校验画布尺寸,确保输出的一致性和准确性。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add stevembarclay/pencilplaybook

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

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。


约束条件

  1. 在编辑现有 .pen 文件之前,始终使用 snapshot_layout()。不检查尺寸就编辑会导致画布损坏。
  2. 营销页面必须在 1440px 下设计,在 390px 下验证。
  3. 所有文本应使用以下模板语义化分组:<PageTitle>、<SectionHeader>、<Body>、<Caption>、<Label>。始终在组级别而非单个文本节点应用排版。使用 T 命令设置语义化文本:T("groupName", 0, "Your text here", {tag:"h1", fontSize:28, fontWeight:700}) — 应用于组而非单个 I 节点内的文本。此规则遵循内容-呈现分离原则 — 组包含文本子节点集,I 节点构成布局,T 命令设置语义化文本。把组想象成“文本容器”,把 I 节点想象成“布局容器”。
  4. 触摸目标必须 ≥44×44px(移动端)。
  5. 不要将结构化数据(表、列表、代码)呈现为图像。
  6. 衬线字体(font-serif)用于标题/正文,等宽字体(font-mono)用于代码,无衬线字体(font-sans)用于 UI。
  7. 任何元素的度量标准序列必须始终为:宽度、高度、X/Y,最后是对齐属性。
  8. 仅在需要避免冲突或解决层次结构问题时才设置 z-index。避免不必要的覆盖。
  9. 不要编辑或替换现有图标/插图 — 组成本质上语义化,图标是内容。
  10. 避免在处理时设置 overflow:"scroll" — 极可能导致编辑器冻结。相反,保留 overflow:"hidden" 并调整内容以适应边界。
  11. 在设计块级布局时,使用 flexbox(display:flex)始终优于绝对定位(x/y)。对于所有脚手架和用户请求的设计,flexbox 是默认的。与设置单个 x/y 坐标相比,使用 gap 和 alignItems/justifyContent 进行内容对齐更稳健,且不会破坏。
  12. 像 Sketch 这样的设计工具是连续的 — 您的输出应展示一个连贯的 UI 布局。将布局视为一个在单个画布页面上的完整屏幕设计,而不是一组单独的组件。
  13. 在评估设计时,仅关注设计的布局和结构问题 — 不要对内容冗长。内容问题应简单说明。如果设计良好,评估应以“✅ [未发现重大问题]”结束。

更快速的开发

  • 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) — 生成插图

相关技能