Agent skill

HyperFrames Slideshow Authoring

by heygen-com in heygen-com/hyperframes

Builds a navigable deck with discrete slides, fragment reveals, and branching, instead of rendering a flat video, with built-in presenter notes.

Apache-2.0Auto-check passedDocuments & Office

Install HyperFrames Slideshow Authoring

skills CLI
$ npx skills add heygen-com/hyperframes --skill slideshow -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install heygen-com/hyperframes slideshow --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/heygen-com/hyperframes.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/slideshow .claude/skills/slideshow && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
slideshow
GitHub stars
58k
Used in
3 other repos
Token cost
~8.5k tokens
SKILL.md length
3,606 words
Files
2 (incl. references)
Skills in repo
32
Repo updated
First seen
Licence
Apache-2.0

At a glance

Builds a navigable deck with discrete slides, fragment reveals, and branching, instead of rendering a flat video, with built-in presenter notes.

  • Works in 2 steps: Scenes — declared the normal way → The JSON island — one script block per…
  • Building an interactive pitch deck or presentation instead of a linear video
  • SKILL.md covers Output — a navigable deck, not…, Intent confirmation, The two pieces and Schema, plus 9 more sections
  • Calls npx and bun

What it does

This skill authors a slideshow as a normal composition of scenes and timelines, plus one addition: a JSON block declaring which scenes count as slides and how they connect. A player component reads that block at runtime and turns what would otherwise be one continuous timeline into a deck you can navigate discretely, with fragment reveals, branching paths, and hotspot-driven navigation.

The output is the running, presentable deck itself rather than an exported video file, served through a present command that also drives presenter mode with speaker notes. When a deck's content comes from a Figma file, it defers to a dedicated Figma skill for asset export and brand-token handling rather than pulling raw design data directly, since that keeps assets clean and later brand changes able to propagate.

When your agent uses it

  • Building an interactive pitch deck or presentation instead of a linear video
  • Converting an existing composition into a navigable slide deck
  • Adding fragment reveals or branching navigation to a presentation

Example prompts

  • “Turn this scene into a slideshow with branching navigation.”
  • “Build a pitch deck from this Figma file with presenter notes.”
  • “Add fragment reveals so each slide's bullets appear one at a time.”

Requirements

  • The hyperframes CLI or Studio for presenting the deck

Workflow steps

2 steps, taken from the step headings in SKILL.md.

  1. Scenes — declared the normal way
  2. The JSON island — one script block per composition

What it can do on your machine

Read from SKILL.md and the folder at commit f6b3821. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npx
    • bun

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npx, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

HyperFrames Slideshow Authoring loads about 8.5k tokens when it runs, and up to ~19k if it reads all its reference files. Until then it costs about 101 tokens; SKILL.md has 3,606 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~101
When it runs · the whole SKILL.md, loaded when a task matches
~8.5k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~19k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from heygen-com/hyperframes at commit f6b3821, republished under its Apache-2.0 licence (© heygen-com). 3,606 words, ~8,452 tokens.

Download SKILL.mdSave it as .claude/skills/slideshow/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
slideshow
description
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.

Plugin installs: Before setup or freshness commands, follow plugin execution rules when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.

First, keep this skill fresh — confirm with the user before running: npx hyperframes skills update slideshow. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.

figma source: If the deck's content or storyboard comes from a figma.com URL, run /figma first — asset export, brand tokens, and storyboard reconstruction if the source is a strip of scene frames — then build from its output. Don't drive Figma via raw MCP tools directly: that skips SVG sanitization, .media/manifest.jsonl provenance, and brand-token var() binding, so a later brand change can't propagate without a full re-import.

Slideshow authoring contract

A HyperFrames slideshow is a normal HyperFrames composition — scenes, clips, GSAP timelines — with one extra ingredient: a JSON island that declares which scenes are slides and how they connect. The player's SlideshowController reads the island and turns the continuous GSAP timeline into a discrete, navigable deck.

Read /hyperframes-core first for the base composition contract (clips, tracks, data-* attributes, determinism rules). This skill covers only what is new: the island schema, slide writing rules, fragments, branching, validation, and the wrapping component.

Output — a navigable deck, not a linear MP4

A slideshow's output is the running deck: serve it with hyperframes present <project-dir> (or Studio present mode) — the player's SlideshowController reads the island and drives navigation, fragments, branching, and presenter mode. See Presenting and handoff below.

Do not hyperframes render a slideshow into a single MP4. A deck is authored as several top-level scene compositions (one data-composition-id per slide) with no master-root composition wrapping them, so render resolves only the first composition and emits a silently truncated MP4 (e.g. 6s of a 40-second deck). A linear main-line export (main slides only, branch sequences excluded) is deferred — until it ships, the supported outputs are the live present deck and per-slide snapshot stills. If a user needs a linear MP4 today, surface this limitation rather than pointing render at the deck.

Intent confirmation

If the user explicitly asks for a slideshow, slide show, or HyperFrames slideshow, proceed with this skill. When the request arrived through /hyperframes, the intent layer's triage owns this confirmation — routed here means already confirmed, so don't re-ask; the layer's run-shape questions don't apply (the deliverable is a deck, not a rendered video). A BRIEF.md, when present, carries the confirmed intent — read it.

If the skill triggered from an adjacent request such as "presentation", "pitch deck", "deck", "interactive deck", or "convert this page", pause before authoring and frame the choice before asking for confirmation. Briefly explain that a HyperFrames slideshow means a runnable deck with discrete slides, built-in navigation and presenter mode, editable speaker notes, shared media handling, and validation before handoff. For source-page conversions, also mention that the goal is to preserve the original page's visual design, interactions, motion, and media behavior while translating page movement into slide-to-slide transitions.

Then ask a short confirmation question:

Do you want this as a HyperFrames slideshow?

Use a yes/no choice UI when the environment provides one; otherwise ask the question in plain text.

Do not implement the slideshow until the user says yes. If they say no, stop using this skill — read /hyperframes and let the intent layer re-route. This confirmation is a routing decision, not a preference gate — per ../hyperframes/references/brief-contract.md § 1 it survives autonomous mode ("surprise me" does not skip it): building the wrong deliverable type is a quality failure, not a creative call.


The two pieces

1. Scenes — declared the normal way

Every slide is backed by a scene. Declare scenes with data-composition-id, data-start, data-duration, and data-label:

html
<div
  data-composition-id="problem"
  data-start="0"
  data-duration="8"
  data-label="The problem"
  data-width="1920"
  data-height="1080"
>
  <!-- clips go here -->
</div>

Branch slides (reachable only via a hotspot, excluded from the main line) are declared exactly the same way — they just appear only in a slideSequences entry in the island, not in the main slides array.

2. The JSON island — one script block per composition

Add exactly one <script type="application/hyperframes-slideshow+json"> block to the composition HTML. It holds all slideshow metadata:

html
<script type="application/hyperframes-slideshow+json">
  {
    "slides": [...],
    "slideSequences": [...]
  }
</script>

The island is the single source of truth for slide order, notes, fragment hold-points, hotspots, and branch sequences. Keep it near the top of the <body>, before the scene divs, so it is easy to find.

Do not hide the slideshow manifest behind an alternate <script type="application/json"> block plus runtime code that creates the island. The present command reads the composition HTML statically and expects the real application/hyperframes-slideshow+json island to already be present.


Schema

SlideshowManifest (the top-level island object)
json
{
  "slides": [
    /* SlideRef[] — the main line, in order */
  ],
  "slideSequences": [
    /* SlideSequence[] — off-line branch sequences */
  ]
}
SlideRef
json
{
  "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
}
FieldRequiredNotes
sceneIdyesMust match a scene's data-composition-id exactly (or provide explicit startTime/endTime). The lint rule resolves scenes by data-composition-id.
notesnoPresenter-only text. Never shown to the audience.
fragmentsnoArray of times (seconds) within the slide's [start, end] range — see Fragments below.
hotspotsnoInteractive overlays that trigger a branch — see Branching below.
startTimenoOptional. Override the matched scene's time bounds; defaults to the scene's start/end.
endTimenoOptional. Override the matched scene's time bounds; defaults to the scene's start/end.
ttsScript, ttsAudioUrl, ttsDurationMsnoReserved. Schema fields exist but TTS playback is not yet wired. Omit unless you are pre-populating for a future build.
SlideHotspot
json
{
  "id": "h1",
  "label": "How did we calculate this?",
  "target": "market-deep-dive",
  "region": { "x": 60, "y": 10, "w": 35, "h": 20 }
}
FieldRequiredNotes
idyesUnique within the slide.
labelyesTooltip / button text shown to the audience.
targetyesMust match a SlideSequence.id in slideSequences.
regionnoPercentage-of-slide bounding box: {x, y, w, h} in 0–100. Omit to render the hotspot as a full-slide labeled button instead.
SlideSequence
json
{
  "id": "market-deep-dive",
  "label": "Market sizing methodology",
  "slides": [{ "sceneId": "mkt-1" }, { "sceneId": "mkt-2" }]
}

slides inside a sequence uses the same SlideRef shape as the main line. Fragments and nested hotspots are allowed.


Slide writing rules

These are hard constraints, not suggestions. A slide that violates them will be outright replaced when a reviewer sees it.

  • Headline is a complete-sentence claim, not a label. Write "SMBs spend 14 hours/week on manual scheduling" not "Scheduling problem". The sentence should stand alone if the visual is ignored.
  • One idea + one visual per slide. If you are tempted to add a second bullet cluster or a second chart, split the slide.
  • Lead with the punchline. The strongest point goes first — on the slide and in the deck order. Investors read left-to-right, top-to-bottom, and they stop.
  • Bottom-up market sizing only. Never write "$50B TAM" without showing the math. Build from unit economics up: accounts × ACV, or transactions × take-rate.
  • Font minimum 30pt equivalent. At 1920×1080, a headline is 72–96px; body copy is 48px. Never go below 40px for any text the audience must read.
  • Search the live catalog before hand-building any named visual. For every look, effect, chart, treatment or transition a slide needs — "CRT scanlines", "glitch", "bar chart race", "shimmer sweep", "terminal window" — run npx hyperframes catalog --query "<the visual, in plain English>" --json and read the top results before you author the slide's clips. The search needs nothing installed: no project, no prior add, no account. It ranks the whole hosted registry (~400 blocks and components) from any directory. npx hyperframes add <name> drops the block's source into the deck, where you customize it in place. This applies with extra force when porting a source page: a real block beats the simplified approximation the porting rules below forbid.

Porting source pages

When converting an existing page into a slideshow, source fidelity is part of the contract. Do not replace source-specific widgets with simplified approximations unless the user explicitly asks for a redesign.

  • Preserve the original page's visual design, motion language, interactive behavior, media behavior, and presentation affordances as closely as practical. When the slideshow system supports presenter mode, include speaker notes using the shared editable-notes behavior rather than a deck-specific implementation.
  • Port mechanical visuals from the source DOM/CSS/JS as exactly as practical: custom players, canvas visualizers, timelines, playheads, stems, expanding circles, hover states, and other interactive details should survive the conversion.
  • Treat native <video> / <audio> elements as the source of truth for any custom media chrome, canvas visualizer, waveform, beat grid, or playhead. Wire the source's media events (play, pause, timeupdate, seeking, seeked, ended, ratechange, volumechange) and derive visual state from media.currentTime; do not run a separate timer that can drift away from actual playback.
  • Every copied <video> or <audio> with src must have HyperFrames timing attributes before lint: data-start and data-duration, plus data-has-audio="true" when audible native audio should be preserved. Use the scene's time range for slide-specific media; for user-controlled evidence videos that may be played from multiple focused slides, use a deck-wide range. Do not leave preload="none" on media; use metadata or auto.
  • Resolve source font tokens before validation. If preserving custom source fonts, add @font-face rules for local/captured font files. If using system fallbacks, replace tokenized declarations such as font-family: var(--f-body) with concrete render-safe stacks such as system-ui, sans-serif or ui-monospace, monospace; do not leave var(...) as the font family value.
  • Audit the source for atypical page movement, especially behavior driven by scroll, wheel, touch, hash state, resize, or a requestAnimationFrame loop. Treat fixed viewports with translated/scaled "world" layers, parallax, pinned panels, horizontal scrollers, scroll-scrubbed timelines, section snapping, and zoom-to-element cameras as source behavior. Scroll is often the source's transition trigger, so preserve the transition by extracting its progress stops, easing, and camera/focus states, then re-host that motion on slideshow navigation through timeline positions, fragments, or a reusable player/harness hook. Standalone wrappers that jump to slide hold-points still need an explicit navigation-camera transition hook; computing per-slide camera transforms is not enough. Do not simulate a literal page-scroll-down transition inside the slide; the viewer should feel camera travel/zoom from one focal point to another, not see a webpage being scrolled. Keep each slide-to-slide camera move continuous: avoid intermediate route stops that reverse x/y direction or zoom unless the source visibly does that at the same boundary. A transition that darts around before landing is worse than a simpler direct focal move.
  • Preserve the source's media crop semantics. Treat screenshots, tweets/social posts, product UI captures, charts, docs, code, leaderboards, and any image with readable text as content evidence, not decorative media: use the source aspect ratio (height: auto) or object-fit: contain inside a stable frame. Use object-fit: cover only when the source did, or for intentionally decorative/background/cinematic thumbnails. After fitting these captures into a slide, inspect all four edges for truncated text, logos, controls, or captions; a visible crop on meaningful content is a bug unless the source itself cropped it.
  • If a behavior is generic to slideshows, put it in the player/controller or in a reusable skill snippet. Do not solve it with one-off deck scripts.
  • Stacked scene frames must never block interaction on the active slide. Hidden frames need both visual hiding and event gating:
css
.scene-frame {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.scene-frame.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

If visibility is driven imperatively, set all three properties (opacity, visibility, and pointerEvents) in the visibility controller. opacity: 0 alone still leaves an invisible layer that can swallow clicks.


Fragments: reveal hold-points within a slide

A fragment is an absolute composition-timeline time (seconds) within a slide's [start, end] range where the controller should hold a reveal state.

How it works:

  1. Player enters a fragmented slide — seeks directly to fragments[0] and holds there.
  2. User presses Next (or →) — controller seeks to fragments[1] and holds.
  3. After the last fragment, Next advances to the next slide.
  4. A slide without fragments enters at a rest frame inside the slide, usually its midpoint, not exactly at slide.end.

Fragment times must fall within [start, end] (inclusive of both bounds). The lint rule rejects only fragments outside that range (time < start or time > end).

Fragment times are absolute composition-timeline positions — the same coordinate space as data-start — not offsets relative to the scene's start.

Navigation is seek-driven, not play-driven. The controller never starts playback just to move between fragments; each navigation command is a deterministic seek to the target hold time. Design fragment states so they are correct at the target timeline time.


Branching: hotspots and slide sequences

Branch slides are real scenes in the same composition timeline. They are listed only under slideSequences and are excluded from main-line navigation — the player never visits them unless a hotspot fires.

Navigation model:

  • Clicking a hotspot pushes {sequenceId, slideIndex: 0} onto the nav stack and enters the branch's first slide.
  • back() pops the stack and returns to the exact parent slide (the one that held the hotspot).
  • backToMain() clears the entire stack and returns to the root slide.
  • Breadcrumb renders from the stack: Main deck › Market sizing methodology › Slide 2.
  • The slide counter inside a branch is scoped to that sequence (1 of 2, not the main-deck total).

What to avoid:

  • Do not add branch scene IDs to the main slides array. They must appear only inside a slideSequences entry. The lint rule flags overlap.
  • Branch scenes are included in the continuous timeline, so a naive linear video export would include them. Export reads main-line slides only (deferred; flagged in the spec).

Worked example: 3-slide deck with fragments and a branch

Scene HTML (skeleton)
html
<body style="margin: 0">
  <script type="application/hyperframes-slideshow+json">
    {
      "slides": [
        {
          "sceneId": "hook",
          "notes": "Open with the stat. Pause on the $40B number."
        },
        {
          "sceneId": "problem",
          "notes": "Walk through each pain point one at a time.",
          "fragments": [11.0, 15.0],
          "hotspots": [
            {
              "id": "h1",
              "label": "Where does the $40B figure come from?",
              "target": "market-detail",
              "region": { "x": 55, "y": 60, "w": 40, "h": 20 }
            }
          ]
        },
        {
          "sceneId": "solution",
          "notes": "One sentence: what we do and who it is for."
        }
      ],
      "slideSequences": [
        {
          "id": "market-detail",
          "label": "Market sizing methodology",
          "slides": [{ "sceneId": "mkt-math", "notes": "Bottom-up: 2.3M SMBs × $17k ACV." }]
        }
      ]
    }
  </script>

  <!-- Slide 1 — hook -->
  <div
    data-composition-id="hook"
    data-start="0"
    data-duration="6"
    data-label="The hook"
    data-width="1920"
    data-height="1080"
    style="position: relative; width: 1920px; height: 1080px; overflow: hidden; background: #0a0a0a"
  >
    <section
      class="clip"
      data-start="0"
      data-duration="6"
      data-track-index="1"
      style="position: absolute; inset: 0; display: grid; place-items: center"
    >
      <h1 id="hook-headline" style="font-size: 80px; color: #fff; font-family: sans-serif">
        SMBs lose $40B/year to manual scheduling
      </h1>
    </section>
  </div>

  <!-- Slide 2 — problem (3 fragments) -->
  <div
    data-composition-id="problem"
    data-start="6"
    data-duration="15"
    data-label="The problem"
    data-width="1920"
    data-height="1080"
    style="position: relative; width: 1920px; height: 1080px; overflow: hidden; background: #0a0a0a"
  >
    <section
      class="clip"
      data-start="6"
      data-duration="15"
      data-track-index="1"
      style="position: absolute; inset: 0; padding: 120px 160px; box-sizing: border-box"
    >
      <h2 id="pain-headline" style="font-size: 64px; color: #fff; font-family: sans-serif">
        Three gaps operators can not close
      </h2>
      <p id="pain-1" style="font-size: 48px; color: #ccc; opacity: 0; font-family: sans-serif">
        No-shows cost 23% of booked revenue
      </p>
      <p id="pain-2" style="font-size: 48px; color: #ccc; opacity: 0; font-family: sans-serif">
        Manual reminders take 4h/week per staff
      </p>
      <p id="pain-3" style="font-size: 48px; color: #ccc; opacity: 0; font-family: sans-serif">
        Rescheduling friction drives 40% churn
      </p>
    </section>
  </div>

  <!-- Slide 3 — solution -->
  <div
    data-composition-id="solution"
    data-start="21"
    data-duration="8"
    data-label="The solution"
    data-width="1920"
    data-height="1080"
    style="position: relative; width: 1920px; height: 1080px; overflow: hidden; background: #0a0a0a"
  >
    <section
      class="clip"
      data-start="21"
      data-duration="8"
      data-track-index="1"
      style="position: absolute; inset: 0; display: grid; place-items: center"
    >
      <h2 id="solution-headline" style="font-size: 72px; color: #fff; font-family: sans-serif">
        Acme automates scheduling for service SMBs — no-shows down 80% in 90 days
      </h2>
    </section>
  </div>

  <!-- Branch slide — excluded from main line -->
  <div
    data-composition-id="mkt-math"
    data-start="29"
    data-duration="7"
    data-label="Market math"
    data-width="1920"
    data-height="1080"
    style="position: relative; width: 1920px; height: 1080px; overflow: hidden; background: #111"
  >
    <section
      class="clip"
      data-start="29"
      data-duration="7"
      data-track-index="1"
      style="position: absolute; inset: 0; display: grid; place-items: center"
    >
      <p id="mkt-formula" style="font-size: 56px; color: #fff; font-family: sans-serif">
        2.3M SMBs × $17k ACV = $39B serviceable market
      </p>
    </section>
  </div>

  <script>
    window.__timelines = window.__timelines || {};

    // Slide 2 fragment entrance animations
    gsap.registerPlugin(); // load any plugins before use

    const tl = gsap.timeline({ paused: true });
    window.__timelines["problem"] = tl;

    // Insert positions are absolute composition-timeline times (same as data-start / fragment values).
    tl.from("#pain-1", { opacity: 0, y: 20, duration: 0.4 }, 11.0);
    tl.from("#pain-2", { opacity: 0, y: 20, duration: 0.4 }, 15.0);
    // pain-3 lands at end of slide
    tl.from("#pain-3", { opacity: 0, y: 20, duration: 0.4 }, 13.0);
  </script>
</body>
Show full SKILL.md (1,458 more words)Show less
Key points in the example
  • The island sceneId values ("hook", "problem", "solution", "mkt-math") exactly match data-composition-id values on scene divs.
  • mkt-math appears only in slideSequences — it is never in the top-level slides array.
  • Fragment times (11.0, 15.0) are within the problem scene's [6, 21] range (times are absolute composition-timeline positions).
  • The hotspot region (x: 55, y: 60, w: 40, h: 20) positions the clickable area in the lower-right quadrant of the problem slide.
  • GSAP timelines are registered on window.__timelines and are paused — the HyperFrames engine drives playback; do not call .play() at construction time.

Wrapping component

Wrap the composition in <hyperframes-slideshow> around <hyperframes-player> in any embedding context:

html
<hyperframes-slideshow>
  <hyperframes-player src="deck.html"></hyperframes-player>
</hyperframes-slideshow>

<hyperframes-slideshow> provides the navigation chrome (Present, Prev / Next, counter, global mute when sound is present, fullscreen), keyboard handling (← / →, Space / Backspace, and P for Present), touch swipe, and hotspot overlays.

The slideshow automatically sets the interactive attribute on every inner <hyperframes-player> at mount time, so clickable controls, links, native media controls, and custom players inside the composition iframe receive pointer events as expected. (Outside a slideshow wrapper, you must add interactive manually on <hyperframes-player> — the player defaults to pointer-events: none on the iframe so clicks on the player host don't get hijacked into toggling timeline playback.)

Presenter mode: use the built-in Present icon button in the slideshow nav capsule, or press P. It calls window.open('?mode=audience') for a fullscreen audience tab; the originating tab becomes the presenter view (current slide reduced, next-slide preview, notes, elapsed timer). The two tabs sync via BroadcastChannel('hf-slideshow:' + location.pathname). Do not add a custom wrapper-level Present button; the shared component owns its placement, icon, styling, and audience-mode hiding.

Presenting over Google Meet / Zoom (screen share): share the audience surface, keep the presenter view on your own screen.

  • Google Meet (or any in-Chrome share): Present → in Meet choose Share screen → A tab → pick the audience tab → switch back to the presenter tab. Chrome keeps a captured tab rendering while backgrounded, so animations and slide nav stay live. Do not share "A window" or "Entire screen" — a fully covered window stops rendering (frozen slides for viewers), and entire-screen exposes your notes.
  • Zoom (desktop app): drag the audience tab out into its own window and share that window. Zoom captures via the OS, so if the audience window becomes fully covered it freezes — use a second monitor, or keep a sliver of the audience window visible behind the presenter view.

Presenter-driven media playback has an autoplay-policy constraint: BroadcastChannel can sync intent, time, and state, but it cannot transfer the presenter's user activation to the audience tab. The shared slideshow player mirrors native media events and starts remote audience playback muted first; only fall back to the standalone harness's audience unlock behavior if muted media.play() is rejected or if the deck specifically requires audible audience playback. Do not keep applying remote timeupdate messages after a rejected play, or the audience will silently seek through the video without playback.

Presenter notes are editable in the presenter view. Edits are stored in localStorage per deck and slide, layered over the manifest notes without rewriting the composition file. Do not add one-off note-editing scripts to decks; rely on the shared slideshow player behavior. If a standalone/custom wrapper truly needs to implement this outside the shared player, use the deterministic storage snippet in references/standalone-harness.md.

Media cleanup on slide exit

The slideshow controller owns slide-exit media cleanup. When navigation changes slide or sequence, it calls hyperframes-player.stopMedia() before entering the next slide. That command:

  • posts stop-media to the iframe runtime, which stops WebAudio and pauses native <video> / <audio> elements;
  • pauses same-origin iframe media directly as a fallback; and
  • pauses parent-frame proxies adopted from iframe media.

Same-slide fragment navigation does not stop media. Global/deck-level parent audio, such as a background track wired through audio-src, is not treated as slide media.

Do not add per-slide cleanup scripts for normal media players. Keep slide video/audio as normal media in the composition; use data-has-audio="true" only when the player should preserve audible native video audio instead of treating it as silent visual media.

If the source page has custom controls or visualizations attached to media, those controls must listen to the same native element the slideshow player stops and mutes. A pause caused by slide exit, presenter sync, native controls, custom controls, or the global mute button should all update the visible custom UI through media events, not through parallel state.

When implementing direct iframe fallback cleanup, treat iframe media as cross-realm DOM. Do not test iframe nodes with the parent page's el instanceof HTMLMediaElement; that returns false in real browsers. Use el.ownerDocument.defaultView.HTMLMediaElement (or an equivalent tag/duck-type guard) before setting muted or calling pause().

Global nav mute

When <hyperframes-slideshow sound> renders the nav mute button, that button is the global mute control for the page. It must mute:

  • child <hyperframes-player> instances, including same-origin iframe media;
  • top-level page <audio> / <video> elements; and
  • wrapper-owned SFX/global Audio objects via the hf-sound event.

Do not add a second mute button inside the composition. If a wrapper script creates new Audio(...) objects that are not attached to the DOM, it must listen for hf-sound and set clip.muted = detail.muted on each object, not merely skip future plays.

The same cross-realm rule applies here: global mute must reach iframe <video> / <audio> elements through the child frame's DOM realm. A passing unit test in a single DOM realm is not enough; verify in a browser that the actual iframe media elements report muted: true after clicking the nav mute button.

hyperframes present serves built bundles from packages/player/dist. After changing player or slideshow chrome behavior, run bun run build in packages/player and restart the present server before testing in a browser.


Running a slideshow standalone (interim)

The durable answer is engine-hosted: hyperframes preview --slideshow / studio present mode will host the composition over the real HyperFrames engine, which drives seek-timelines, owns the gesture frame, and reads the island from the composition. That path is coming; prefer it once it ships.

Until then, standalone demos (a composition opened via the bare player bundle in a browser, without the engine) require workarounds for three gaps: the composition must expose a seekable root timeline, the island must be duplicated into the wrapper, and wrapper-owned SFX/global audio should live in the parent frame. These patterns are documented in:

references/standalone-harness.md

Do not treat the patterns there as the blessed model — they exist only to bridge the gap until the engine-hosted path lands.

Handoff

For a public or user-facing slideshow project, the root index.html should be a runnable slideshow entrypoint. Opening it in a browser should show slideshow navigation and respond to Next/Prev; it should not expose only the raw composition and require the user to know about Studio or an internal wrapper file. If the raw HyperFrames composition must remain separate for CLI compatibility, put it in a subdirectory such as composition/index.html and point scripts/commands at that directory.

The direct-open wrapper must rely on the built-in Present icon button rendered by <hyperframes-slideshow>. Do not add a bespoke #present-btn, fixed-position button, or wrapper-specific Present styling. The shared component owns the control bar, hides Present in ?mode=audience, and supports P as a keyboard shortcut.

Validate the direct-open path before handoff. If file:// browser restrictions break iframe media, local scripts, or same-origin player access, use a self-contained wrapper or make the handoff command start a local server and open the working URL; do not leave index.html in a broken or ambiguous state.

For a completed slideshow deck, the primary user-facing next step is presenter mode, not Studio. Run or provide:

bash
npx hyperframes present <project-dir>

Studio/preview is useful for editing a composition, but it is not a clear final destination for a slideshow user. If you create a package.json for a slideshow project where the raw composition lives in composition/, make the default runnable script start presenter mode:

json
{
  "scripts": {
    "dev": "npx hyperframes present ./composition",
    "studio": "npx hyperframes preview ./composition --background"
  }
}

At handoff, include the local presenter URL printed by the command and the minimal instruction: "Click Present, or press P, to open the audience tab." If the user will present over Google Meet or Zoom, also pass on the screen-share guidance from the Presenting section above (share the audience tab in Meet; a dragged-out audience window in Zoom). Keep the server running if the user asked you to start it.


Validation

After authoring or editing a slideshow composition, run validation (it reruns lint before opening the browser):

bash
npx hyperframes check

Treat lint errors and validation StaticGuard contract messages as blockers even if a command exits successfully. Fix the file and rerun until check reports no lint or runtime errors.

The slideshow lint rule checks:

  • Every slide.sceneId resolves to an existing scene (by data-composition-id).
  • Every hotspot.target references a defined slideSequence id.
  • Fragment times fall within each slide's [start, end] range.
  • No two main-line slides overlap in time.

Fix all violations before previewing. A composition that fails lint will not parse correctly in the player.

© heygen-com, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (references) in skills/slideshow of heygen-com/hyperframes.

  • SKILL.md
  • references/standalone-harness.md

Open the folder on GitHubat commit f6b3821

Used in 3 other repositories

We found 3 copies of this SKILL.md (exact, near-identical or edited) in other folders, from 3 other GitHub owners. This page covers the copy in heygen-com/hyperframes, which our catalogue first saw on October 7, 2026.

Compare with similar skills

HyperFrames Slideshow Authoring next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

HyperFrames Slideshow Authoring compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
HyperFrames Slideshow Authoring this skillheygen-com/hyperframes58k3 repos~8.5kAutomated safety check: PassApache-2.0
Visual Stylecalesthio/OpenMontage65k—~1.5kAutomated safety check: PassAGPL-3.0
Video Template Frame Creative Voltagenexu-io/open-design100k—~376Automated safety check: PassApache-2.0
Make Deckbluzir/claude-code-design106—~2.7kAutomated safety check: PassNone
Slides GrabNomaDamas/slides-grab1.2k—~1.3kAutomated safety check: PassMIT
Slides Grab ExportNomaDamas/slides-grab1.2k—~1kAutomated safety check: PassMIT

Similar skills

  • Visual Style

    calesthio/OpenMontage

    Create, extract, and apply portable visual design systems via visual-style.md files.

    65k GitHub stars~1.5k tokensUpdated 4 days ago
    Frontend & DesignAuto-check passed
  • Use this plugin when the user wants a "Creative Voltage Frame" HyperFrames motion video — Electric split with hand-drawn script — offset panels slide in, display title rises with an outlined word…

    100k GitHub stars~376 tokensUpdated today
    Documents & OfficeAuto-check passed
  • Make Deck

    bluzir/claude-code-design

    Build an HTML slide deck (1920×1080, keyboard nav, exportable) when user asks for a presentation, pitch deck, slides, or keynote.

    106 GitHub stars~2.7k tokensUpdated 5 mo ago
    Documents & OfficeAuto-check passed
  • Slides Grab

    NomaDamas/slides-grab

    End-to-end presentation workflow usable in Codex and Claude Code.

    1.2k GitHub stars~1.3k tokensUpdated 6 days ago
    Documents & OfficeAuto-check passed
  • Slides Grab Export

    NomaDamas/slides-grab

    Stage 3 conversion skill usable in Codex and Claude Code. An agent skill from NomaDamas/slides-grab.

    1.2k GitHub stars~1k tokensUpdated 6 days ago
    Documents & OfficeAuto-check passed
  • Article To HTML

    agentara/skills

    Render a markdown draft / any document in the conversation context into a single-file "paper proposal" HTML — serif body, monospace meta, numbered sections, inline SVG figures, callouts, tables…

    600 GitHub stars~1.7k tokensUpdated 8 days ago
    Documents & OfficeAuto-check passed

More from heygen-com/hyperframes

All 32 skills in this repo
  • HyperFrames Animation

    heygen-com/hyperframes

    Collects motion rules, scene blueprints, transitions and runtime adapters for HyperFrames video compositions, with GSAP as the default animation runtime.

    58k GitHub starsUsed in 3 repos~2.1k tokens
    Auto-check passed
  • HyperFrames Media Use

    heygen-com/hyperframes

    Finds, generates and edits media for HyperFrames video projects: music, sound effects, images, icons, logos, voiceovers, captions and color grades.

    58k GitHub starsUsed in 2 repos~2.1k tokens
    Auto-check passed
  • Embedded Video Captions

    heygen-com/hyperframes

    Adds captions to a single-subject talking-head video without editing the footage, from plain subtitles to cinematic text placed behind the speaker.

    58k GitHub starsUsed in 3 repos~8.6k tokens
    Auto-check passed
  • Weekly Changelog Video

    heygen-com/hyperframes

    Turns a weekly changelog markdown file into a branded HyperFrames video with voiceover, animated mock-UI scenes and captions, using fonts, background and scripts bundled in the skill.

    58k GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Faceless Explainer Video

    heygen-com/hyperframes

    Turns an article, notes or a topic brief into an explainer video whose visuals are invented per scene, built frame by frame in HyperFrames with no footage.

    58k GitHub starsUsed in 3 repos~7.5k tokens
    Auto-check: notes
  • Figma to HyperFrames

    heygen-com/hyperframes

    Imports Figma assets, brand tokens, components and motion into a HyperFrames video composition, using the Figma REST API with a connector or native export for shaders.

    58k GitHub starsUsed in 3 repos~4.5k tokens
    Auto-check: notes

Works with

Questions about HyperFrames Slideshow Authoring

What does HyperFrames Slideshow Authoring do?

Builds a navigable deck with discrete slides, fragment reveals, and branching, instead of rendering a flat video, with built-in presenter notes. This skill authors a slideshow as a normal composition of scenes and timelines, plus one addition: a JSON block declaring which scenes count as slides and how they connect. A player component reads that block at runtime and turns what would otherwise be one continuous timeline into a deck you can navigate discretely, with fragment reveals, branching paths, and hotspot-driven navigation.

When should I use HyperFrames Slideshow Authoring?

HyperFrames Slideshow Authoring fits situations like: building an interactive pitch deck or presentation instead of a linear video; converting an existing composition into a navigable slide deck; adding fragment reveals or branching navigation to a presentation.

How do I install HyperFrames Slideshow Authoring in Claude Code?

Run `npx skills add heygen-com/hyperframes --skill slideshow -a claude-code`. Or copy the skill folder (skills/slideshow in heygen-com/hyperframes) into .claude/skills/slideshow in your project. Claude Code loads it when a task matches its description.

How do I install HyperFrames Slideshow Authoring in Codex?

Run `npx skills add heygen-com/hyperframes --skill slideshow -a codex`. Or copy the skill folder (skills/slideshow in heygen-com/hyperframes) into .agents/skills/slideshow in your project. Codex loads it when a task matches its description.

Can I use HyperFrames Slideshow Authoring in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add heygen-com/hyperframes --skill slideshow -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/slideshow, .gemini/skills/slideshow, .github/skills/slideshow and .opencode/skills/slideshow in your project.

What does HyperFrames Slideshow Authoring need to run?

Going by SKILL.md and its folder, HyperFrames Slideshow Authoring needs the command-line tools its instructions call (npx and bun). Our summary lists: The hyperframes CLI or Studio for presenting the deck.

Does HyperFrames Slideshow Authoring access the network?

SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is HyperFrames Slideshow Authoring safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does HyperFrames Slideshow Authoring use?

HyperFrames Slideshow Authoring is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does HyperFrames Slideshow Authoring use?

About 8.5k tokens (SKILL.md is roughly 34k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 11k tokens, read only when the agent opens those files.

What are the alternatives to HyperFrames Slideshow Authoring?

Skills that share tags, products or a category with HyperFrames Slideshow Authoring: Visual Style (calesthio/OpenMontage, 65k stars), Video Template Frame Creative Voltage (nexu-io/open-design, 100k stars), Make Deck (bluzir/claude-code-design, 106 stars) and Slides Grab (NomaDamas/slides-grab, 1.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains HyperFrames Slideshow Authoring?

heygen-com (a GitHub organization) maintains it in heygen-com/hyperframes, which has 58,020 GitHub stars. The repository holds 32 skills in this directory. The repository was last updated on October 7, 2026.

Source: heygen-com/hyperframes on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.