mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-05 17:30:50 +00:00
Scaffolded projects' npm run check now invokes the single check command instead of chaining lint, validate, and inspect (three Chrome boots become one). The CLI skill, its correctness reference, the entry skill's capability map, README/docs catalog rows, the Mintlify CLI page (new check section, deprecation banner on inspect), template CLAUDE/AGENTS (byte-identical), root CLAUDE/AGENTS, and every creation-workflow skill that taught the old sequence all point at check. snapshot keeps its standalone sections; validate/inspect stay documented as deprecated aliases with their check equivalents.
132 lines
5.1 KiB
Markdown
132 lines
5.1 KiB
Markdown
---
|
|
name: hyperframes-three
|
|
description: Three.js and WebGL adapter patterns for HyperFrames. Use when creating deterministic Three.js scenes, WebGL canvas layers, AnimationMixer timelines, camera motion, shader-driven visuals, or canvas renders that respond to HyperFrames hf-seek events.
|
|
---
|
|
|
|
# Three.js for HyperFrames
|
|
|
|
HyperFrames supports Three.js through its `three` runtime adapter. The adapter does not own your scene. It publishes HyperFrames time and dispatches a seek event so your composition can render the exact frame.
|
|
|
|
## Contract
|
|
|
|
- Create the scene, camera, renderer, materials, and assets synchronously when possible.
|
|
- Render from HyperFrames time, not wall-clock time.
|
|
- Listen for the `hf-seek` event and render exactly that time.
|
|
- Load models, textures, and HDRIs before render-critical seeking. Do not fetch them at seek time.
|
|
- Avoid `requestAnimationFrame` or `renderer.setAnimationLoop` as the source of truth for render-critical motion.
|
|
- **Always set `data-duration="<seconds>"` on the root `[data-composition-id]` element.** Unlike CSS/WAAPI/Lottie, the `three` adapter has no duration auto-inference — it only forwards time via `hf-seek`/`__hfThreeTime`, it doesn't inspect your scene for an `AnimationClip`/`AnimationMixer` length. Without `data-duration` (and no GSAP timeline), the render engine has no way to know how long to capture and fails with "Composition has zero duration". `npx hyperframes lint` errors on this (`root_composition_missing_duration_source`).
|
|
|
|
The adapter sets `window.__hfThreeTime` and dispatches `new CustomEvent("hf-seek", { detail: { time } })` on each seek.
|
|
|
|
## Basic Pattern
|
|
|
|
```html
|
|
<canvas id="three-layer"></canvas>
|
|
<script type="module">
|
|
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.181.2/+esm";
|
|
|
|
const canvas = document.getElementById("three-layer");
|
|
const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
|
|
// Match these to your composition's frame size.
|
|
renderer.setSize(1920, 1080, false);
|
|
renderer.setPixelRatio(1);
|
|
|
|
const scene = new THREE.Scene();
|
|
const camera = new THREE.PerspectiveCamera(35, 1920 / 1080, 0.1, 100);
|
|
camera.position.set(0, 0, 6);
|
|
|
|
const mesh = new THREE.Mesh(
|
|
new THREE.IcosahedronGeometry(1.4, 4),
|
|
new THREE.MeshStandardMaterial({ color: 0x64d2ff, roughness: 0.38 }),
|
|
);
|
|
scene.add(mesh);
|
|
scene.add(new THREE.HemisphereLight(0xffffff, 0x223344, 2));
|
|
|
|
function renderAt(time) {
|
|
mesh.rotation.y = time * 0.7;
|
|
mesh.rotation.x = Math.sin(time * 0.6) * 0.16;
|
|
renderer.render(scene, camera);
|
|
}
|
|
|
|
window.addEventListener("hf-seek", (event) => {
|
|
renderAt(event.detail.time);
|
|
});
|
|
|
|
renderAt(window.__hfThreeTime || 0);
|
|
</script>
|
|
```
|
|
|
|
```css
|
|
#three-layer {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: block;
|
|
}
|
|
```
|
|
|
|
## Loading Addons (`GLTFLoader`, `OrbitControls`, etc.)
|
|
|
|
For anything under `three/addons/`, use an importmap so bare specifiers resolve. The HyperFrames lint recognizes both this form and the inline `+esm` import above — pick whichever your composition needs.
|
|
|
|
```html
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"three": "https://cdn.jsdelivr.net/npm/three@0.181.2/build/three.module.js",
|
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.181.2/examples/jsm/"
|
|
}
|
|
}
|
|
</script>
|
|
<script type="module">
|
|
import * as THREE from "three";
|
|
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
// ...
|
|
</script>
|
|
```
|
|
|
|
Pin the `three` version in both entries to the same value. Mixing versions across the map and bare imports causes silent breakage.
|
|
|
|
## AnimationMixer Pattern
|
|
|
|
For GLTF or authored clip animation, seek the mixer directly:
|
|
|
|
```js
|
|
function renderAt(time) {
|
|
mixer.setTime(time);
|
|
renderer.render(scene, camera);
|
|
}
|
|
```
|
|
|
|
If several mixers exist, seek all of them from the same `time`.
|
|
|
|
## Good Uses
|
|
|
|
- Deterministic 3D objects, product spins, particles with seeded data, and shader plates.
|
|
- Camera moves derived from `time`.
|
|
- GLTF animation clips when assets are local and loaded before validation completes.
|
|
|
|
## Avoid
|
|
|
|
- Using `Date.now()`, `performance.now()`, or clock deltas to update scene state.
|
|
- Leaving render-critical work inside a free-running animation loop.
|
|
- Loading remote models or textures at render time.
|
|
- Device-pixel-ratio dependent output. Pin renderer size and pixel ratio for video renders.
|
|
- Post-processing passes that depend on previous frame history unless you can reconstruct state from time.
|
|
|
|
## Validation
|
|
|
|
After editing a Three.js composition:
|
|
|
|
```bash
|
|
npx hyperframes lint
|
|
npx hyperframes check
|
|
```
|
|
|
|
## Credits And References
|
|
|
|
- HyperFrames adapter source: `packages/core/src/runtime/adapters/three.ts`.
|
|
- Why `data-duration` is required here specifically (no auto-inference for this adapter): `packages/core/src/runtime/init.ts` (`resolveAdapterDurationFloorSeconds`) and the CSS/WAAPI/Lottie adapters' `getInferredDurationSeconds`, which the `three` adapter deliberately does not implement.
|
|
- Three.js `WebGLRenderer` docs: https://threejs.org/docs/pages/WebGLRenderer.html
|
|
- Three.js `AnimationMixer.setTime()` docs: https://threejs.org/docs/pages/AnimationMixer.html
|