85453da49f
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docs / Validate docs (push) Has been cancelled
Sync skills to ClawHub / Publish changed skills (push) Has been cancelled
149 lines
5.3 KiB
Plaintext
149 lines
5.3 KiB
Plaintext
---
|
|
title: Frame Adapters
|
|
description: "Bring your own animation runtime to Hyperframes."
|
|
---
|
|
|
|
The Frame Adapter pattern is how Hyperframes supports multiple animation runtimes. The core question every adapter answers:
|
|
|
|
> What should the screen look like at frame N?
|
|
|
|
If a runtime can answer that, it can plug into Hyperframes.
|
|
|
|
<Info>
|
|
The Adapter API is currently at **v0** (experimental). Breaking changes are possible until v1. The core contract (seek-by-frame, deterministic output) is stable, but method signatures may evolve.
|
|
</Info>
|
|
|
|
## How It Works
|
|
|
|
The host application (the [engine](/packages/engine) or [producer](/packages/producer)) drives rendering by calling adapter methods in a strict sequence. The adapter never controls its own clock -- it only responds to seek commands.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Host as Host (Engine)
|
|
participant Adapter as Frame Adapter
|
|
participant Chrome as Chrome / Browser
|
|
|
|
Host->>Adapter: init(context)
|
|
Adapter-->>Host: ready
|
|
Host->>Adapter: getDurationFrames()
|
|
Adapter-->>Host: 300 frames
|
|
|
|
loop For each frame 0..300
|
|
Host->>Host: normalize frame (clamp, floor)
|
|
Host->>Adapter: seekFrame(frame)
|
|
Adapter->>Chrome: Update DOM / canvas state
|
|
Adapter-->>Host: done
|
|
Host->>Chrome: Capture pixel buffer
|
|
end
|
|
|
|
Host->>Adapter: destroy()
|
|
Adapter-->>Host: cleaned up
|
|
```
|
|
|
|
## Adapter API (v0)
|
|
|
|
```typescript adapters/types.ts
|
|
type FrameAdapterContext = {
|
|
compositionId: string;
|
|
fps: number;
|
|
width: number;
|
|
height: number;
|
|
rootElement?: HTMLElement;
|
|
};
|
|
|
|
type FrameAdapter = {
|
|
id: string;
|
|
init?: (ctx: FrameAdapterContext) => Promise<void> | void;
|
|
getDurationFrames: () => number;
|
|
seekFrame: (frame: number) => Promise<void> | void;
|
|
destroy?: () => Promise<void> | void;
|
|
};
|
|
```
|
|
|
|
## Required Semantics
|
|
|
|
- `getDurationFrames()` must return a finite integer >= 0
|
|
- `seekFrame(frame)` must support arbitrary seek order (forward, backward, random)
|
|
- `seekFrame(frame)` must be idempotent for the same input frame
|
|
- `seekFrame(frame)` must clamp internal time to the adapter's range
|
|
- Adapters should be paused/seek-driven, not clock-driven
|
|
|
|
## Host Orchestration
|
|
|
|
The host normalizes frames before calling the adapter:
|
|
|
|
```typescript engine/render-loop.ts
|
|
normalizedFrame = clamp(Math.floor(frame), 0, durationFrames);
|
|
```
|
|
|
|
A typical render loop:
|
|
|
|
```typescript engine/render-loop.ts
|
|
await adapter.init?.({ compositionId, fps, width, height, rootElement });
|
|
const durationFrames = adapter.getDurationFrames();
|
|
|
|
for (let frame = 0; frame <= durationFrames; frame += 1) {
|
|
await adapter.seekFrame(frame);
|
|
// capture pixel buffer for this frame
|
|
}
|
|
|
|
await adapter.destroy?.();
|
|
```
|
|
|
|
## Determinism Contract
|
|
|
|
These rules are non-negotiable for any adapter. They are the foundation of Hyperframes' [deterministic rendering](/concepts/determinism) guarantee.
|
|
|
|
- Canonical clock: `t = frame / fps`
|
|
- No wall-clock dependencies (`Date.now`, drift-dependent logic)
|
|
- No unseeded randomness
|
|
- No render-time network fetches
|
|
- Fixed output params (`fps`, `width`, `height`)
|
|
- Finite duration only
|
|
- Deterministic frame quantization before seek
|
|
|
|
## Supported Runtimes
|
|
|
|
First-party runtime adapters:
|
|
|
|
All runtime adapters live in the `/hyperframes-animation` skill — invoke it for the runtime-specific seek API as well as motion rules, scene blueprints, and transitions.
|
|
|
|
| Runtime | Seek Method | Skill |
|
|
|---------|-------------|-------|
|
|
| [GSAP](/guides/gsap-animation) | `timeline.totalTime(timeSeconds)` or `timeline.seek(timeSeconds)` | `/hyperframes-animation` |
|
|
| Anime.js | `instance.seek(timeMs)` for animations registered on `window.__hfAnime` | `/hyperframes-animation` |
|
|
| CSS keyframes | Browser `Animation.currentTime`, with paused negative-delay fallback | `/hyperframes-animation` |
|
|
| Lottie / dotLottie | `goToAndStop(timeMs, false)`, raw-frame setters, or player seek APIs | `/hyperframes-animation` |
|
|
| Three.js / WebGL | `hf-seek` events plus `window.__hfThreeTime` for deterministic scene rendering | `/hyperframes-animation` |
|
|
| Web Animations API | `document.getAnimations()` and `animation.currentTime` | `/hyperframes-animation` |
|
|
| TypeGPU / WebGPU | GPU compute shaders with deterministic seek via `hf-seek` events | `/hyperframes-animation` |
|
|
|
|
Community adapters are welcome -- if it can seek by frame, it belongs in Hyperframes.
|
|
|
|
## Conformance Tests
|
|
|
|
Every adapter should pass these minimum tests:
|
|
|
|
1. **Repeatability** -- seek same frame twice, get identical output
|
|
2. **Random seek** -- seek order `[90, 10, 50, 10]` produces deterministic results
|
|
3. **Bounds** -- negative and overflow frame values do not break
|
|
4. **Duration** -- returned duration is a finite integer
|
|
5. **Cleanup** -- no leaked timers/listeners after `destroy`
|
|
|
|
## Next Steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Deterministic Rendering" icon="lock" href="/concepts/determinism">
|
|
Understand the determinism guarantees adapters must uphold
|
|
</Card>
|
|
<Card title="GSAP Animation" icon="wand-magic-sparkles" href="/guides/gsap-animation">
|
|
See the first-party GSAP adapter in action
|
|
</Card>
|
|
<Card title="@hyperframes/engine" icon="gear" href="/packages/engine">
|
|
The capture engine that drives adapters during rendering
|
|
</Card>
|
|
<Card title="Contributing" icon="code-branch" href="/contributing">
|
|
Build and contribute your own adapter
|
|
</Card>
|
|
</CardGroup>
|