DSH OpenPencil

DSH OpenPencil

OpenPencil 的 DeepSeek Harness 插件 —— 在对话中预览、检查并编辑真实的 .op 文档。
精确多帧预览 • 交互式画布 • 托管编辑器 • 智能体原生设计工具

npm: @zseven-w/dsh-openpencil · 当前插件版本:0.1.0-rc.14 · 编辑器面板已在 DSH 桌面版 0.2.1-rc.3 验证

English · 简体中文 · 繁體中文 · 日本語 · 한국어 · Français · Español · Deutsch · Português · Русский · हिन्दी · Türkçe · ไทย · Tiếng Việt · Bahasa Indonesia

npm CI Stars License Discord


DSH OpenPencil —— 多帧预览与侧边栏编辑器

带交互式画布与托管编辑器工作台的精确多帧 .op 预览

## 为什么选择 DSH OpenPencil DSH OpenPencil 将 [DeepSeek Harness](https://github.com/deepseek-ai/DSH) 与 [OpenPencil](https://github.com/ZSeven-W/openpencil) 连接起来,让智能体(Agent)驱动一个真实、可编辑、可交互的设计画布,而不是返回一张生成的图片。
### 🖼️ 精确多帧预览 已安装的 OpenPencil 无头导出器会渲染忠实于设计的预览:第一个顶层帧以大型可回放 PNG 呈现,另有一条可水平滚动的缩略图栏,支持点击选择以及多帧文档的上一个/下一个导航。 ### 🗺️ 交互式画布 「打开交互式画布」会按需挂载只读的 OpenPencil Web SDK,支持平移、缩放与适应视图 —— 无需离开对话即可检查任意页面、嵌套节点或非活动页面。
### ✏️ 托管编辑器 启用 `editable: true` 后,编辑操作会打开托管的 OpenPencil 编辑器 —— 包含选择、图层、属性、绘图工具、撤销/重做以及明确的保存语义 —— 呈现在一个可调整大小的右侧工作台中,并支持全屏选项。 ### 🤖 智能体原生设计工具 五个直接操作画布的工具,加上六个 `openpencil_pipeline_*` 工具,让智能体能通过托管的 OpenPencil 运行时创建、检查、细化、发布、修改和读取真实画布。
### 🔐 能力门控授权 图像与文档授权是经过签名、与哈希绑定的能力凭据。浏览器元数据永远不会暴露任意的宿主机路径,签名的预览/编辑器能力也永远不会进入规范的工具结果或模型上下文。 ### ⚡ 事务性安全 完整管线中的文档会一直保留在私有、未发布的草稿中,直到通过全部原生与 DSH 质量门禁。发布绝不会覆盖已有路径,中止或批次失败也不会留下空的目标文件。
### 🌍 遵循 DSH 外观与风格 工具卡片与托管编辑器会跟随 DSH 的中文/英文语言环境以及浅色/深色主题,无需重新加载编辑会话。 ### 🎯 一个完整的工作流 「需求 → 私有草稿 → 语义化批次 → live 用户预览 → 确定性的结构/布局/质量校验 → 最终 PNG 完整性保护下的原子发布」—— 全部在 DSH 内完成闭环。
## 安装到 DSH DSH 是独立的包。若尚未安装,先装一次: ```sh npm install -g @deepseek-ai/dsh@latest ``` 然后把插件装进某个 profile 并启动 Web 应用: ```sh dsh plugin --profile web add @zseven-w/dsh-openpencil@latest dsh web ``` 插件目前仍处于预发布阶段,发布版本使用 npm 的 `latest` 标签;从 `latest` 安装即可获取当前版本。较旧的 `next` 标签已不是当前发布通道。 本地开发时,先构建当前检出目录,再把其绝对路径链接进 Web profile,随后完整重启 DSH: ```sh pnpm run build dsh plugin --profile web add link:/absolute/path/to/dsh-openpencil dsh web ``` `link:` 依赖会让后续重新构建的产物直接从当前检出目录生效;但替换 profile 依赖后必须完整重启 DSH,因为随附的 Web profile 默认不会热重载宿主插件包。 不想全局安装 DSH?用 `pnpm dlx` 跑同样的两步: ```sh pnpm dlx --package=@deepseek-ai/dsh@latest dsh plugin --profile web add @zseven-w/dsh-openpencil@latest pnpm dlx --package=@deepseek-ai/dsh@latest dsh web ``` > OpenPencil 插件是公开的,无需 npm token。如果 DSH 预发布版本本身需要 registry 身份验证,请将该凭据保存在仓库检出目录之外的用户级或临时 npm 配置中。本仓库刻意不包含任何 registry 凭据。 ## 设计工具 可选风格流程为 `openpencil_style_plan` → `openpencil_style_confirm` → `openpencil_pipeline_begin`,begin 保留原设计 brief,并传入 `style_selection`。目录浏览和精确选择无需模型推荐,推荐提供方默认关闭。该交接支持 script 引擎;app-agent 与电商风格交接暂不支持,普通 app-agent 生成入口保持可用。 | 工具 | 作用 | | --- | --- | | `openpencil_new` | 面向简单任务的兼容快速路径:运行一份事务性 QuickJS `batch_design` 脚本,以“仅在不存在时创建”的语义发布并返回可编辑呈现。生产级设计应优先使用下方完整管线。 | | `openpencil_pipeline_begin` | 启动仅归当前会话所有的私有草稿,在内部创建唯一 root,返回 `rootNodeId`、`continuationStyle` 与紧凑的运行时匹配构建契约,并立即在侧边栏打开同一个 live canvas;目标文件仍未发布。 | | `openpencil_pipeline_context` | 只在 begin 契约确实缺少某个指定 guideline、style、theme 或 UI kit 时加载一次定向上下文;不是启动时的固定步骤。 | | `openpencil_pipeline_batch` | 最多运行两段直接原生 `I(...)`/`K(...)` generation script:第一段严格执行 begin `next` 返回的有界首个可见视口脚本,第二段一次补齐全部剩余区域。展示第二次预览前会执行 authored-structure 门禁;空分类/商品 helper 会被拒绝并原子恢复第一批快照,只允许重发一次修正后的第二批,且不消耗两段式预算。每次成功事务只会尝试展示给用户的精确 PNG,随后必须不加叙述地立即执行返回的 `next`。第三段 generation script 会被拒;只有 finish 返回的完整修复门禁可以授权一段有界 `U(...)` QuickJS 修复脚本。 | | `openpencil_pipeline_inspect` | 仅在用户明确要求时提供手动诊断;普通生成不会把它当作预览或模型看图步骤。 | | `openpencil_pipeline_finish` | 健康状态下一次调用就完成最终化、验证、最终 root PNG 自动预览与 `createIfAbsent` 原子发布。只有结果同时为 `needs_correction`、`canContinue: true`、含完整非空 `repairTargets` 且 `omitted: 0` 时,才授权一次纯 `U(...)` 修复和最后一次 finish;其他未发布结果一律终止。 | | `openpencil_pipeline_abort` | 丢弃未发布草稿,不创建目标文件。 | | `openpencil_create` | 在现有的活动画布上应用事务性 `batch_design` 程序来生成或重构节点。 | | `openpencil_edit` | 修改显式指定的节点或用户选中的单个节点。 | | `openpencil_render` | 创建不可变、内容寻址的 `.op` 快照,并渲染活动页面上的每个顶层帧 —— 可选 `scale` 与 `editable` 参数。 | | `openpencil_selection` | 读取实时编辑器画布中当前选中的确切节点。 | ## 智能体设计工作流 ### 设计回合的模型档位 生成质量与驱动流水线回合的模型直接相关。两批次契约在快档模型上可以工作, 但排版判断、文案质量与契约遵从度在更强或开启推理的模型上有显著提升。 以设计为主的 profile 建议在 `agent-default-model` 中使用非 flash 档 (例如 `deepseek-v4` 并开启 `reasoningEffort`,替代 `deepseek-v4-flash`); 仅聊天为主、设计只是附带能力的 profile 可保留快档。 桌面电商 Hero 的几何结构会在第二批前验证:右侧每个视觉子节点和叠加形状都必须留在 Hero 的固定内宽高中。超大视觉会连同第一批原子回滚,不再撑大 live canvas 或流入最终发布。Generation receipt 只暴露已提交的节点映射与预览;原生诊断延后到 finish 聚合,由它一次给出精确修复事务,不再诱发生成中途的猜测循环。 普通一句话需求直接调用 `openpencil_pipeline_begin`,不再花一个模型步骤加载可选 skill,然后走固定短路径:严格执行 begin `next` 给出的有界第一段直接 JS → 第二段也是最后一段直接 JS,一次补齐全部剩余区域 → 一次 `openpencil_pipeline_finish`。当前第一批只渲染**首个可见视口**:按 brief 构建完整 navigation/header 与精修 primary hero/content,限制 **不超过 32 次 `I`/`K` 调用、脚本不超过 8 KiB**。这个预算保留真实结构与视觉层级,同时仍避免重新落入无界生成循环;次要 cards、detail 与 `below-fold` 内容延后到第二批。电商 begin 会在绘制前选定与 App 对齐的 `ecommerce-modern-light` 方案:白色基底、暖色区段节奏、克制的橙色操作色、1120px 居中内容、56px Hero 大标题,并让可见文案跟随用户需求语言(中文需求保持中文文案,只允许可选的简短 ASCII 品牌名)。桌面电商 Hero 是带 `padding:[64,160]` 的全宽水平 frame,内层严格由 512px 文案、64px 间距和 448px 商品视觉组成;禁止再把 Hero 固定为 1120px 后叠加这组 padding。标题和副标题均使用 `width:"fill_container"`。通用电商把主视觉直接挂在 Hero 下:`I(hero,{type:"image",name:"Hero product image",width:448,height:360,imageSearchQuery:"gray loveseat isolated photo"})`。`imageSearchQuery` 是节点的直接字段,禁止写成 `image:{...}`,禁止再套 wrapper、和装饰形状混用,或被任一商品卡复用;第一批提交后它会立即富化。只有用户明确要求插画或不使用照片时,才允许改用显式 `layout:"none"` 的 4–6 层定位构图,其中至少包含 ellipse/path。纯粹堆叠圆角矩形、空白右栏、溢出或过小装饰块都会在第二批前被门禁原子回滚。平台和 viewport 只从最近一条真实用户请求中确定;模型扩写的 `brief` 不能把未指定的平台擅自改成移动端。用户未指定品牌时,直接根据 brief 使用中性店铺名或简短占位,不花时间比较命名方案。未提供 logo asset 时只使用纯文本品牌;禁止发明字母徽章,也不要给 text node 添加背景、固定高度或 effects。begin 会创建唯一 root 并打开私有 live canvas;每次 begin 或 batch 成功后,都必须不加叙述、规划、比较、检查或无关工具调用地立即执行下一步。健康 finish 会先执行原生定稿,再富化定稿后真实存在的图片槽,并在同一次调用中渲染最终用户预览与发布。 与 App 对齐的电商预设会把 64px Header 固定为 `padding:[0,160]`:Header 使用 `navbar`,Nav 是由 44px `nav-link` 项组成的 `nav-links` 集合,Header actions 则是由 44×44 `icon-button` frame 构成的 `toolbar`,不再直接放裸图标。160×48 主 CTA 使用 `button`、把 label 放进自己的 binding,并采用符合 AA 的 `#C2410C`/`#FFFFFF`。三张商品卡保持同一个连贯系列。通用家居需求固定使用运行时 4/4 实测通过的组合:`gray armchair isolated photo`、`artemide tolomeo lamp photo` 和 `potted plant isolated photo`;第三张卡必须写成盆栽,不能继续标成花瓶。 begin 返回的 `rootNodeId`、`continuationStyle`、`canvas` 与 `buildContract` 就是权威运行契约。除非用户明确指定文件名,否则省略 `path`,由插件生成具体且防冲突的 `.op` 文件名,避免把模板语法写进路径后再 begin/abort 重试。直接原样实现 `next` 指定的有界第一段脚本,不扩大或重新解释范围,也不插入面向用户的 reasoning;自动预览返回后,立即用第二段也是最后一段脚本通过数组与循环补齐全部区域。这条直接的两段式路径让执行保持有界并及时返回。 两段 generation script 都使用直接 `I(...)`/`K(...)` QuickJS,以及 begin 返回的精确 `rootNodeId`、`continuationStyle` 与 `buildContract`。在 `run_code` 内用 `String.raw` tagged template 构造内嵌脚本,保证转义符和预期文本换行原样进入 QuickJS。必须使用下面这个多行 wrapper: ```js const draftId = ""; const script = String.raw`...`; const r = await tools.openpencil_pipeline_batch({ draftId, script }); return r; ``` 先把精确的 `begin.draftId` 加引号写入独立 `draftId` 字符串,再声明 `script`。固定的工具参数对象只能包含 `draftId` 和 `script`;禁止追加 `canvasWidth`、其他字段或把 return 写进对象。只返回 `r`,不要 log、print 或 stringify。每一批 QuickJS 都是 fresh scope,本地 binding 不会跨批次存在。`I`/`K` 返回的是不透明 node-id 字符串,不是可修改的节点对象:binding 只能作为后续 `I`/`K` 的父级,禁止赋值 `binding.x`、`binding.y` 或任何成员。第二批禁止重建 Page、App Content、Header 或 Hero;优先把新建且已绑定的 section rail 直接挂到 begin 的 `rootNodeId`。如果第一批创建了共享 content wrapper,只能使用第一批返回 binding 的精确 nodeId 继续挂载,绝不能按同名再建一个 wrapper。 `rootNodeId` 本身就是页面 frame,顶层区域直接挂到它上面,禁止再创建 Page/root wrapper;只有 frame/group binding 可以作为父级,包含图标的圆形视觉必须使用 frame 加 `cornerRadius`,不能拿 ellipse 当父级。每个语义容器(Header、Nav、Search、Hero、Card、Section、Toolbar、Button 或 CTA)都必须接住 `I`/`K` 返回的 binding,并立即通过该 binding 加入全部预期可见 children;禁止留下空语义容器,也禁止把预期 children 放成它的 siblings。最短有效 Header 示例为 `const h=I(root,{type:"frame",name:"Header",layout:"horizontal"}); I(h,{type:"text",content:"Shop",fontFamily:"Inter, system-ui, sans-serif"});`。移动端只有全宽 chrome/full-bleed section 可以直接挂 root;裸 text、icon、小 control 与 section title 必须放进一个已绑定且左右 gutter 为 24px 的 rail/section。每个分类卡都要有真实的视觉 tile 和 label;不同商品卡不能复用同一个 glyph 冒充商品图,应使用匹配且不同的 icon/shape,找不到合适视觉时直接省略 media wrapper。移动端分类项中的视觉 tile 固定为 56×56 tile frame。桌面电商分类栏以 `justifyContent:"space_between"` 铺满 1120px 内容宽度;商品栏固定为三张等宽 `fill_container` 卡片、24px 间距,右侧不能留下大段空白。每个 Button/CTA frame 创建后,必须立即通过其返回 binding 插入可见 text/icon child,不能把 label/icon 放成 sibling。最小图标示例为 `{type:'icon_font',name:'Search icon',iconFontName:'search',width:20,height:20}`:`name` 是图层标签,真正选择 glyph 的是 `iconFontName`,且只能使用这组已验证的 Lucide 名称:`home`、`search`、`shopping-bag`、`shopping-cart`、`user`、`heart`、`star`、`plus`、`arrow-right`、`sparkles`、`sun`、`apple`、`snowflake`、`droplet`、`cookie`、`leaf`、`coffee`、`package`、`gift`、`baby`、`spray-can`、`lamp`、`sofa`、`armchair`、`shirt`;没有合适图标时用形状构图。非电商设计默认只使用一个带具体英文 `imageSearchQuery` 的 `type:"image"` leaf,除非用户明确要求多图;电商固定使用三张不同商品图。每个 query 不超过四个英文词,只描述一个具体商品,禁止 lifestyle、collection 或宽泛 category;通用家居严格使用上面的实测组合。带 `isolated` 的 query 必须有 isolated/cutout/white-background 等正向元数据,重试也不能退回普通房间图;多词 query 至少命中两个有意义的元数据 token。禁止在大型固定商品媒体框里只放一个很小的 icon。每个 Hero/Product/Art/Media frame 只能有一个主视觉:一张 image,或一个实质性的 composed-shape visual,禁止 image 与占位 icon 并存;image node 是叶节点,不能作为父级。每个生成文本节点都必须显式使用 `fontFamily: "Inter, system-ui, sans-serif"`,普通字号和行高分别为 `fontSize: 16`、`lineHeight: 1.5`。桌面 App 继续使用内置 Inter;Web 宿主不会内置 Inter,因此自动走通用字体回退且不会弹出缺失字体提示。禁止只写裸 `Inter`。CJK 的 `lineHeight < 1.3` 会提升到 `1.5`,数值型 text height 也会自动改为 `fit_content`,除非 `textGrowth` 明确为 `fixed-width-height`。仅标题或特殊排版显式覆盖字号和行高。其余当前节点、样式、脚本与修复规则仍以运行时契约为唯一来源。第三段 generation script 会被拒;只有下文所述的完整修复门禁,才能授权第三段也是最后一段有界 QuickJS 修复脚本,并且只对指定目标使用 `U(...)`。 分类横栏必须为每个 label 使用不同且语义匹配的 icon。每个 `