slideshow
Author a HyperFrames slideshow — a presentation, pitch deck, or interactive deck with discrete slides, fragment reveals, branching, hotspot navigation, and built-in presenter mode with speaker notes; also converts an existing page into a deck. Output is a navigable deck, not a rendered MP4. If the user didn't explicitly ask for a slideshow, confirm before authoring. Unclear → /hyperframes.
1How It Works & Mechanism
Artifact definition precedes everything: Deliver a "live deck" rather than an MP4, and explicitly forbid passing the deck to hyperframes render — because a deck is composed of multiple top-level scenes without a master root, render only parses the first composition and silently truncates it into a short clip.
**Do not `hyperframes render` a slideshow into a single MP4.**
The implementation mechanism is "standard compositions + a declarative JSON island": Compositions remain HF scenes/clips/GSAP; the additional piece is an application/hyperframes-slideshow+json block, which the player's SlideshowController reads to turn continuous timelines into a discretely navigable deck.
A HyperFrames slideshow is a normal HyperFrames composition — scenes, clips, GSAP timelines — with one extra ingredient: a **JSON island**
The island must be a physical DOM block, placed flexibly but positioned early in the body: present statically parses the composition HTML; if the manifest is hidden behind other script tags and generated at runtime, present will fail to read it.
The `present` command reads the composition HTML statically and expects the real `application/hyperframes-slideshow+json` island to already be present.
Fragments are reveal stops at **absolute composition time**, and navigation is driven by deterministic seeks rather than playback: Entering a slide with fragments immediately seeks to fragments[0] and pauses; Next sequentially seeks to the subsequent stop.
Navigation is seek-driven, not play-driven.
Branches are real scenes that simply aren't listed in the main sequence: Clicking a hotspot pushes {sequenceId, slideIndex:0} onto the stack to enter the branch entry, back pops the stack to return to the parent slide, and backToMain clears the stack; breadcrumbs and counters are rendered per sequence scope.
Clicking a hotspot pushes `{sequenceId, slideIndex: 0}` onto the nav stack and enters the branch's first slide.
Authoring discipline is a hard constraint rather than a suggestion (full-sentence headlines, one idea per slide, lead with the hardest-hitting point, bottom-up market sizing, minimum font sizes, and searching the live catalog for off-the-shelf blocks before writing), complete with rationale: Non-compliant slides are replaced outright during review.
**Headline is a complete-sentence claim, not a label.**
Porting existing pages requires fidelity down to the mechanism level: Native media elements serve as the single source of truth, visual states are derived from media events and media.currentTime, font tokens must resolve to concrete font stacks, and screenshot-type evidence must use contain at its native aspect ratio rather than cover.
Treat native `<video>` / `<audio>` elements as the source of truth for any custom media chrome, canvas visualizer, waveform, beat grid, or playhead.
Presenter mode is owned by shared components: Present button / P key, opens a new audience tab, synchronized across tabs via BroadcastChannel; speaker notes are edited in the presenter view and stored in localStorage (overriding the manifest without mutating the composition file).
**Presenter mode:** use the built-in Present icon button in the slideshow nav capsule, or press P.
Media cleanup and muting are controller responsibilities with cross-realm nuances: The controller calls stopMedia on slide/sequence transitions; fragment navigation within the same slide does not clear media; iframe media cannot be tested with the parent page's instanceof (returns false in real browsers).
The slideshow controller owns slide-exit media cleanup.
The standalone harness is an interim solution rather than the standard path: Until the engine-managed path (preview --slideshow / studio present mode) lands, running demos via a bare player requires three workarounds (exposing a seekable root timeline, copying the island into the wrapper, and letting the wrapper own audio).
These patterns are a **temporary workaround** for standalone demos.
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | 官方 hyperframes CLI:present(起 deck 服务与讲者/观众同步)、lint、check、preview、snapshot(逐页静帧) |
| package | 播放器构建产物(本仓 packages/player/dist 的 hyperframes-player / hyperframes-slideshow 全局包;改播放器行为后需在 packages/player 跑 bun run build) |
| network | CDN 资源(harness 示例):Three.js 模块从 jsdelivr 导入,供独立 demo 的 3D 背景层使用(产物期由浏览器拉取,按范式不判级) |
| package | 浏览器平台 API(非外部服务):BroadcastChannel 讲者/观众同步、localStorage 备注持久化、postMessage 与 iframe 播放器通信、WebAudio/Audio 自持音效 |
| package | 兄弟 skill 关联:deck 内容来自 Figma 时必须先跑 /figma(资产导出/品牌令牌/分镜重建),基础合成契约在 /hyperframes-core,词级字幕规则在 /embedded-captions |
| cli | 官方 registry 搜索/安装(写页面前先 catalog 查现成视觉积木,需要时 add 进 deck) |
4Recommended Governance & Evidence
- scripts/: Execute local scripts or commands: No bundled scripts inside this skill directory (contains 2 files: SKILL.md + references/standalone-harness.md); ha
- 网络端点: Declare external network access: Artifact runtime (unrated per conventions, logged only): harness Three.js sample imports three@0.160.0 from cdn.jsdelivr.net, fetched by the browser
- 本地工作目录: File I/O and artifact output: Project files (authored by agent): composition HTML (containing island and scene divs), wrapper/index.html, and composition/
5Second-Pass Verification
- [ok] 网络面是否真如声明(蓝档判定的关键反例检查) — 全目录仅 1 处 http(s) 命中:standalone-harness.md 第 895 行的 three@0.160.0 jsdelivr 导入(示例代码块内);无 fetch(、无 process.env、无 child_process、无凭证关键词。SKILL.md 侧只有本地命令(present/lint/check/preview/snapshot)与浏览器 API(BroadcastChannel/localStorage/postMessage),均为本地或浏览器内行为。
- [ok] 「禁止 render」的声明是否与机理自洽(不是随口警告) — SKILL.md 给出原因:deck 由多个顶层 scene 合成(每页一个 data-composition-id)且**没有 master-root 合成**,所以 render 只解析第一个合成,产出静默截断的 MP4(举例 6s/40s);并说明线性导出(仅主线、排除分支)目前是 deferred,故支持输出为 present 活 deck 与逐页 snapshot。声明与结构描述一致。
- [ok] island 的「静态可读」要求与 present 行为是否一致 — 文档明确 present 静态解析合成 HTML、期望真实的 application/hyperframes-slideshow+json 已存在,并禁止用另一个 application/json 块 + 运行时代码生成 island。这与「JSON 岛是唯一真源、sceneId 必须匹配 data-composition-id」的 lint 契约自洽。
- [ok] harness 内容是否被当成正统做法(避免误判为「本 skill 主张两套实现」) — harness 开头即写 interim framing(临时绕行)与「When that path ships, most of what follows collapses」,SKILL.md 亦写「Do not treat the patterns there as the blessed model」。两处口径一致,属过渡文档而非第二套正统。
- [ok] 是否存在夸大(把引擎/播放器能力算作本 skill 能力) — 文档反复把导航、presenter mode、媒体清理、静音归给共享播放器组件(<hyperframes-slideshow> / SlideshowController / hyperframes-player.stopMedia),本 skill 只声明 island 数据契约与写作/移植纪律,未见据他人之功。
6Verdict & Scenarios
034ea590dd179243…