首先,让此技能保持最新 —— 静默运行,无需询问:
npx hyperframes skills update slideshow。如果一切已是最新,它是一个快速的无操作命令;否则它会在你依赖之前刷新此技能及其依赖的核心领域技能。
figma 源:如果deck的内容或故事板来自 figma.com URL,请先运行
/figma—— 资产导出、品牌令牌和故事板重建(如果源是一系列场景帧)—— 然后从其输出构建。不要直接通过原始MCP工具驱动Figma:这会跳过SVG净化、.media/manifest.jsonl溯源以及品牌令牌var()绑定,因此后续的品牌更改无法在不重新导入的情况下传播。
幻灯片制作合同
HyperFrames幻灯片是一个普通的HyperFrames构图 —— 场景、剪辑、GSAP时间线 —— 但多了一个额外成分:一个JSON island,它声明哪些场景是幻灯片以及它们如何连接。播放器的SlideshowController读取该island,并将连续的GSAP时间线转换为离散、可导航的deck。
请先阅读 /hyperframes-core 了解基础构图合同(剪辑、轨道、data-* 属性、确定性规则)。此技能仅涵盖新增内容:island模式、幻灯片编写规则、片段、分支、验证以及包装组件。
输出 —— 可导航的deck,而非线性MP4
幻灯片的输出是运行中的deck:使用 hyperframes present <project-dir>(或 Studio 演示模式)提供服务 —— 播放器的SlideshowController读取island并驱动导航、片段、分支和演示者模式。请参阅下面的演示和交接部分。
请勿将幻灯片 hyperframes render 为单个MP4。 Deck的作者是几个顶层场景构图(每个幻灯片一个 data-composition-id),并且没有主根构图包裹它们,因此 render 仅解析第一个构图并输出一个静默截断的MP4(例如,一个40秒的deck只输出6秒)。线性主线导出(仅主幻灯片,不包括分支序列)被推迟 —— 在该功能发布之前,支持的输出是实时present deck和每张幻灯片的 snapshot 静态图像。如果用户需要线性MP4,请说明此限制,而不是将 render 指向deck。
意图确认
如果用户明确要求幻灯片、幻灯片演示或HyperFrames幻灯片,请按此技能执行。当请求通过 /hyperframes 到达时,意图层的分流负责此确认 —— 路由至此意味着已确认,因此不要重新询问;该层的运行形状问题不适用(交付物是一个deck,而不是渲染的视频)。当存在 BRIEF.md 时,它携带已确认的意图 —— 请阅读它。
如果此技能从相邻请求触发,例如“演示文稿”、“推介deck”、“deck”、“交互式deck”或“转换此页面”,请在制作前暂停,并在请求确认之前呈现选择。简要说明,HyperFrames幻灯片意味着一个可运行的deck,包含离散的幻灯片、内置导航和演示者模式、可编辑的演讲者笔记、共享媒体处理以及交接前的验证。对于源页面转换,还需提到目标是保留原始页面的视觉设计、交互、动效和媒体行为,同时将页面移动转换为幻灯片过渡。
然后询问一个简短的确认问题:
您希望将其作为 HyperFrames 幻灯片吗?
如果环境提供是/否选择UI,则使用它;否则以纯文本形式提问。
在用户回答“是”之前,不要实施幻灯片。如果他们回答“否”,请停止使用此技能 —— 阅读 /hyperframes 并让意图层重新路由。此确认是一个路由决策,而非偏好门 —— 根据 ../hyperframes-core/references/brief-contract.md § 1,它在自主模式下仍然有效(“给我惊喜”不会跳过它):构建错误的交付类型是质量失败,而非创意决定。
两部分
1. 场景 —— 正常声明
每张幻灯片都由一个场景支持。使用 data-composition-id、data-start、data-duration 和 data-label 声明场景:
<div
data-composition-id="problem"
data-start="0"
data-duration="8"
data-label="The problem"
data-width="1920"
data-height="1080"
>
<!-- 剪辑在此处 -->
</div>
分支幻灯片(仅通过热点可访问,从主线中排除)的声明方式完全相同 —— 它们仅出现在island的 slideSequences 条目中,而不是主 slides 数组中。
2. JSON island —— 每个构图一个脚本块
在构图HTML中恰好添加一个 <script type="application/hyperframes-slideshow+json"> 块。它包含所有幻灯片元数据:
<script type="application/hyperframes-slideshow+json">
{
"slides": [...],
"slideSequences": [...]
}
</script>
该island是幻灯片顺序、笔记、片段停留点、热点和分支序列的唯一权威来源。将其放在 <body> 顶部附近,场景div之前,以便易于查找。
不要将幻灯片清单隐藏在替代的 <script type="application/json"> 块加运行时代码创建island的方式后面。present 命令静态读取构图HTML,并期望真正的 application/hyperframes-slideshow+json island已经存在。
模式
SlideshowManifest(顶层island对象)
{
"slides": [
/* SlideRef[] — 主线,按顺序 */
],
"slideSequences": [
/* SlideSequence[] — 离线分支序列 */
]
}
SlideRef
{
"sceneId": "problem",
"notes": "Lead with the pain, not the company.",
"fragments": [3.5, 5.2, 7.0],
"hotspots": [
/* SlideHotspot[] */
],
"ttsScript": null,
"ttsAudioUrl": null,
"ttsDurationMs": null
}
| 字段 | 必需 | 备注 |
|---|---|---|
sceneId | 是 | 必须精确匹配场景的 data-composition-id(或提供显式的 startTime/endTime)。lint规则通过 data-composition-id 解析场景。 |
notes | 否 | 仅演示者可见的文本。从不向观众显示。 |
fragments | 否 | 幻灯片 [start, end] 范围内的时刻数组(秒)—— 请参阅下面的片段部分。 |
hotspots | 否 | 触发分支的交互式叠加层 —— 请参阅下面的分支部分。 |
startTime | 否 | 可选。覆盖匹配场景的时间边界;默认为场景的起始/结束。 |
endTime | 否 | 可选。覆盖匹配场景的时间边界;默认为场景的起始/结束。 |
ttsScript、ttsAudioUrl、ttsDurationMs | 否 | 保留。 存在模式字段但TTS播放尚未连接。除非你正在为未来构建预填充,否则请省略。 |
SlideHotspot
{
"id": "h1",
"label": "How did we calculate this?",
"target": "market-deep-dive",
"region": { "x": 60, "y": 10, "w": 35, "h": 20 }
}
| 字段 | 必需 | 备注 |
|---|---|---|
id | 是 | 在幻灯片内唯一。 |
label | 是 | 向观众显示的工具提示/按钮文本。 |
target | 是 | 必须匹配 slideSequences 中的 SlideSequence.id。 |
region | 否 | 基于幻灯片百分比的边界框:{x, y, w, h} 范围为 0-100。省略则将该热点渲染为一个全幻灯片标记按钮。 |
SlideSequence
{
"id": "market-deep-dive",
"label": "Market sizing methodology",
"slides": [{ "sceneId": "mkt-1" }, { "sceneId": "mkt-2" }]
}
序列内的 slides 使用与主线相同的 SlideRef 结构。允许使用片段和嵌套热点。
幻灯片编写规则
这些是硬性约束,而非建议。违反它们的幻灯片将在审阅者看到时被直接替换。
- 标题是一个完整句子的主张,而不是标签。 写“SMBs spend 14 hours/week on manual scheduling”而不是“Scheduling problem”。即使忽略视觉效果,句子也应能独立存在。
- 每张幻灯片一个想法 + 一个视觉元素。 如果你倾向于添加第二个项目符号簇或第二个图表,请拆分幻灯片。
- 以重点开头。 最有力的观点放在第一位 —— 在幻灯片上和在deck顺序中都是如此。投资者从左到右、从上到下阅读,然后停止。
- 仅进行自下而上的市场规模测算。 切勿在没有显示计算过程的情况下写“$50B TAM”。从单位经济学向上构建:账户数 × ACV,或交易数 × 抽成率。
- 字体最小相当于30pt。 在1920×1080分辨率下,标题为72-96px,正文为48px。对于观众必须阅读的任何文本,切勿低于40px。
移植源页面
在将现有页面转换为幻灯片时,源保真度是合同的一部分。除非用户明确要求重新设计,否则不要用简化的近似值替换源特定的Widget。
- 尽可能精确地保留原始页面的视觉设计、动效语言、交互行为、媒体行为和表现功能。当幻灯片系统支持演示者模式时,请使用共享的可编辑笔记行为来包含演讲者笔记,而不是使用deck特定的实现。
- 尽可能精确地从源 DOM/CSS/JS 移植机械视觉效果:自定义播放器、Canvas可视化工具、时间线、播放头、茎、展开圆圈、悬停状态和其他交互细节应在转换后保留。
- 将原生的
<video>/<audio>元素视为任何自定义媒体chrome、Canvas可视化工具、波形、节拍网格或播放头的权威来源。连接源的媒体事件(play、pause、timeupdate、seeking、seeked、ended、ratechange、volumechange),并从media.currentTime派生视觉状态;不要运行一个可能与实际播放漂移的独立定时器。 - 每个带有
src的复制<video>或<audio>在lint之前必须具有HyperFrames计时属性:data-start和data-duration,以及当应保留可听的原始音频时添加data-has-audio="true"。对于特定幻灯片的媒体,使用场景的时间范围;对于可能从多个聚焦幻灯片播放的用户控制证据视频,使用整个deck的范围。不要将preload="none"留在媒体上;使用metadata或auto。 - 在验证之前解析源字体令牌。如果保留自定义源字体,为本地/捕获的字体文件添加
@font-face规则。如果使用系统回退,将标记化的声明如font-family: var(--f-body)替换为具体的、可安全渲染的堆栈如system-ui, sans-serif或ui-monospace, monospace;不要将var(...)保留为字体族值。 - 审计源中非典型的页面移动,特别是由滚动、滚轮、触摸、哈希状态、调整大小或requestAnimationFrame循环驱动的行为。将固定视口与平移/缩放“世界”层、视差、固定面板、水平滚动器、滚动擦洗时间线、节捕捉和缩放至元素的摄像机视为源行为。滚动通常是源的过渡触发器,因此通过提取其进度停止点、缓动和摄像机/焦点状态来保留过渡,然后将该动效通过时间线位置、片段或可重用的播放器/挂载钩子重新托管在幻灯片导航上。独立包装器跳转到幻灯片停留点仍然需要一个显式的导航-摄像机过渡钩子;计算每张幻灯片的摄像机变换是不够的。不要在幻灯片内部模拟字面的页面向下滚动过渡;观众应该感受到从一个焦点到另一个焦点的摄像机移动/缩放,而不是看到一个网页被滚动。保持每次幻灯片到幻灯片的摄像机移动连续:避免中间路由停止点反转x/y方向或缩放,除非源在该边界上明显地这样做。在着陆前四处移动的过渡比更简单的直接焦点移动更糟糕。
- 保留源的媒体裁剪语义。将屏幕截图、推文/社交媒体帖子、产品UI截图、图表、文档、代码、排行榜以及任何包含可读文本的图像视为内容证据,而非装饰性媒体:在稳定框内使用源的宽高比(
height: auto)或object-fit: contain。仅当源本身这样做时,或对于故意装饰性/背景/电影缩略图,才使用object-fit: cover。在将这些截图放入幻灯片后,检查所有四个边缘是否有被截断的文本、徽标、控件或标题;对有意义内容的可见裁剪是一个错误,除非源本身裁剪了它。 - 如果一个