interaction-design-board
Generate several genuinely different, runnable HTML interaction prototypes for one product surface, combine them in an interactive Design Board, collect structured selection/remix feedback, and only then hand the approved behavior to production implementation. Use when a user asks for multiple clickable UI versions, interaction alternatives, progressive-disclosure options, a Design Board, HTML prototypes, test-time scaling for product design, or says the visual styling is acceptable but the hierarchy, workflow, layout, or interaction still feels unprofessional. Prefer this over static image exploration when the decision depends on what happens after clicking, expanding, selecting, filtering, or moving through states.
1实现原理 · 为什么它能做到
流程门禁:先冻结 Decision Contract(user job/decision scope/immutable facts/existing language/first-view invariant/interaction states/stop condition),再提议 3 个独立交互架构候选(命令优先/队列详情/对象主导/对比主导/ledger 优先等族),每个候选=一个交互假说而非皮肤,变量只动导航/选择/披露/动作归属/信息序。
Each candidate embodies a distinct interaction hypothesis rather than a skin.
build_board.py 是合规闸门:读 board.json(schemaVersion=interaction-design-board/v1),校验 2-8 个变体、变体文件不越 manifest 目录且非 symlink、sha256 去重(byte-identical 拒绝)、每个变体必须自包含 HTML(禁外部 script/img/link/poster/url() 资源、禁 CSS @import、必须有 title、禁 <base>),然后填模板产出单文件 Board。
f"{field} depends on external resource {locator!r}; inline it as CSS, JS, or data URL"
运行隔离=模板注入 CSP + srcdoc sandbox iframe:每个候选被包进 srcdoc frame,Board 向其注入 default-src 'none' 的 CSP(仅 unsafe-inline 样式/脚本 + data:/blob: 媒体,connect-src/frame-src/object-src/form-action 全禁),再叠 sandbox='allow-scripts allow-forms allow-modals'。
policy.content = "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; img-src data: blob:; media-src data: blob:; font-src data:; connect-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'"
测试时缩放(test-time scaling):有独立 worker 上下文时,一个候选派一个 worker、共享同一份冻结 contract、互不可见彼此输出,防收敛成兄弟方案;无 worker 则串行生成但重读冻结 contract 而非上一个候选。
assign one candidate to each worker with the same frozen decision contract and only that candidate's hypothesis. Do not let workers see one another's output.
反馈回路:Board 提交 feedback.json / feedback-pending.json(regenerated:true 时带 regenerateAction iterate|remix)→ agent 保留接受部分、改失败轴、只重生成受影响候选 → 版本化 Board 文件 → gstack serve 已存在则 POST /api/reload(响应 {"reloaded":true}),重复 serve 不算 reload。
curl -sS -X POST "${BOARD_URL%/}/api/reload" \ -H 'Content-Type: application/json' \ -d '{"html":"<absolute-versioned-board-path>"}'
生产实施门禁:用户确认反馈总结后才写 approved.json(选中/批准交互规则/first-view invariant/被拒 trade-off/实际演练状态/剩余未知/原型文件身份),然后才进产品实现并用真实浏览器验证同一代表任务——像素相似不算数。
Then—and only then—implement in the product.
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| cli | python3(build_board.py,纯 stdlib) |
| cli | gstack design 可执行(可选:serve Board + /api/feedback + /api/reload;未装则开文件直用) |
| cli | curl(可选:Board 重载探测/触发) |
4管控建议与判定依据
- scripts/: 执行本地脚本或命令: python3 build_board.py(纯 stdlib;读取 manifest 与变体 HTML、写 design-board.html)
- 环境变量 / API Key: 读取厂商服务密钥: 无
- 本地工作目录: 文件读写与工件输出: build_board.py 写 session-dir/design-board.html;agent 按流程在 session-dir 写 boa
5第二遍独立确认
- [ok] 穿越/symlink/外部资源拒绝 — resolve_variant: symlink 拒 + relative_to(root) 校验;validate_self_contained: RESOURCE_PATTERNS 扫 script/img/link/video/url(),仅放行 data:/blob:/about:。
- [ok] CSP 断网声明 — 模板 241 行 CSP 含 connect-src 'none'; frame-src 'none'; object-src 'none';srcdoc + sandbox allow-scripts allow-forms allow-modals 双保险。
- [ok] sha256 去重与变体数上限 — seen_hashes 重复即 ContractError;'2 <= len(variants) <= 8'。
- [ok] 无网络外发/凭证 — build_board.py imports 仅 stdlib(argparse/hashlib/html/json/re/sys/html.parser/pathlib);无 http/密钥。
- [unlocatable] gstack serve/reload 集成 — 依赖外部 gstack 工具(仓库外),本环境未安装;SKILL 中 serve/reload/反馈端点语义无法端到端验证,代码侧仅见模板对 __GSTACK_SERVER_URL 与 ./api/feedback 的 POST。
- [unlocatable] Board 内候选交互可用性(UI 层) — 模板 434 行含 tab/对比视图/反馈面板 JS,未在浏览器实测;fixtures+test_build_board.py 覆盖构建层而非视觉层。
6结论
bb7d5b878d07fe8e…