mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
* feat(shader-transitions): add playSeamTransitionLoop to preview a seam on a loop Plays a catalog transition's real WebGL effect between two already-decoded frames on a caller-supplied canvas, looping 0->1->0 every second. The caller supplies the two seam frames itself, so this takes two CanvasImageSource frames directly rather than resolving any DOM scene. Reuses the existing webgl.ts primitives hyper-shader.ts's full composition engine already relies on; no GSAP timeline, no scene capture, no multi-transition scheduling here, just setup + a render loop. shaderName is the catalog block's own name. 12 of the 14 shader-tagged catalog blocks match their shaders/registry.ts key verbatim; two are aliased internally (domain-warp-dissolve->domain-warp, chromatic-radial-split->chromatic-split) since those registry keys are also engine/producer's canonical TRANSITIONS[...] names and weren't renamed to match the catalog. Every other catalog block (including the CSS/motion-only ones) has no WebGL implementation and throws, so a caller can fall back to its own render for those. Re-exported from @hyperframes/studio (new workspace dependency on shader-transitions) so a consumer of studio and core needs no deep import. * fix(shader-transitions): keep the WebGL context alive across stop() - stop() called WEBGL_lose_context.loseContext(), which permanently kills the canvas's WebGL context -- a later playSeamTransitionLoop() call on the same canvas (a popover reusing its element across hovers) would pass the null-context guard with the same dead context object and silently render nothing. Delete the program, textures and buffer this call created instead, matching the granular-release idiom hyper-shader.ts already uses for its own reusable contexts. - ready never resolved if stop() ran before the first frame (a hover that ends within one frame, well under 16ms), hanging any caller awaiting it forever along with everything it closed over. stop() now resolves ready too; resolving an already-settled promise is a no-op for the normal path. Also: resolveReady() only needs calling once, on the first frame, not every tick. * test(shader-transitions): extract shared running-loop setup, dedup per fallow * fix(shader-transitions): pass accent colors, fix leaks and validation - renderShader's colors argument was undefined, so u_accent/ u_accent_dark/u_accent_bright stayed at WebGL's zero default. 7 of the 14 shader blocks (domain-warp, ridged-burn, sdf-iris, ripple-waves, gravitational-lens, thermal-distortion, light-leak) use those uniforms for their glow/burn colour, so the preview silently rendered without it for half the catalog -- the "plays the real effect" claim was false for those seven. Exported webgl.ts's DEFAULT_ACCENT_COLORS (hyper-shader.ts's own fallback, previously only inlined twice there) and pass it through. - Each linkProgram() call leaked its compiled vertex and fragment shader objects (created, attached, linked, never deleted) -- a real WebGL browser never frees them on its own, and this call is on a hover-repeat path via a reused canvas. Fixed in webgl.ts's linkProgram itself, which every caller in this package routes through, not just this new one. - loopMs was never validated: 0 divided to NaN progress, negative values ran the shader backwards, Infinity froze it at 0 -- all silently, no caller-visible error. Now throws synchronously for a non-finite or non-positive value, matching the function's other synchronous-throw contract (unknown shader, no WebGL context). - getFragSource() and the catalog-alias lookup both did an unguarded plain-object index (shaders[name], CATALOG_SHADER_ALIASES[shaderName]), which returns Object.prototype members for names like "constructor" instead of undefined -- an unusual shaderName could reach the shader compiler with a garbled error or an unintended match. Both now use Object.hasOwn. Tests: second half of the loop (progress descending, not climbing past 1), both catalog aliases (only one was covered before), all four invalid-loopMs shapes, the accent-color uniforms actually being set, and webgl.test.ts's new deleteShader assertion. All mutation-verified non-vacuous. * test(shader-transitions): dedup the two timing tests per fallow * fix(shader-transitions): apply default accent colors and validate loop options renderShader now defaults colors to DEFAULT_ACCENT_COLORS instead of the caller deciding, so playSeamTransitionLoop no longer renders 7 of 14 shader blocks with a zeroed-out accent. Validates width/height alongside loopMs, switches the catalog alias map to a Map so a bogus name never resolves an Object.prototype member, and fixes linkProgram to only delete the shader it created itself. * fix(shader-transitions): free GL resources when seam-loop setup throws A bad fromSource/toSource reaching uploadTextureSource previously left whatever quadBuf/program/textures had already been allocated dangling, since playSeamTransitionLoop throws before returning a handle a caller could call stop() on. Trims three over-limit JSDoc blocks and drops a redundant prototype-pollution rationale now that getFragSource guards it. * chore(shader-transitions): trim seam-loop comments to the comment ratchet * test(shader-transitions): unknown-shader throw covers names on Object.prototype
@hyperframes/studio
Browser-based composition editor UI for Hyperframes. Provides a visual timeline, code editor, and live preview for building video compositions.
Install
npm install @hyperframes/studio
What it does
The studio is a React application with:
- Visual timeline — drag, resize, and arrange elements on tracks
- Code editor — edit HTML and GSAP scripts with CodeMirror (syntax highlighting, autocomplete)
- Live preview — see changes in real time as you edit
- Composition inspector — view and modify element properties
Development
The studio is embedded in the hyperframes preview command. To develop the studio UI itself:
cd packages/studio
bun run dev # Start Vite dev server
bun run build # Build for production
bun run typecheck # Type-check
Tech stack
- React 19, Zustand 4/5 (state management; development uses Zustand 5)
- CodeMirror 6 (editor)
- Tailwind CSS (styling)
- Vite (bundler)
- Phosphor Icons
Documentation
Full documentation: hyperframes.heygen.com/packages/studio
Related packages
@hyperframes/core— types and parsers used by the editorhyperframes— CLI that serves the studio viahyperframes preview