| name | infinite-canvas-prezi |
| description | Prezi 风格「无限画布」单文件 HTML 演示生成器:基于 impress.js,用画布的空间布局本身承载叙事逻辑(镜头缩放/平移/旋转),白底黑字 Keynote 简约风 + 多彩点缀,标配一批风格统一的 AI 插画与经验证的网络素材。输入一个主题或一份素材(文档/链接/转写),自动完成研究 → 事实清单 → 场景与空间结构规划 → 媒体准备(快速降级不死磕)→ 构建单文件 HTML → 逐场景 QA → 交付。
三步顺序执行:1 素材理解与画布策划 → 2 媒体准备 → 3 构建 HTML 与 QA。上一步落盘产物(plan.json / media_manifest.json)是下一步输入,每步出口有脚本闸门。
触发词(需明确的空间叙事意图,勿被泛化动画/网页缩放误触):"Prezi"、"Prezi 风格演示"、"无限画布演示"、"空间叙事演示"、"impress.js 演示"、"镜头在一张画布上缩放/平移/旋转的演示"、"/infinite-canvas-prezi"。仅当用户要的是「一张无限画布 + 镜头运动承载逻辑」而非「一页页翻的幻灯」时触发。
Do NOT use for: 传统翻页教学 deck / reveal.js 课件(teaching-deck-builder)、PPTX 组装(manuscript-to-ppt)、单张信息图(infographic-composer / lecture-image-pack)、纯静态 16:9 图片页(ppt-image-pages)。当用户要的是「一页页翻的幻灯」而非「一张无限画布上镜头运动」时,不要用本 skill。
|
无限画布演示生成器(Infinite Canvas Prezi)
把一个主题或一份素材,做成 Prezi 风格的单文件 HTML 演示:所有内容分布在一张无限画布上,翻页时镜头以缩放 / 平移 / 旋转运动展示,空间布局本身承载叙事逻辑。产物是零构建、单文件、浏览器直接打开的 .html。
与传统 PPT / reveal.js deck 的本质区别不是「会动」,而是画布的空间关系 = 内容的逻辑关系。观众通过镜头在画布上的运动理解内容结构。所以本 skill 最核心的产出是「内容逻辑 → 空间结构」的映射,而不是页面美化。
执行方式:严格按步骤 1 → 2 → 3 顺序执行,不跳步。三步以 scene_id 为主键串成闭环,禁止「口头概述几个场景后直接写 HTML」。每步的产出必须落盘为工作区 JSON 文件(聊天里的表格/概述不算产出):
- 步骤 1 落盘
plan.json:facts(事实清单,逐条带 source)+ scenes(每项一个 scene_id,含 title / points 上屏要点 / coords 坐标 / media_need / 可选 source_image_candidate)+ style_lock + source_inventory(显式逐段遍历源素材的留痕,见 1.2.1)
- 步骤 2 落盘
media_manifest.json:items 逐 scene_id 填 type(source_image/search/ai/svg/none)/ url_or_path / verified / 降级记录 downgrade
- 步骤 3 逐
scene_id 渲染成 .step,产出 单文件 HTML + 实机截图 screenshots/ + 独立终审 review.json
跨步一致性闸门(脚本强制,rc≠0 不许进下一步):每步出口跑 python3 scripts/prezi_gate.py --phase <plan|media|build|final> <workdir> [built.html]——media 相位机械核对 media_manifest 与 plan 的 scene_id 集合相等(缺一即回步骤 2 补齐);build 相位机械核对 HTML .step id 覆盖全部 scene_id、无计划外新增、全部远程资源 URL 在已验证清单内。任何相位失败 → 修复后重跑,同一相位最多打回 2 次;仍不过 → 停下向用户报告,不许无限重试。
只在原则性疑惑时才停下问用户(素材严重残缺 / 存在多种完全不同的理解 / 受众目的完全无法判断且影响方向)。凡能自行合理确定的,直接决定并推进,不等确认。
工具映射(本机 / Claude Code 等价能力)
原 prompt 来自 YouMind 平台,下列平台能力在本 harness 中映射为:
| 原平台说法 | 本机等价 |
|---|
read 读 @引用文档/文件 | Read 工具(长文档分页读完,禁止只读开头就规划);登录墙链接(X / 公众号 / 飞书)先走 markdown-proxy skill |
fetch 抓网页正文 | WebFetch(或 markdown-proxy 拿干净正文) |
fetch 验证图片 URL 可访问 | curl -sIL --max-time 10 <url>(看最终 HTTP 200 + content-type: image/*),或 WebFetch |
| 网络搜索(研究 / 搜图) | WebSearch(研究主题、找候选图片来源页) |
generateImage AI 生图 | 调用 gpt-image-2-router skill(跑该 skill 目录下的 scripts/generate.py,默认 --route auto:Codex → YouMind → ListenHub,与该 router 默认一致)。禁止用 matplotlib / PIL / 手写 SVG 冒充「AI 插画」——简单图形走内联 SVG/CSS,插画走 GPT Image 2 |
| 产出 HTML(webpage) | Write 一个自包含 .html 文件到工作区 |
| 交付物 | 交付 .html 文件;本机默认再 cloudflare-pages-deployer 部署拿 URL、并按用户交付习惯发 Telegram(见 3.4「交付」;若这些 skill/配置不可用则退化为只交付本地文件) |
外部运行时依赖:只有 impress.js 一个库。唯一经实测可用的 CDN 是 https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js(npm/impress.js@* 与 cdnjs 路径均 404,勿用)。该文件约 183KB,需要严格离线单文件时可整段内联进 <script>。产物零构建、无本地安装依赖。
步骤 1:素材理解与画布策划
角色:资深叙事设计师 + 信息架构师 + 空间叙事(Prezi 式)专家。
目标:完整理解输入 → 建事实清单 → 场景拆分 → 空间结构选择 → 画布坐标规划 → 风格锁定稿。
1.1 输入适配(按类型处理)
- 纯主题 / 一句话需求("做一个关于黑洞的演示"):先
WebSearch 研究该主题,收集可靠来源的事实 / 数据 / 案例,逐条记录出处。
- @引用的文档 / 文件:
Read 完整读取;长文档分页读完,禁止只读开头就开始规划。
- URL(文章 / 网页):
WebFetch 或 markdown-proxy 获取正文后分析。
- 视频 / 播客链接:需要转写稿;若已有转写文档则读它,否则告知用户先生成转写(不要凭标题臆测内容)。
- 多个素材:逐一读取后合并分析,标注每条信息来自哪个素材。
1.2 事实清单铁律(杜绝臆造)
建立一份事实清单(落盘为 plan.json 的 facts 数组,逐条 {id, text, source}):后续所有上屏文字、数据、术语、引用,只能来自这份清单(素材原文,或已记录出处的搜索结果)。禁止凭常识「合理补充」清单中不存在的数据或结论。纯主题模式下,每条事实必须能对应到搜索来源。prezi_gate.py --phase plan 会硬拦无 source 的事实;上屏文字是否真的全部出自清单,由交付前的独立终审核验(见 3.3)。
1.2.1 源素材覆盖遍历(source_inventory,防重点被误删)
事实清单防的是「臆造/多」;这一条防的是**「漏」——把源素材里本该讲的重点整段删掉**。判据是内容重要性,不是图片数量:纯文字素材一张图都没有,照样可能漏掉一个论点、一次转折、一个承载方法介绍的案例、一种独特呈现效果(如「用动图展现某过程」这类高光)。
动作:通读源素材后,把它切成重要内容点(论点 / 转折 / 案例 / 关键数据 / 独特呈现),逐一登记进 plan.json 的 source_inventory.items:
{"id","summary":"这个内容点讲什么","kind":"content|static_image|dynamic_media",
"disposition":"covered|skipped","scene_id":"(covered时)","skip_reason":"(skipped时:为何不值得进场景)"}
- 主轴是
content(内容点),媒体是附属标注;dynamic_media 专指 GIF/视频/动图这类极易被静态化丢弃的呈现。
- 选重点、取舍次要内容是应该的——不追求全覆盖,
skipped 完全合法,但要写明 skip_reason。
- 动态媒体默认应呈现(它往往是「效果最好」的那部分),要
skipped 必须给出过硬理由。
prezi_gate.py --phase plan 只机械核「已登记项处置合法 + skipped 有理由」,不计数、不判覆盖全不全、不判重要性(那是柔性判断)。真正的裁决——你漏掉的里面有没有本该讲的重点——由交付前的独立终审 coverage 维做:它会绕过你这份清单、自己重读源素材重新切分内容点再比对(防你漏登记的段落自证通过)。所以这份清单是「强制你逐段遍历」的留痕,不是覆盖裁决的依据。
1.3 场景拆分(一个场景 = 一次镜头停留)
- 一个场景只讲一个讲点(一个概念 / 一个论据 / 一个转折),信息量以观众 10–30 秒内可消化为准。
- 上屏文字精炼:标题 + 少量关键要素词 / 短句,不搬运整段原文。
- 每个场景是
plan.json scenes 数组的一项,标注:scene_id、title、points 上屏要点(出自事实清单)、coords 坐标参数(见 1.5)、media_need 媒体需求;此外每页必归入某个聚簇(clusters,见 1.4)。媒体需求预判素材类型,按优先级:素材自带且直接支撑该讲点的原图(source_image,见 2.1 第 0 级)→ 真实实体网络搜图 → 抽象概念 AI 插画 → 简单图形内联 SVG-CSS → 已有主视觉则无需配图。有原图候选的场景须在 source_image_candidate 字段显式写明(原文哪张图 + 来源/许可)——--phase media 会核对该字段有没有被落实或写明降级理由。按默认配图心态规划:标题页默认一张宽幅横幅,多数内容场景默认一张配图;仅当场景已有大型 SVG 主视觉或数据图表作主视觉时才标「无需配图」。
- 场景数量自适应,一般 6–20 个。开头的 establishing 建议用「真实画布远景」:镜头拉远俯瞰真实聚簇的空间布局,让观众建立心理地图——但禁止用带「下钻在此 / 目录 / 接下来讲 X」字样的示意图剧透机制(结构靠后续镜头运动涌现,见 1.4 原则 4)。结尾必须预留「全景总览」(Prezi 标志性收尾,也是最高层级的一次回看)。层级内容还应在每个大部分讲完时安排「中观回看」场景(见 1.4 镜头编排)。
1.4 空间即逻辑:聚簇优先(由内容逻辑推导,禁止平铺)
本 skill 立身之本是**「画布的空间关系 = 内容的逻辑关系」**。这不只对层级/总分内容成立——每一层都成立。把相关页面等距一排推进、只靠翻页前进,是最常见的失败:空间没承载任何逻辑。(2026-07-05 用户实测反复指出:除嵌套外其余全平铺、看不出关系。)
聚簇优先四原则(BLOCKING):
- 先拆聚簇(群落):内容先分解成一个个聚簇——每组紧密相关的页面(一个子主题 / 一组并列 / 一段序列 / 一个部分-整体组)是一个簇。每页必属某簇,不许出现均匀路径上的孤立散页。落盘为
plan.json 的 clusters(见下)。
- 簇内紧凑但不遮挡:同簇页面空间上紧挨(镜头小幅移动),排布反映簇内关系:并列→紧挨并排/小三角、序列→短路径、对比→对置、部分-整体→嵌套下钻(子页足迹几何住在父页里,见「真嵌套」)。但「紧挨」不等于「重叠」——任意两张卡片的足迹都不许相互遮挡(簇内间距要 > 卡宽/卡高,留出小缝;唯一例外是嵌套父页有意包含自己的子讲点)。
--phase plan 机械核卡片足迹两两不重叠。
- 簇间分离且承载关系:不同簇之间留明显空隙(镜头大幅移动),簇的相对位置反映簇间逻辑(论点→主体→结论;总→分;问题→解决;递进→同向;对比→左右)。
- 结构靠空间与镜头涌现,禁止剧透:不得用「结构说明图 / 目录页」预先标注「这里有下钻」「接下来讲 X」。观众通过镜头在簇间移动、钻入子簇再退回自然感受逻辑。开场若要给全貌,用真实画布的远景俯瞰(真实聚簇本身,不画示意图、不加元标注)。
plan.json 落盘 clusters(强制结构优先产物,--phase plan 机械校验):
"clusters":[{"id","label","logic":"thesis|parallel|sequence|contrast|part_whole|progression|conclusion",
"scene_ids":[...],"nested":bool,"parent":"(nested时的父 scene_id)","singleton_reason":"(单页簇才需)"}...]
机械闸会拦:无聚簇 / 散 singleton(占比>25% 或无理由)/ 少于 2 个多页真聚簇 / 一簇摊满整条路径(半径超限)/ 簇间贴太近(间隔<0.6 卡宽)/ 假嵌套(父子 scale 比<3 或子足迹不在父足迹内)。机械层拦不住「多个紧凑小簇却排成等距直线、相对位置不表达逻辑」——那由独立终审 R3 兜(见 references/review-checklist.md ⑥ 路径语法)。
先判内容逻辑,再定各簇内部与簇间的空间结构——不要一刀切,尤其不要默认全程一条均匀路径(那正是"打开每个都小、一味顺路走、看不出结构"的根因):
| 内容逻辑 | 空间结构 |
|---|
| 时间线 / 流程 / 步骤 | 沿一条路径线性推进(横向 / 斜向 / 折线) |
| 总分 / 多个并列方面 | 中心辐射:全景居中,镜头依次 zoom 进各分支再回中心 |
| 层层深入 / 宏观到微观 | 嵌套缩放:细节场景以小 data-scale 藏在大场景图形内部,镜头逐级钻入 |
| 循环 / 闭环 / 生命周期 | 环形排布,镜头绕环行进,可配 rotate 让每站正对观众 |
| 对比 / 正反方 | 左右(或上下)分区,镜头两侧横摆,最后拉远同框对比 |
层级/总分内容优先层级式布局(BLOCKING,当内容呈总分/层级/模块关系时——多数素材如此):采用 macro→meso→micro 的嵌套布局,让空间排布本身表达结构,而不是把所有场景串成一条均匀的路径线。纯粹的时间线/单一流程/循环/对比按上表由内容逻辑决定,不强套层级。层级布局要点:
- 各大部分(meso)在画布上占据彼此分开的区域/象限,其相对位置反映大部分之间的关系(并列 / 递进 / 对立);
- 每个大部分内部的子讲点(micro)聚成一簇围绕该部分,簇内空间排布反映子部分关系:并列→并排、递进→阶梯、对比→左右、包含→嵌套缩放;禁止把某部分的子场景一条线甩在主路径上。
镜头编排(纵览 → 下钻 → 中观回看):
- 先纵览:开场用 establishing overview 让观众看清整体结构(见 1.3);
- 再下钻:进入某大部分时镜头 zoom 进该簇,逐个子讲点走;
- 回中观回看:该部分讲完 / 需要小结时,镜头拉回该部分(或整体)的中观视图回看一眼承上启下,再平移到下一大部分;结尾全景总览是最高层级的回看。回看不堆叠(2026-07-06 用户实测):树模式下「只有一个容器子且无自有叶内容」的空壳层坍缩——不生成独立父视图步、不生成该层 recap,子直接住进上层槽位;连续多层同时结束的连环 recap 相邻堆叠时只保留最深一层。机械规则见
references/roam-outline.md「镜头编排三规则」,--phase plan/build 双向核。
相邻场景的镜头运动应在**下钻(zoom in)/ 回拉(zoom out)/ 平移(pan)**间交替,避免连续同向推进的疲劳(与 1.5 防晕规则一致)。混合结构允许(如大部分之间线性、某一部分内部嵌套缩放)。判据:把 overview 一屏摆出来,只看空间布局能否读出「内容有几大块、块内子项什么关系」?只看到一条均匀路径线 = 退化成单调线性,不合格。
真嵌套缩放(BLOCKING,总分/层级内容必做,不许平铺假装层级):Prezi 的招牌魅力是「一张图列出多层级结构 → 点进去钻入其中某部分(别有洞天)→ 在子部分间穿梭 → 再退回上一级看整体,因为刚探索过而觉得既熟悉又赏心悦目」。总分/层级内容至少要有一组真嵌套:
- 父场景是一个能看清该部分整体结构的视图(一张「结构图 / 分区图 / 母图形」);
- ≥2 个子讲点以显著更小的
data-scale(父子 scale 比建议 ≥ 3)嵌在父场景的空间包围盒内部——镜头钻进去时,子讲点填满取景框,观众看不出它其实住在父图里;
- 有**钻入(zoom in 到子群)→ 子间穿梭(pan)→ 退回(zoom out 回父级看整体)**的完整镜头序列。
- 纯 y 平铺 + 一个远景 hub ≠ 嵌套——那只是把场景摆高低,镜头从没「钻进某个图形内部再退出来」。
- 例外:纯时间线 / 单一流程 / 循环 / 对比结构可不做嵌套(由上表内容逻辑决定),但必须在
plan.json 注明 structure_type,否则独立终审 nesting 维默认按「总分内容」要求真嵌套。
判据(独立终审 nesting 维会核):HTML 坐标里是否真存在父子嵌套(scale 比显著、子坐标落在父包围盒内、有钻入+退回序列),还是纯平铺假装层级。
1.5 画布坐标规划 + 防晕规则
为每个场景规划 impress.js 坐标:data-x、data-y、data-z、data-rotate(必要时 data-rotate-x/y)、data-scale。规划时即执行防晕规则:
- 相邻场景旋转角度差 ≤ 90°;
- 相邻场景缩放比 ≤ 10 倍;
- 避免连续多站都是「大旋转 + 大缩放」叠加;镜头运动类型(平移 / 缩放 / 旋转)应交替出现;
- 相邻场景在画布上的间距必须大于各自内容包围盒,防止镜头停留时看到邻居场景穿帮(除非是有意的「背景中若隐若现」设计)。
1.6 风格锁(默认基准,除非用户显式指定风格)
- 底色:纯白
#FFFFFF。
- 基础文字:近黑(
#1a1a1a 级别),Keynote 式简约排版,字重 / 字号分层清晰。
- 彩色点缀:图形勾勒、重点词、强调色块用彩色,从 2–4 个和谐色相中取色(按主题气质自选),禁止全篇单一色相。
- 用户显式指定风格(深色科技风 / 复古风等)时,在满足要求前提下保持底层一致性:排版层级清晰、可读性优先、配色体系统一、点缀色不单一。
1.7 规划完成后
把 facts / scenes / style_lock 落盘为工作区 plan.json,跑 python3 scripts/prezi_gate.py --phase plan <workdir> 过闸(rc≠0 修复后重跑,最多打回 2 次)。然后在聊天中用几行文字简述「空间结构选择 + 场景大纲」,不等待确认,直接进入步骤 2。
步骤 1 自检清单(工作提示,放行以 gate 为准)
步骤 2:媒体准备(AI 生图 + 网络素材,快速降级不死磕)
角色:严谨但务实的视觉素材编辑。
目标:按步骤 1 的场景媒体需求,逐项落实素材,落盘「场景 → 素材」对照的 media_manifest.json。
本步骤是标配流程,不是可选项:每次演示默认产出一批风格统一的 AI 插画覆盖核心概念场景,并为真实实体类内容尝试网络搜图。
2.1 素材获取优先级
- 素材自带图优先复用(BLOCKING,第 0 优先级,排在以下所有项之前):当输入素材(@文档 / URL / 转写 / 用户给的文章)本身内嵌了图片(论文原图、结果图、机制示意、产品/界面截图、图注配图),且该图直接支撑某场景的讲点时——直接复用原图,不要另找图或另生成把原图晾在一边。原图承载原文语境,最贴切、最省事。判据:该场景讲的正是原文某段,而原文那段配了图 → 强复用信号。逐场景过一遍「这个讲点原文有没有对应图?」。仍受 2.4 版权与署名约束:原文图也要记录来源/许可(
media_manifest 标 source_image + 原始 URL);curl -sIL 验证可访问后入清单(原文常见 R2/公众号/图床 CDN,多数可直连,个别有防盗链按 2.3 降级)。仅当原文无对应图、或原图不适配(画质差 / 与讲点无关 / 版权明确受限 / 纯装饰)时,才降级到下面 1–3 级。不要因为"想统一成 AI 插画风"就弃用承载原文语境的原图——原图与统一风格插画可以共存(原图作证据、插画作概念示意)。
- 能用代码画的不找图:箭头、流程框、简单图表、几何图形、分隔装饰、书封卡片、logo 文字标等 → 标「内联 SVG/CSS 绘制」,留给步骤 3 直接实现。加载最快、风格最可控、零外链风险。
- 真实实体优先网络搜图:真实人物、产品、地点、历史事件、艺术品、真实照片类 →
WebSearch 找来源页。优先稳定、可公开访问、无防盗链的来源(Wikimedia Commons、官方网站、稳定 CDN)。
- 抽象概念用 AI 生成:概念示意、隐喻插画、氛围图等搜不到或不该用真实照片的 → 调
gpt-image-2-router。
2.2 配图密度基准(宁可略多,不要偏少)
- 默认基准:位图覆盖约 60%–80% 的内容场景(不计 camera 空步与纯装饰步),保持「每 1–2 页一图」的视觉节奏。
- 标题页默认一张宽幅横幅(21:9 或 16:9);结尾页默认一张点题插画。
- 已有大型 SVG 主视觉(金字塔 / 环形循环 / 阶梯)或密集数据图表/对比条的场景可不加位图——SVG 主视觉本身就是图。
- 经验教训:真实反馈里「图有些少」远比「图太多」常见;拿不准某场景要不要配图时,倾向于配。
- 相关性是底线:每张图必须服务该场景讲点,禁止无关硬塞装饰图。
- 密度下限兜底:若搜图大面积降级后位图覆盖率跌破 60%,优先用内联 SVG/CSS 示意或补几张同风格 AI 插画把密度拉回基准;确实补不上(如高度抽象无从配图)时,在交付说明里一句话讲清原因,不默默交一版图荒的演示。
2.3 快速降级铁律(不死磕)
素材获取遇阻立即降级,禁止反复死磕:
- 每项搜图素材最多验证 2–3 个候选 URL;全部失败就降级,不换源纠缠。
- 降级链:网络搜图失败 → AI 生成同主题风格化插画 → 内联 SVG/CSS 绘制示意(如书封做成 CSS 立体书卡片)→ 放弃该场景配图(纯排版同样干净)。任何一级降级都可接受。
- 按时交付完整演示 > 单个素材的完美。整个媒体准备阶段不允许卡死在任何单项素材上。
- 防盗链警惕:豆瓣、当当/京东/淘宝等电商图床普遍有防盗链或 UA/Referer 校验——即使工具端验证通过,观众浏览器里也可能 403。此类来源直接跳过或降级。
2.4 网络搜图规范
- 找到候选后,必须逐一
curl -sIL / WebFetch 验证图片 URL 真实可访问(最终 200 + image/*),失败按降级铁律处理;禁止把未验证 URL 写进演示。
- 禁止编造、拼接、猜测图片 URL。
- 图片内容必须与场景讲点真正相关,禁止「差不多就行」硬塞。
- 记录每张图的来源页面,便于溯源。
- 版权与署名:优先公有领域 / CC 授权 / 官方授权可公开使用的来源(Wikimedia Commons 等);记录来源页与许可,避免采用版权状态不明或明确受限的图片。真实照片搜不到合规来源时,降级为 AI 插画而非冒险采用受限图。素材自带图(2.1 第 0 级)同样适用:直接复用原文图时也要在
media_manifest 记来源/许可;若原文图版权明确受限或不可公开复用,降级为重绘 / AI 插画 / 文字化表达,不冒险照搬。
2.5 AI 生成图规范
- 提示词锁定与风格锁一致的视觉语言:默认白色背景、简约插画/图形风、黑色主线条 + 风格锁选定的点缀彩色,构图干净。
- 同一演示内的生成图风格统一(同一套色板与笔触描述复用于所有提示词)。
- 图内避免文字或仅用极少量大字(避免生成文字出错);文字信息一律由 HTML 层排版承担。
- 按用途选比例:标题页横幅
--aspect-ratio 21:9 或 16:9,侧栏配图 1:1 或 4:3。
- 用户指定非默认风格时,生图提示词随风格锁变体调整。
gpt-image-2-router 返回的产物路径 / CDN URL 视为已验证,直接入清单。
2.6 输出
落盘工作区 media_manifest.json:items 逐 scene_id 一项——type(source_image / search / ai / svg / none)、url_or_path、verified(远程 URL 经 2.4 验证后才可置 true)、aspect_ratio(位图项必填:宽/高数值,验证素材时实测——本地图直接量、远程图下载探测一次;imgfocus 横图判定依赖它,远程记录值属 v2a 信任、独立终审截图兜底)、note(来源或提示词备注)、downgrade(降级记录:原计划 → 实际采用及原因;plan 里声明了 source_image_candidate 却未复用原图时必填)。落盘后跑 python3 scripts/prezi_gate.py --phase media <workdir> 过闸(机械核对 scene_id 集合与 plan 相等、远程 URL 已验证、本地媒体文件真实存在、位图项带数值 aspect_ratio、R1 原图复用或有降级理由;rc≠0 修复后重跑,最多打回 2 次)。过闸后直接进入步骤 3,不等确认。
步骤 2 自检清单(工作提示,放行以 gate 为准)
步骤 3:构建 HTML 演示与 QA
角色:资深前端工程师 + 演示设计师。
目标:把步骤 1 的 plan.json + 步骤 2 的 media_manifest.json,落成一个单文件自包含的 Prezi 风格 HTML,QA 后交付。
3.1 构建方式
用 Write 产出单个 .html 文件作为最终交付物。所有 CSS/JS(业务代码)一律内联,不产出多文件工程、不要求用户本地安装依赖。
3.2 技术规范
- 引擎:impress.js(经典 Prezi 式开源库)。CDN 只用实测可用的那一个:
<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js"></script>。根容器 <div id="impress" data-transition-duration="1000" data-width="1920" data-height="1080">(根 data-width/height 定义画布参考坐标系,按 1080p 设)。每个场景为 <div class="step">,坐标严格采用步骤 1 规划的 data-x/y/z/rotate/scale;给 .step 一个固定像素尺寸(如 width:900px + 内边距),让内容包围盒可预期、便于防穿帮。末尾引 CDN 后调 impress().init();。
- 单文件自包含的确切含义(二选一;2026-07-06 起默认对调为严格离线):
- 默认:严格离线单文件:把 impress.js 那 183KB 整段内联进
<script>,所有图片(含 GIF)一律 base64 data-URI 内联——零外链、断网可播。roam2prezi 默认即此模式:素材下载缓存到工作区 media_cache/(URL sha1 键+原扩展名),断网重跑零网络;原始 URL 保留在同元素 data-src-origin(机器可读血缘,供 gate D1 图片归属核验——只有同元素带实打实 data:image base64 载荷时才被认可,防伪造)。--phase build 在离线模式(plan media_mode:"offline")下把外链血缘闸收缩为零可抓取远程资源(含 impress CDN)。
- 在线模式(
roam2prezi.py --online 显式选择):impress.js 走上述 CDN;图片 = 步骤 2 已验证的远程 URL 或 base64 内联的本地生成图。除 impress CDN 与已验证远程图外无其它外链。
—— 仅当图片体量过大、用户明确接受多文件时,才改为「html + 图片同目录相对引用」并整目录打包交付。
- 全景总览:最后一个 step 设
id="overview",坐标取全部场景包围盒的几何中心、scale 取「能把最远包围盒边收进取景框」的值(精确计算见 references/build-template.md);观众按下一页到最后自动回到全景。
- 用户文本转义:所有来自事实清单/素材的文字在写入 HTML 前做 HTML 转义(
< > & " '),防止素材里的符号破坏结构或注入。
- 渐进显现(BLOCKING,2026-07-06 用户需求「感受生成过程 + 回顾复习」):聚焦到一张内容卡时,标题/副题立即显示,要点逐条 + 配图作为一条初始隐藏——观众每按一次「下一步」显现一条(impress.js 自带 substep 插件:要点
<li class="substep">、图列 div 同 class),全部显现后再按才离开本卡。一旦离开(显现过),之后回看(recap/总览/重访)全部保留可见:impress:stepleave 时给该步全部 substep 打永久 .revealed 类并移除 .substep 类(缺 remove 则重访时插件继续逐条拦截 next)。适用面:叶卡/普通内容卡的要点与配图;标题卡、父视图卡(子卡预览=空间语义)、imgfocus/camera 空步不参与。--phase build 机械核:≥2 要点的内容步须逐条 substep 元素 + JS「离开永久显现」接线(代码层 addEventListener/classList.add/classList.remove 调用 token + 原文层 impress:stepleave/revealed 字面量)+ camera/父视图步禁藏 substep;行为真实性由独立终审 nav 维真按键测试兜底(v2a)。
- 导航:保留 impress.js 原生键盘导航(方向键 / 空格);必须实现「点击卡片直接聚焦」——监听
click,e.target.closest('.step') 命中某卡就 api.goto(该 step),让观众在总览里点某簇、或在父页里点某个子卡都能一键飞过去聚焦(点空白处 next);进度圆点也做成可点击直达(dot → api.goto(steps[i]))+ 底部进度指示;首屏用一行小字提示操作方式。--phase build 会机械核对「点击聚焦」接线(click 监听 + closest('.step') + api.goto)存在。
- 降级:保留
.impress-not-supported 提示样式,不支持 CSS 3D 的浏览器显示线性阅读版内容。
- 样式:执行步骤 1 风格锁——白底、近黑基础文字、Keynote 排版层级、彩色仅用于图形勾勒与重点强调且色相不单一;非当前场景保持 impress.js 默认降透明度效果,突出当前镜头。
- 文字可读性 + 充盈取景框(BLOCKING):镜头停在某内容场景时,其内容应充盈取景框主要区域(版心约 70–88%),标题与正文清晰饱满——不要让内容缩在取景框中央一小团、四周大片空白显得"小而稀"(这是"打开每个都感觉比较小"的直接原因)。做法:物理字号先按
data-scale 反算——物理字号 ≈ 目标屏上字号 / data-scale(目标屏上字号:标题≈报告主标级、正文≈清晰正文级),.step 固定宽度也随 scale 反算让投影后接近版心宽;再以实机截图的 apparent size 为准校正(impress 实际投影与公式可能有偏差,截图看空不空、糊不糊)。适用面:仅限内容 step——overview、纯 camera 空步、刻意留白/过渡场景不在此列,不要误把它们撑满。
- 媒体:只用步骤 2 验证过的 URL 与生成图;
<img> 设 max-width/max-height 约束在场景包围盒内。图文布局优先左右并排(flex):文字区 flex:1,图片作侧栏列(固定像素 200–320px 或 40–48% 比例列均可,f 按实际 CSS 取值)并默认全高垂直居中——避免上下堆叠把面板撑高导致取景框切边;标题页横幅居中放置、宽约版心 60%。所有远程 <img> 一律加 loading="lazy" 与 onerror="this.style.display='none'"(失效静默隐藏,不留破图标);简单图形与书封卡片用内联 SVG/CSS。
- 横向侧栏图必须配「图片聚焦步」(BLOCKING,2026-07-05 用户反馈:侧栏横图观感小、看不清):侧栏是「宽度受限」的——横向图(宽/高 ≥ 1.25,截图/论文图/图表/GIF 都算)放侧栏,镜头停整卡时图只占取景框一小块,必然看不清。解法是 Prezi 语言里现成的:镜头再走一站。凡「文字 + 侧栏横向位图」的内容场景,其 step 之后紧跟一个图片聚焦 camera 空步
id="imgfocus-<scene_id>"(class="step camera imgfocus",无内容;camera class 享「计划外 step」与 output_lint 字号双豁免),坐标对准图片列中心、scale 让图充盈取景框约 85%——镜头节奏 = 整卡 → 钻进图 → 拉出回卡(zoomback)→ 下一站:离开 imgfocus 的下一步若不是拉出类步(recap/overview/同坐标纯拉出 zoomout),必须插 zoomback-<scene_id> camera 空步(本卡坐标、本卡 scale)——深钻小 scale 直飞兄弟卡=大变焦+大平移叠加眩晕(2026-07-06 用户实测),拆成两段单一运动后每段 zoom 比约 2–3 倍,防晕规则天然满足;树模式 --phase build 机械核 zoomback 在位且坐标绑定本卡。坐标公式与 snippet 见 references/build-template.md「图片聚焦步脚手架」。豁免须显式留痕:全宽横幅/图已充盈、纯装饰小图等不适用场景,父 step 必须标 data-imgfocus="skip:<理由>"(无标记不豁免——机械层不区分布局,fail-closed);嵌套父页自动豁免(钻入由子讲点承担);竖图/方图不触发。触发场景的父 step 必须声明图片显示盒 data-imgfocus-box="dx,dy,w,h"(画布单位、相对父卡中心、未旋转局部系——机器可核的聚焦目标声明)。--phase build 机械核(2026-07-05 晚经 Codex 对抗审 B1-B8 硬化):触发场景必须「有合规聚焦步或显式 skip」——聚焦步六项:紧跟父步 + camera 空步(全局 camera 步都必须真空,禁走私内容)+ scale<父 + rotate 同父 + 取景把声明盒完整收进(父卡 rotate≠0 时反旋转核) + 盒较大维充盈取景框 ≥70%(防 scale 只小一点点的假聚焦);step 归属对任意标签生效(section 等同 div)、位图载体不限 <img>(svg image/object/embed/video/内联 background 都算)、所有 step id 全局唯一、skip 理由须含可见字符。盒位自报属可证伪声明;谎报盒位、<style> 块背景图绕过、短文本绕过,由独立终审 ② 基于截图兜(v2a)。
起手模板:HTML 骨架(含 .step 尺寸、进度圆点、点击翻页脚手架)、单文件/离线两模式、overview 精确计算、截图验证做法,全部在 references/build-template.md——构建时加载它照抄改。
3.3 QA(构建闸 → 实机截图 → 独立终审,放行以 gate 为准)
QA 分三段,顺序执行,全部脚本承接:
- 构建闸(刚):
python3 scripts/prezi_gate.py --phase build <workdir> <built.html>——机械核对 .step id 覆盖 plan 全部 scene_id、无计划外新增(overview / camera / data-fill="skip" 豁免)、HTML 全部远程资源 URL(含 srcset、CSS background-image)只允许 impress CDN 与 manifest 已验证 URL、横向侧栏图的 imgfocus 聚焦步在位或显式 skip 留痕、字号下限(内含 output_lint)。rc≠0 修复后重跑,最多打回 2 次。
- 实机截图(必做,非建议):无头浏览器逐张截图首屏、若干中间 step、overview,存工作区
screenshots/(≥3 张)。肉眼自检不足以发现取景切边/穿帮。具体做法见 references/build-template.md。
- 独立终审(柔,禁自审,7 维):用 Agent 工具起一个独立子 Agent(非构建上下文),照
references/review-checklist.md 逐项审查,产出工作区 review.json(契约见该文件末尾:reviewer: "independent-subagent"、reviewer_agent_id、html_sha256、逐项 {id, pass, evidence}、overall_pass)。7 个必审维度:R1 源图复用 / R2 充盈观感 / R3 结构可读 / facts 事实溯源 / nav 导航 / coverage 源素材覆盖 / nesting 真嵌套缩放。
- 子 Agent 输入必须含完整源素材边界:不只
built.html + screenshots/ + plan.json,还必须把源素材本身(原文档 / 链接内容 / 转写稿 + 图片/GIF 目录)路径传给它——coverage 维要它读源素材、绕过 plan.source_inventory 自己重新切分内容点再比对成品,缺了源素材这一维就是瞎审(这正是旧版病根)。review prompt 必须写明「不要以 plan 的 inventory 为唯一输入」。
coverage 判据是重要性不是数量:只揪「本该讲的重点/独特呈现(含动态图这类高光)被误删」,选重点取舍不 fail。nesting 判据:总分/层级内容有没有真嵌套缩放(钻入+退回),纯平铺假装层级 = fail(豁免结构类型看 plan.structure_type)。
- 过闸:
python3 scripts/prezi_gate.py --phase final <workdir> <built.html>(final 内部复跑 plan/media/build 全部前置检查、核 review.json.html_sha256 与当前产物一致、核截图不早于产物修改时间、核 7 维齐全且全 pass)。构建者禁止手写或修改 review.json——有 fail 项时构建者只修产物,修完必须重跑 --phase build、重新截图、重新调用独立子 Agent 复审(不得沿用旧 review.json / 旧截图),最多 2 轮;仍不过 → 停下向用户报告,不许无限重试、不许降级为自审放行。
下面的清单是构建时的工作提示(写 HTML 时对照防漏),不是放行依据——放行依据是上面三段的 gate 退出码:
(实机截图与判断类维度的放行机制已并入本节开头三段:截图存 screenshots/ 供独立终审与 --phase final 消费;R1/R2/R3 由独立子 Agent 照 references/review-checklist.md 审出 review.json。)
3.4 交付
交付 .html 后,只用两三句话说明:演示主题与场景数、操作方式(←/→ 方向键或点击翻页,最后一页为全景总览)。不冗长复述内部执行过程。
Roam 大纲双向生产线(BLOCKING 交付物,2026-07-06 用户需求「HTML 难手改」):交付前跑 python3 scripts/prezi2roam.py <workdir> 导出 roam.md,并在工作区放 update.sh(roam2prezi 薄封装)与 README-roam.md(语法+边界+两档 QA 说明)。用户改大纲 → 跑 update.sh → 确定性重建 plan/布局/HTML 并过机械三闸;正式重新交付仍须重截图+独立终审过 final(final 含 roam↔plan 规范化 AST 一致性核)。语法/边界/工具细节见 references/roam-outline.md。
空间结构:全递归树模式(默认,2026-07-06) —— roam2prezi 默认把大纲当全递归树:任意深度的容器都是一个节点,子节点以显著更小 scale 真几何嵌入父节点足迹(真嵌套预览到底),根节点=演示标题=最外层视图(兼 overview)。镜头 = DFS 前序 + 每个内部节点子树遍历完退回时插 recap 回看;子节点在父内自动混合布局(2 左右 / 3 三角 / 4+ 环绕 / 大 fanout 网格,层间形状自然变化),缩放比自适应(能装下且 ≥3)。无硬性深度/子数/总数上限(内容多层就深)。旧「主线聚簇 + 一层下钻」聚簇模式经 roam2prezi.py --cluster 保留兼容;闸门按 plan.json 的 layout_mode(tree / 缺省=cluster)分流校验。手写 plan.json 的空间规划要点(聚簇优先四原则等)见 1.4,仍适用于聚簇模式与树模式的语义判断。
本机默认交付动作(除非用户另有说明;相关 skill/配置不可用时退化为只交付本地文件):
- 默认单文件模式下,
.html 自包含可直接发;仅当选了「多文件相对引用」模式,才需整个工程目录打包(.html + 图片)再发,不能只发引用相对路径图片的裸 html。
- 适合公开预览时,用
cloudflare-pages-deployer 部署拿 URL。
- 按用户交付习惯,将最终产物(html 或部署 URL)通过 Telegram 发给用户(用本机 Simpson bot 与全局配置里的默认 chat,不在 skill 内硬编码个人 chat_id)。
3.5 禁止事项
- 禁止使用未经步骤 2 验证的媒体 URL(
--phase build 机械拦截 manifest 外远程资源)。
- 禁止上屏事实清单之外的文字性事实(独立终审
facts 项核验)。
- 禁止无视步骤 1 坐标规划自行随意摆放导致眩晕或穿帮。
- 禁止产出多文件工程或要求用户本地安装依赖。
- 禁止用 matplotlib / PIL / 手写 SVG 冒充「AI 插画」(简单示意图走内联 SVG/CSS,插画走 gpt-image-2-router)。
- 禁止构建者手写、改写或润色
review.json——它只能由独立子 Agent 产出;脚本无法密码学证明独立性,这条是行为红线(信任边界如实声明:final 闸核的是结构与身份痕迹,独立性本身靠本条纪律 + agent 调用记录)。
- 如实声明的 v2a 残留信任边界(脚本兜不住、靠行为红线 + 独立审自核):① 审查者身份自填(同上);②
coverage 维的源素材由主流程递给审查者,脚本未冻结源哈希做机械交叉核——构建者必须把完整源素材边界(原文全篇 + 全部图片/GIF 目录)传给审查者,禁止只递 plan 或裁剪过的子集,审查者须先自核源是否完整(见 review-checklist ⑤);③ nesting 豁免不得凭 plan.structure_type 自报放行,审查者须独立判定内容逻辑(见 review-checklist ⑥);④ 聚簇/嵌套的「渲染真实性」:--phase build 已机械绑定 HTML 的 data-x/y/scale/rotate == plan 坐标,并禁止用内联/样式表 transform 覆盖 step 定位;但静态闸无法沙箱化运行时 JS(inline script 在 load 后重排 step、或调 impress API 改坐标)——故意用 JS 运行时重排把聚簇渲染成平铺,属对抗性构建者行为,静态层拦不全。兜底是独立终审 R3 读的是真实截图(渲染后像素):无论用 CSS/JS 怎么造假,渲染成平铺就会被 R3 的总览截图当场判 fail。彻底静态闭合需受控渲染 runner(v2b,未做)。⑤ 「点击卡片聚焦」的接线真实性:--phase build 只结构性核对 <script> 里有 click 监听 + closest('.step') + api.goto(剥了注释);但把整段 handler 藏进 JS 字符串字面量能骗过 token 搜索(静态判 JS 行为不可判定)。兜底是独立终审 nav 维必须在无头浏览器里真点一张卡、验证镜头确实飞过去聚焦(见 review-checklist ④),假接线渲染不出真行为,会被当场判 fail。⑥ imgfocus 的两处启发式:远程图的 aspect_ratio 是构建者实测记录值(脚本不重新下载复核);「实质文字 ≥40 字符」阈值可被压短文本绕过——两者都由独立终审 ② 基于实机截图兜底(侧栏横图无聚焦步且 skip 理由不成立 = fail)。
- 禁止跳过任何 gate 相位、或在 rc≠0 时继续推进;同一相位打回超过 2 次必须停下向用户报告。
步骤 3 示例
承接咖啡主题 → 输出:咖啡:从种子到杯子.html 单文件,10 个场景沿斜向旅程线排布,「处理法」站内嵌套缩放三个子场景,白底黑字 + 暖橙/青绿/深棕三色点缀,标题页 21:9 横幅 + 约七成场景配统一风格 AI 插画(图文左右并排),含点击翻页与进度圆点,末尾全景总览一屏看尽整条旅程线。
端到端示例(三步串联)
输入:「做一个咖啡从种子到杯子的演示」(纯主题)
→ 步骤 1:WebSearch 研究咖啡产业链 → 事实清单(产地带 / 处理法 / 烘焙度 / 萃取参数,带来源)→ 空间结构:线性斜向旅程线 → 场景:标题开场 → 起源与产地带 → 种植采收 → 三种处理法(该站内部嵌套缩放进三个小场景)→ 烘焙 → 研磨与萃取 → 品鉴 → 全景总览。
→ 步骤 2:真实烘焙机照片走 Wikimedia 搜图并验证;某著作书封电商图床有防盗链 → 降级为 CSS 立体书卡片;「风味轮」搜不到 → gpt-image-2-router 生成「白底简约风味轮插画,黑色线条,暖橙与青绿点缀」。
→ 步骤 3:Write 单文件 html,impress.js 引擎,坐标照搬步骤 1,图文左右并排,末尾 overview 全景 → 打包 → Cloudflare 部署 → Telegram 交付。