mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-13 20:58:33 +00:00
## Summary
- 2 skills in `skills/` directory (tool-agnostic, installed via `hyperframes skills`)
- **compose-video** (112 lines): Core HyperFrames composition authoring contract — data attributes, timeline, video/audio rules, GSAP constraints, editing consistency
- `patterns.md`: PiP, title card, slideshow examples (loaded on demand)
- **captions** (138 lines): Tone-adaptive caption styling from transcript analysis — per-word styling, script-to-style mapping, whisper.cpp format reference
## Test plan
- [ ] Skills load in Claude Code
- [ ] compose-video under 500 lines, no `assets/` or `fonts/` references
- [ ] Captions skill triggers on tone detection keywords
🤖 Generated with [Claude Code](https://claude.com/claude-code)
2.7 KiB
2.7 KiB
Composition Patterns
Picture-in-Picture (Video in a Frame)
Animate a wrapper div for position/size. The video fills the wrapper. The wrapper has NO data attributes.
<div
id="pip-frame"
style="position:absolute;top:0;left:0;width:1920px;height:1080px;z-index:50;overflow:hidden;"
>
<video
id="el-video"
data-start="0"
data-duration="60"
data-track-index="0"
src="talking-head.mp4"
muted
playsinline
></video>
</div>
tl.to(
"#pip-frame",
{ top: 700, left: 1360, width: 500, height: 280, borderRadius: 16, duration: 1 },
10,
);
tl.to("#pip-frame", { left: 40, duration: 0.6 }, 30);
Title Card with Fade
<div
id="title-card"
data-start="0"
data-duration="5"
data-track-index="5"
style="display:flex;align-items:center;justify-content:center;background:#111;z-index:60;"
>
<h1 style="font-size:64px;color:#fff;opacity:0;">My Video Title</h1>
</div>
tl.to("#title-card h1", { opacity: 1, duration: 0.6 }, 0.3);
tl.to("#title-card", { opacity: 0, duration: 0.5 }, 4);
Slide Show with Section Headers
Use separate elements on the same track, each with its own time range. Slides auto-mount/unmount based on data-start/data-duration.
<div class="slide" data-start="0" data-duration="30" data-track-index="3">...</div>
<div class="slide" data-start="30" data-duration="25" data-track-index="3">...</div>
<div class="slide" data-start="55" data-duration="20" data-track-index="3">...</div>
Top-Level Composition Example
<div
id="comp-1"
data-composition-id="my-video"
data-start="0"
data-duration="60"
data-width="1920"
data-height="1080"
>
<!-- Primitive clips -->
<video
id="el-1"
data-start="0"
data-duration="10"
data-track-index="0"
src="..."
muted
playsinline
></video>
<video
id="el-2"
data-start="el-1"
data-duration="8"
data-track-index="0"
src="..."
muted
playsinline
></video>
<img id="el-3" data-start="5" data-duration="4" data-track-index="1" src="..." />
<audio id="el-4" data-start="0" data-duration="30" data-track-index="2" src="..." />
<!-- Sub-compositions loaded from files -->
<div
id="el-5"
data-composition-id="intro-anim"
data-composition-src="compositions/intro-anim.html"
data-start="0"
data-track-index="3"
></div>
<div
id="el-6"
data-composition-id="captions"
data-composition-src="compositions/caption-overlay.html"
data-start="0"
data-track-index="4"
></div>
<script>
// Just register the timeline — framework auto-nests sub-compositions
const tl = gsap.timeline({ paused: true });
window.__timelines["my-video"] = tl;
</script>
</div>