hyperframes 0.6.97 → 0.6.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/beat-analyzer.global.js +326 -0
  2. package/dist/cli.js +12428 -4680
  3. package/dist/commands/layout-audit.browser.js +86 -0
  4. package/dist/hyperframe-runtime.js +22 -22
  5. package/dist/hyperframe.manifest.json +1 -1
  6. package/dist/hyperframe.runtime.iife.js +22 -22
  7. package/dist/skills/hyperframes-cli/SKILL.md +67 -103
  8. package/dist/skills/hyperframes-cli/references/doctor-browser.md +45 -0
  9. package/dist/skills/hyperframes-cli/references/init-and-scaffold.md +51 -0
  10. package/dist/skills/hyperframes-cli/references/lambda.md +132 -0
  11. package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +93 -0
  12. package/dist/skills/hyperframes-cli/references/preview-render.md +107 -0
  13. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
  14. package/dist/studio/assets/hyperframes-player-DgsMQSvV.js +418 -0
  15. package/dist/studio/assets/index-B62bDCQv.css +1 -0
  16. package/dist/studio/assets/{index-HveJ0MuV.js → index-C52IT_lp.js} +1 -1
  17. package/dist/studio/assets/index-DOh7E1uj.js +1 -0
  18. package/dist/studio/assets/index-DrwSRbsl.js +252 -0
  19. package/dist/studio/index.html +2 -2
  20. package/dist/templates/_shared/AGENTS.md +46 -21
  21. package/dist/templates/_shared/CLAUDE.md +16 -14
  22. package/package.json +3 -2
  23. package/dist/pngDecodeBlitWorker.js +0 -239
  24. package/dist/skills/gsap/SKILL.md +0 -240
  25. package/dist/skills/gsap/references/effects.md +0 -297
  26. package/dist/skills/gsap/scripts/extract-audio-data.py +0 -188
  27. package/dist/skills/hyperframes/SKILL.md +0 -491
  28. package/dist/skills/hyperframes/data-in-motion.md +0 -19
  29. package/dist/skills/hyperframes/house-style.md +0 -73
  30. package/dist/skills/hyperframes/palettes/bold-energetic.md +0 -14
  31. package/dist/skills/hyperframes/palettes/clean-corporate.md +0 -14
  32. package/dist/skills/hyperframes/palettes/dark-premium.md +0 -14
  33. package/dist/skills/hyperframes/palettes/jewel-rich.md +0 -14
  34. package/dist/skills/hyperframes/palettes/monochrome.md +0 -14
  35. package/dist/skills/hyperframes/palettes/nature-earth.md +0 -14
  36. package/dist/skills/hyperframes/palettes/neon-electric.md +0 -14
  37. package/dist/skills/hyperframes/palettes/pastel-soft.md +0 -14
  38. package/dist/skills/hyperframes/palettes/warm-editorial.md +0 -14
  39. package/dist/skills/hyperframes/patterns.md +0 -191
  40. package/dist/skills/hyperframes/references/audio-reactive.md +0 -76
  41. package/dist/skills/hyperframes/references/beat-direction.md +0 -171
  42. package/dist/skills/hyperframes/references/captions.md +0 -163
  43. package/dist/skills/hyperframes/references/css-patterns.md +0 -373
  44. package/dist/skills/hyperframes/references/design-picker.md +0 -117
  45. package/dist/skills/hyperframes/references/dynamic-techniques.md +0 -102
  46. package/dist/skills/hyperframes/references/html-in-canvas-patterns.md +0 -507
  47. package/dist/skills/hyperframes/references/motion-principles.md +0 -150
  48. package/dist/skills/hyperframes/references/narration.md +0 -92
  49. package/dist/skills/hyperframes/references/prompt-expansion.md +0 -68
  50. package/dist/skills/hyperframes/references/techniques.md +0 -525
  51. package/dist/skills/hyperframes/references/text-effects.md +0 -64
  52. package/dist/skills/hyperframes/references/transcript-guide.md +0 -107
  53. package/dist/skills/hyperframes/references/transitions/catalog.md +0 -117
  54. package/dist/skills/hyperframes/references/transitions/css-3d.md +0 -12
  55. package/dist/skills/hyperframes/references/transitions/css-blur.md +0 -51
  56. package/dist/skills/hyperframes/references/transitions/css-cover.md +0 -43
  57. package/dist/skills/hyperframes/references/transitions/css-destruction.md +0 -95
  58. package/dist/skills/hyperframes/references/transitions/css-dissolve.md +0 -66
  59. package/dist/skills/hyperframes/references/transitions/css-distortion.md +0 -45
  60. package/dist/skills/hyperframes/references/transitions/css-grid.md +0 -10
  61. package/dist/skills/hyperframes/references/transitions/css-light.md +0 -49
  62. package/dist/skills/hyperframes/references/transitions/css-mechanical.md +0 -30
  63. package/dist/skills/hyperframes/references/transitions/css-other.md +0 -25
  64. package/dist/skills/hyperframes/references/transitions/css-push.md +0 -41
  65. package/dist/skills/hyperframes/references/transitions/css-radial.md +0 -37
  66. package/dist/skills/hyperframes/references/transitions/css-scale.md +0 -24
  67. package/dist/skills/hyperframes/references/transitions.md +0 -138
  68. package/dist/skills/hyperframes/references/typography.md +0 -175
  69. package/dist/skills/hyperframes/references/video-composition.md +0 -62
  70. package/dist/skills/hyperframes/scripts/animation-map.mjs +0 -601
  71. package/dist/skills/hyperframes/scripts/contrast-report.mjs +0 -348
  72. package/dist/skills/hyperframes/scripts/package-loader.mjs +0 -269
  73. package/dist/skills/hyperframes/templates/design-picker.html +0 -1432
  74. package/dist/skills/hyperframes/visual-styles.md +0 -443
  75. package/dist/studio/assets/hyperframes-player-Daj5djxa.js +0 -418
  76. package/dist/studio/assets/index-B0twsRu0.css +0 -1
  77. package/dist/studio/assets/index-Cfye9xzo.js +0 -251
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
6
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
7
  <title>HyperFrames Studio</title>
8
- <script type="module" crossorigin src="/assets/index-Cfye9xzo.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-B0twsRu0.css">
8
+ <script type="module" crossorigin src="/assets/index-DrwSRbsl.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-B62bDCQv.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -1,14 +1,28 @@
1
1
  # HyperFrames Composition Project
2
2
 
3
- ## Skills
3
+ ## Skills — USE THESE FIRST
4
4
 
5
- This project uses AI agent skills for framework-specific patterns. Install them if not already present:
5
+ **Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
6
6
 
7
- ```bash
8
- npx skills add heygen-com/hyperframes
9
- ```
7
+ **Doing anything with HyperFrames?** Start at `/hyperframes-read-first` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), and routes every "make me a video" request to the right workflow. Read it first, especially when there's no project context to orient you. The video workflows it routes to:
8
+
9
+ - `/product-launch-video` — a **product** URL or brief / script → 60-90s product launch / SaaS / promo video.
10
+ - `/website-to-video` — a **general** website / URL → a video _of_ the site (tour / showcase / social clip from captured visuals); a product **launch / promo** is `/product-launch-video`.
11
+ - `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
12
+ - `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
13
+ - `/graphic-overlays` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
14
+ - `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
15
+ - `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
16
+ - `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes authoring flow, any length.
17
+
18
+ **Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
19
+
20
+ The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-creative`, `/hyperframes-cli`, `/hyperframes-media`, `/hyperframes-registry`) and the full capability map live inside `/hyperframes-read-first` — it is the single source of truth for which skill handles which intent.
21
+
22
+ > **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
10
23
 
11
- Skills encode patterns like `window.__timelines` registration, `data-*` attribute semantics, Tailwind v4 browser-runtime styling for `--tailwind` projects, and shader-compatible CSS rules that are not in generic web docs. Using them produces correct compositions from the start.
24
+ > **Skills not available?** Ask the user to run `npx hyperframes skills` and restart their
25
+ > agent session, or install manually: `npx skills add heygen-com/hyperframes`.
12
26
 
13
27
  ## Commands
14
28
 
@@ -17,46 +31,57 @@ npm run dev # start the preview server (long-running — keep it alive
17
31
  npm run check # lint + validate + inspect
18
32
  npm run render # render to MP4
19
33
  npm run publish # publish and get a shareable link
34
+ npx hyperframes lint --verbose # include info-level findings
35
+ npx hyperframes lint --json # machine-readable output for CI
20
36
  npx hyperframes docs <topic> # reference docs in terminal
21
37
  ```
22
38
 
23
39
  > **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
24
- > Always run it as a background process so it stays alive while you edit compositions.
25
- > Running it in the foreground will time out and kill the server, breaking the browser preview.
40
+ > In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
41
+ > command it will time out and the server will die, breaking the browser preview.
42
+
43
+ ## Documentation
44
+
45
+ **For quick reference**, use the local CLI docs command (no network required):
46
+
47
+ ```bash
48
+ npx hyperframes docs <topic>
49
+ ```
50
+
51
+ Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
52
+
53
+ **For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
54
+
55
+ ```
56
+ https://hyperframes.heygen.com/llms.txt
57
+ ```
26
58
 
27
59
  ## Project Structure
28
60
 
29
61
  - `index.html` — main composition (root timeline)
30
62
  - `compositions/` — sub-compositions referenced via `data-composition-src`
31
- - `assets/` — media files (video, audio, images)
32
63
  - `meta.json` — project metadata (id, name)
33
64
  - `transcript.json` — whisper word-level transcript (if generated)
34
65
 
35
- ## Linting — Always Run After Changes
66
+ ## Linting — ALWAYS RUN AFTER CHANGES
36
67
 
37
- After creating or editing any `.html` composition, run the full check before considering the task complete:
68
+ After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
38
69
 
39
70
  ```bash
40
71
  npm run check
41
72
  ```
42
73
 
43
- Fix all errors before presenting the result.
74
+ Fix all errors before presenting the result. Inspect warnings should be reviewed before rendering.
44
75
 
45
76
  ## Key Rules
46
77
 
47
78
  1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
48
- 2. Visible timed elements **must** have `class="clip"` — the framework uses this for visibility control
49
- 3. GSAP timelines must be paused and registered on `window.__timelines`:
79
+ 2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
80
+ 3. Timelines must be paused and registered on `window.__timelines`:
50
81
  ```js
51
82
  window.__timelines = window.__timelines || {};
52
83
  window.__timelines["composition-id"] = gsap.timeline({ paused: true });
53
84
  ```
54
85
  4. Videos use `muted` with a separate `<audio>` element for the audio track
55
- 5. Sub-compositions use `data-composition-src="compositions/file.html"`
86
+ 5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
56
87
  6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
57
-
58
- ## Documentation
59
-
60
- Full docs: https://hyperframes.heygen.com/introduction
61
-
62
- Machine-readable index for AI tools: https://hyperframes.heygen.com/llms.txt
@@ -4,20 +4,22 @@
4
4
 
5
5
  **Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
6
6
 
7
- | Skill | Command | When to use |
8
- | -------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------- |
9
- | **hyperframes** | `/hyperframes` | Creating or editing HTML compositions, captions, TTS, audio-reactive animation, marker highlights |
10
- | **hyperframes-cli** | `/hyperframes-cli` | Dev-loop CLI: init, lint, inspect, preview, render, doctor |
11
- | **hyperframes-media** | `/hyperframes-media` | Asset preprocessing: tts (Kokoro), transcribe (Whisper), remove-background (u2net) |
12
- | **hyperframes-registry** | `/hyperframes-registry` | Installing blocks and components via `hyperframes add` |
13
- | **website-to-hyperframes** | `/website-to-hyperframes` | Capturing a URL and turning it into a video full website-to-video pipeline |
14
- | **tailwind** | `/tailwind` | Tailwind v4 browser-runtime styles for projects created with `hyperframes init --tailwind` |
15
- | **gsap** | `/gsap` | GSAP animations for HyperFrames tweens, timelines, easing, performance |
16
- | **animejs** | `/animejs` | Anime.js animations registered on `window.__hfAnime` |
17
- | **css-animations** | `/css-animations` | CSS keyframes that HyperFrames can pause and seek |
18
- | **lottie** | `/lottie` | `lottie-web` and dotLottie players registered on `window.__hfLottie` |
19
- | **three** | `/three` | Three.js scenes rendered from HyperFrames `hf-seek` events |
20
- | **waapi** | `/waapi` | Web Animations API motion driven through `document.getAnimations()` |
7
+ **Doing anything with HyperFrames?** Start at `/hyperframes-read-first` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), and routes every "make me a video" request to the right workflow. Read it first, especially when there's no project context to orient you. The video workflows it routes to:
8
+
9
+ - `/product-launch-video` — a **product** URL or brief / script 60-90s product launch / SaaS / promo video.
10
+ - `/website-to-video` a **general** website / URL a video _of_ the site (tour / showcase / social clip from captured visuals); a product **launch / promo** is `/product-launch-video`.
11
+ - `/faceless-explainer` arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
12
+ - `/embedded-captions` an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
13
+ - `/graphic-overlays` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
14
+ - `/pr-to-video` a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
15
+ - `/motion-graphics` a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
16
+ - `/general-video` fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes authoring flow, any length.
17
+
18
+ **Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
19
+
20
+ The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-creative`, `/hyperframes-cli`, `/hyperframes-media`, `/hyperframes-registry`) and the full capability map live inside `/hyperframes-read-first` — it is the single source of truth for which skill handles which intent.
21
+
22
+ > **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
21
23
 
22
24
  > **Skills not available?** Ask the user to run `npx hyperframes skills` and restart their
23
25
  > agent session, or install manually: `npx skills add heygen-com/hyperframes`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperframes",
3
- "version": "0.6.97",
3
+ "version": "0.6.99",
4
4
  "description": "HyperFrames CLI — create, preview, and render HTML video compositions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,9 +17,10 @@
17
17
  "scripts": {
18
18
  "test": "vitest run",
19
19
  "dev": "tsx src/cli.ts",
20
- "build": "bun run build:fonts && tsup && bun run build:runtime && bun run build:copy",
20
+ "build": "bun run build:fonts && tsup && bun run build:runtime && bun run build:beat-analyzer && bun run build:copy",
21
21
  "build:fonts": "node scripts/build-fonts.mjs",
22
22
  "build:runtime": "tsx scripts/build-runtime.ts",
23
+ "build:beat-analyzer": "node scripts/build-beat-analyzer.mjs",
23
24
  "build:copy": "node scripts/build-copy.mjs",
24
25
  "typecheck": "tsc --noEmit"
25
26
  },
@@ -1,239 +0,0 @@
1
- import { createRequire as __hf_createRequire } from "node:module";
2
- import { fileURLToPath as __hf_fileURLToPath } from "node:url";
3
- import { dirname as __hf_dirname } from "node:path";
4
- var require = __hf_createRequire(import.meta.url);
5
- var __filename = __hf_fileURLToPath(import.meta.url);
6
- var __dirname = __hf_dirname(__filename);
7
-
8
- // ../producer/src/services/pngDecodeBlitWorker.ts
9
- import { parentPort } from "worker_threads";
10
-
11
- // ../engine/src/utils/alphaBlit.ts
12
- import { inflateSync } from "zlib";
13
- function paeth(a, b, c) {
14
- const p = a + b - c;
15
- const pa = Math.abs(p - a);
16
- const pb = Math.abs(p - b);
17
- const pc = Math.abs(p - c);
18
- if (pa <= pb && pa <= pc) return a;
19
- if (pb <= pc) return b;
20
- return c;
21
- }
22
- function decodePngRaw(buf, caller) {
23
- if (buf[0] !== 137 || buf[1] !== 80 || buf[2] !== 78 || buf[3] !== 71 || buf[4] !== 13 || buf[5] !== 10 || buf[6] !== 26 || buf[7] !== 10) {
24
- throw new Error(`${caller}: not a PNG file`);
25
- }
26
- let pos = 8;
27
- let width = 0;
28
- let height = 0;
29
- let bitDepth = 0;
30
- let colorType = 0;
31
- let interlace = 0;
32
- let sawIhdr = false;
33
- const idatChunks = [];
34
- while (pos + 12 <= buf.length) {
35
- const chunkLen = buf.readUInt32BE(pos);
36
- const chunkType = buf.toString("ascii", pos + 4, pos + 8);
37
- const chunkData = buf.subarray(pos + 8, pos + 8 + chunkLen);
38
- if (chunkType === "IHDR") {
39
- width = chunkData.readUInt32BE(0);
40
- height = chunkData.readUInt32BE(4);
41
- bitDepth = chunkData[8] ?? 0;
42
- colorType = chunkData[9] ?? 0;
43
- interlace = chunkData[12] ?? 0;
44
- sawIhdr = true;
45
- } else if (chunkType === "IDAT") {
46
- idatChunks.push(Buffer.from(chunkData));
47
- } else if (chunkType === "IEND") {
48
- break;
49
- }
50
- pos += 12 + chunkLen;
51
- }
52
- if (!sawIhdr) {
53
- throw new Error(`${caller}: PNG missing IHDR chunk`);
54
- }
55
- if (colorType !== 2 && colorType !== 6) {
56
- throw new Error(`${caller}: unsupported color type ${colorType} (expected 2=RGB or 6=RGBA)`);
57
- }
58
- if (interlace !== 0) {
59
- throw new Error(
60
- `${caller}: Adam7-interlaced PNGs are not supported (interlace method ${interlace})`
61
- );
62
- }
63
- const channels = colorType === 6 ? 4 : 3;
64
- const bpp = channels * (bitDepth / 8);
65
- const stride = width * bpp;
66
- const compressed = Buffer.concat(idatChunks);
67
- const decompressed = inflateSync(compressed);
68
- const rawPixels = Buffer.allocUnsafe(height * stride);
69
- const prevRow = new Uint8Array(stride);
70
- const currRow = new Uint8Array(stride);
71
- let srcPos = 0;
72
- for (let y = 0; y < height; y++) {
73
- const filterType = decompressed[srcPos++] ?? 0;
74
- const rawRow = decompressed.subarray(srcPos, srcPos + stride);
75
- srcPos += stride;
76
- switch (filterType) {
77
- case 0:
78
- currRow.set(rawRow);
79
- break;
80
- case 1:
81
- for (let x = 0; x < stride; x++) {
82
- currRow[x] = (rawRow[x] ?? 0) + (x >= bpp ? currRow[x - bpp] ?? 0 : 0) & 255;
83
- }
84
- break;
85
- case 2:
86
- for (let x = 0; x < stride; x++) {
87
- currRow[x] = (rawRow[x] ?? 0) + (prevRow[x] ?? 0) & 255;
88
- }
89
- break;
90
- case 3:
91
- for (let x = 0; x < stride; x++) {
92
- const left = x >= bpp ? currRow[x - bpp] ?? 0 : 0;
93
- const up = prevRow[x] ?? 0;
94
- currRow[x] = (rawRow[x] ?? 0) + Math.floor((left + up) / 2) & 255;
95
- }
96
- break;
97
- case 4:
98
- for (let x = 0; x < stride; x++) {
99
- const left = x >= bpp ? currRow[x - bpp] ?? 0 : 0;
100
- const up = prevRow[x] ?? 0;
101
- const upLeft = x >= bpp ? prevRow[x - bpp] ?? 0 : 0;
102
- currRow[x] = (rawRow[x] ?? 0) + paeth(left, up, upLeft) & 255;
103
- }
104
- break;
105
- default:
106
- throw new Error(`${caller}: unknown filter type ${filterType} at row ${y}`);
107
- }
108
- rawPixels.set(currRow, y * stride);
109
- prevRow.set(currRow);
110
- }
111
- return { width, height, bitDepth, colorType, rawPixels };
112
- }
113
- function decodePng(buf) {
114
- const { width, height, bitDepth, colorType, rawPixels } = decodePngRaw(buf, "decodePng");
115
- if (bitDepth !== 8) {
116
- throw new Error(`decodePng: unsupported bit depth ${bitDepth} (expected 8)`);
117
- }
118
- const output = new Uint8Array(width * height * 4);
119
- if (colorType === 6) {
120
- output.set(rawPixels);
121
- } else {
122
- for (let i = 0; i < width * height; i++) {
123
- output[i * 4 + 0] = rawPixels[i * 3 + 0] ?? 0;
124
- output[i * 4 + 1] = rawPixels[i * 3 + 1] ?? 0;
125
- output[i * 4 + 2] = rawPixels[i * 3 + 2] ?? 0;
126
- output[i * 4 + 3] = 255;
127
- }
128
- }
129
- return { width, height, data: output };
130
- }
131
- function buildSrgbToSignalLut(transfer) {
132
- const lut = new Uint16Array(256);
133
- const hlgA = 0.17883277;
134
- const hlgB = 1 - 4 * hlgA;
135
- const hlgC = 0.5 - hlgA * Math.log(4 * hlgA);
136
- const pqM1 = 0.1593017578125;
137
- const pqM2 = 78.84375;
138
- const pqC1 = 0.8359375;
139
- const pqC2 = 18.8515625;
140
- const pqC3 = 18.6875;
141
- const pqMaxNits = 1e4;
142
- const sdrNits = 203;
143
- for (let i = 0; i < 256; i++) {
144
- if (transfer === "srgb") {
145
- lut[i] = i * 257;
146
- continue;
147
- }
148
- const v = i / 255;
149
- const linear = v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
150
- let signal;
151
- if (transfer === "hlg") {
152
- signal = linear <= 1 / 12 ? Math.sqrt(3 * linear) : hlgA * Math.log(12 * linear - hlgB) + hlgC;
153
- } else {
154
- const Lp = Math.max(0, linear * sdrNits / pqMaxNits);
155
- const Lm1 = Math.pow(Lp, pqM1);
156
- signal = Math.pow((pqC1 + pqC2 * Lm1) / (1 + pqC3 * Lm1), pqM2);
157
- }
158
- lut[i] = Math.min(65535, Math.round(signal * 65535));
159
- }
160
- return lut;
161
- }
162
- var SRGB_TO_SRGB_16 = buildSrgbToSignalLut("srgb");
163
- var SRGB_TO_HLG = buildSrgbToSignalLut("hlg");
164
- var SRGB_TO_PQ = buildSrgbToSignalLut("pq");
165
- function getSrgbToSignalLut(transfer) {
166
- if (transfer === "pq") return SRGB_TO_PQ;
167
- if (transfer === "hlg") return SRGB_TO_HLG;
168
- return SRGB_TO_SRGB_16;
169
- }
170
- function blitRgba8OverRgb48le(domRgba, canvas, width, height, transfer = "hlg") {
171
- const pixelCount = width * height;
172
- const lut = getSrgbToSignalLut(transfer);
173
- for (let i = 0; i < pixelCount; i++) {
174
- const da = domRgba[i * 4 + 3] ?? 0;
175
- if (da === 0) {
176
- continue;
177
- } else if (da === 255) {
178
- const r16 = lut[domRgba[i * 4 + 0] ?? 0] ?? 0;
179
- const g16 = lut[domRgba[i * 4 + 1] ?? 0] ?? 0;
180
- const b16 = lut[domRgba[i * 4 + 2] ?? 0] ?? 0;
181
- canvas.writeUInt16LE(r16, i * 6);
182
- canvas.writeUInt16LE(g16, i * 6 + 2);
183
- canvas.writeUInt16LE(b16, i * 6 + 4);
184
- } else {
185
- const alpha = da / 255;
186
- const invAlpha = 1 - alpha;
187
- const hdrR = (canvas[i * 6 + 0] ?? 0) | (canvas[i * 6 + 1] ?? 0) << 8;
188
- const hdrG = (canvas[i * 6 + 2] ?? 0) | (canvas[i * 6 + 3] ?? 0) << 8;
189
- const hdrB = (canvas[i * 6 + 4] ?? 0) | (canvas[i * 6 + 5] ?? 0) << 8;
190
- const domR = lut[domRgba[i * 4 + 0] ?? 0] ?? 0;
191
- const domG = lut[domRgba[i * 4 + 1] ?? 0] ?? 0;
192
- const domB = lut[domRgba[i * 4 + 2] ?? 0] ?? 0;
193
- canvas.writeUInt16LE(Math.round(domR * alpha + hdrR * invAlpha), i * 6);
194
- canvas.writeUInt16LE(Math.round(domG * alpha + hdrG * invAlpha), i * 6 + 2);
195
- canvas.writeUInt16LE(Math.round(domB * alpha + hdrB * invAlpha), i * 6 + 4);
196
- }
197
- }
198
- }
199
-
200
- // ../producer/src/services/pngDecodeBlitWorker.ts
201
- if (!parentPort) {
202
- console.warn("[pngDecodeBlitWorker] no parentPort; module loaded on main thread");
203
- } else {
204
- parentPort.on("message", (msg) => {
205
- const { png, pngOffset, pngLength, dest, destOffset, destLength, width, height, transfer } = msg;
206
- const pngBuf = Buffer.from(png, pngOffset, pngLength);
207
- const destBuf = Buffer.from(dest, destOffset, destLength);
208
- try {
209
- const decodeStart = Date.now();
210
- const { data: rgba } = decodePng(pngBuf);
211
- const decodeMs = Date.now() - decodeStart;
212
- const blitStart = Date.now();
213
- blitRgba8OverRgb48le(
214
- rgba,
215
- destBuf,
216
- width,
217
- height,
218
- transfer
219
- );
220
- const blitMs = Date.now() - blitStart;
221
- const reply = {
222
- ok: true,
223
- png,
224
- dest,
225
- decodeMs,
226
- blitMs
227
- };
228
- parentPort.postMessage(reply, [png, dest]);
229
- } catch (err) {
230
- const reply = {
231
- ok: false,
232
- error: err instanceof Error ? err.message : String(err),
233
- png,
234
- dest
235
- };
236
- parentPort.postMessage(reply, [png, dest]);
237
- }
238
- });
239
- }
@@ -1,240 +0,0 @@
1
- ---
2
- name: gsap
3
- description: GSAP animation reference for HyperFrames. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, timelines (gsap.timeline(), position parameter, labels, nesting, playback), and performance (transforms, will-change, quickTo). Use when writing GSAP animations in HyperFrames compositions.
4
- ---
5
-
6
- # GSAP
7
-
8
- ## HyperFrames Contract
9
-
10
- HyperFrames controls GSAP through its `gsap` runtime adapter. Create a paused timeline synchronously, register it on `window.__timelines` with the exact `data-composition-id`, and let HyperFrames seek it.
11
-
12
- ```html
13
- <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
14
- <script>
15
- window.__timelines = window.__timelines || {};
16
- const tl = gsap.timeline({ paused: true });
17
-
18
- tl.from(".title", { y: 48, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
19
- tl.to(".accent", { scaleX: 1, duration: 0.5, ease: "power2.out" }, 0.25);
20
-
21
- window.__timelines["main"] = tl; // key must equal data-composition-id on the composition root
22
- </script>
23
- ```
24
-
25
- - The registry key must match the composition root's `data-composition-id`.
26
- - Do not call `tl.play()` for render-critical motion.
27
- - Do not build timelines inside async code, timers, or event handlers.
28
- - Keep loops finite. HyperFrames renders finite video durations.
29
-
30
- ## Core Tween Methods
31
-
32
- - **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
33
- - **gsap.from(targets, vars)** — animate from `vars` to current state (entrances).
34
- - **gsap.fromTo(targets, fromVars, toVars)** — explicit start and end.
35
- - **gsap.set(targets, vars)** — apply immediately (duration 0).
36
-
37
- Always use **camelCase** property names (e.g. `backgroundColor`, `rotationX`).
38
-
39
- ## Common vars
40
-
41
- - **duration** — seconds (default 0.5).
42
- - **delay** — seconds before start.
43
- - **ease** — `"power1.out"` (default), `"power3.inOut"`, `"back.out(1.7)"`, `"elastic.out(1, 0.3)"`, `"none"`.
44
- - **stagger** — number `0.1` or object: `{ amount: 0.3, from: "center" }`, `{ each: 0.1, from: "random" }`.
45
- - **overwrite** — `false` (default), `true`, or `"auto"`.
46
- - **repeat** — finite number; never `-1` in HyperFrames. Compute repeats from the visible duration. **yoyo** — alternates direction with repeat.
47
- - **onComplete**, **onStart**, **onUpdate** — callbacks.
48
- - **immediateRender** — default `true` for from()/fromTo(). Set `false` on later tweens targeting the same property+element to avoid overwrite.
49
-
50
- ## Transforms and CSS
51
-
52
- Prefer GSAP's **transform aliases** over raw `transform` string:
53
-
54
- | GSAP property | Equivalent |
55
- | --------------------------- | ------------------- |
56
- | `x`, `y`, `z` | translateX/Y/Z (px) |
57
- | `xPercent`, `yPercent` | translateX/Y in % |
58
- | `scale`, `scaleX`, `scaleY` | scale |
59
- | `rotation` | rotate (deg) |
60
- | `rotationX`, `rotationY` | 3D rotate |
61
- | `skewX`, `skewY` | skew |
62
- | `transformOrigin` | transform-origin |
63
-
64
- - **autoAlpha** — prefer over `opacity`. At 0: also sets `visibility: hidden`.
65
- - **CSS variables** — `"--hue": 180`.
66
- - **svgOrigin** _(SVG only)_ — global SVG coordinate space origin. Don't combine with `transformOrigin`.
67
- - **Directional rotation** — `"360_cw"`, `"-170_short"`, `"90_ccw"`.
68
- - **clearProps** — `"all"` or comma-separated; removes inline styles on complete.
69
- - **Relative values** — `"+=20"`, `"-=10"`, `"*=2"`.
70
-
71
- ## Function-Based Values
72
-
73
- ```javascript
74
- gsap.to(".item", {
75
- x: (i, target, targets) => i * 50,
76
- stagger: 0.1,
77
- });
78
- ```
79
-
80
- ## Easing
81
-
82
- Built-in eases: `power1`–`power4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine`. Each has `.in`, `.out`, `.inOut`.
83
-
84
- ## Defaults
85
-
86
- ```javascript
87
- gsap.defaults({ duration: 0.6, ease: "power2.out" });
88
- ```
89
-
90
- ## Controlling Tweens
91
-
92
- ```javascript
93
- const tween = gsap.to(".box", { x: 100 });
94
- tween.pause();
95
- tween.play();
96
- tween.reverse();
97
- tween.kill();
98
- tween.progress(0.5);
99
- tween.time(0.2);
100
- ```
101
-
102
- ## gsap.matchMedia() (Responsive + Accessibility)
103
-
104
- Runs setup only when a media query matches; auto-reverts when it stops matching.
105
-
106
- ```javascript
107
- let mm = gsap.matchMedia();
108
- mm.add(
109
- {
110
- isDesktop: "(min-width: 800px)",
111
- reduceMotion: "(prefers-reduced-motion: reduce)",
112
- },
113
- (context) => {
114
- const { isDesktop, reduceMotion } = context.conditions;
115
- gsap.to(".box", {
116
- rotation: isDesktop ? 360 : 180,
117
- duration: reduceMotion ? 0 : 2,
118
- });
119
- },
120
- );
121
- ```
122
-
123
- ---
124
-
125
- ## Timelines
126
-
127
- ### Creating a Timeline
128
-
129
- ```javascript
130
- const tl = gsap.timeline({ defaults: { duration: 0.5, ease: "power2.out" } });
131
- tl.to(".a", { x: 100 }).to(".b", { y: 50 }).to(".c", { opacity: 0 });
132
- ```
133
-
134
- ### Position Parameter
135
-
136
- Third argument controls placement:
137
-
138
- - **Absolute**: `1` — at 1s
139
- - **Relative**: `"+=0.5"` — after end; `"-=0.2"` — before end
140
- - **Label**: `"intro"`, `"intro+=0.3"`
141
- - **Alignment**: `"<"` — same start as previous; `">"` — after previous ends; `"<0.2"` — 0.2s after previous starts
142
-
143
- ```javascript
144
- tl.to(".a", { x: 100 }, 0);
145
- tl.to(".b", { y: 50 }, "<"); // same start as .a
146
- tl.to(".c", { opacity: 0 }, "<0.2"); // 0.2s after .b starts
147
- ```
148
-
149
- ### Labels
150
-
151
- ```javascript
152
- tl.addLabel("intro", 0);
153
- tl.to(".a", { x: 100 }, "intro");
154
- tl.addLabel("outro", "+=0.5");
155
- tl.play("outro");
156
- tl.tweenFromTo("intro", "outro");
157
- ```
158
-
159
- ### Timeline Options
160
-
161
- - **paused: true** — create paused; call `.play()` to start.
162
- - **repeat**, **yoyo** — apply to whole timeline.
163
- - **defaults** — vars merged into every child tween.
164
-
165
- ### Nesting Timelines
166
-
167
- ```javascript
168
- const master = gsap.timeline();
169
- const child = gsap.timeline();
170
- child.to(".a", { x: 100 }).to(".b", { y: 50 });
171
- master.add(child, 0);
172
- ```
173
-
174
- ### Playback Control
175
-
176
- `tl.play()`, `tl.pause()`, `tl.reverse()`, `tl.restart()`, `tl.time(2)`, `tl.progress(0.5)`, `tl.kill()`.
177
-
178
- ---
179
-
180
- ## Performance
181
-
182
- ### Prefer Transform and Opacity
183
-
184
- Animating `x`, `y`, `scale`, `rotation`, `opacity` stays on the compositor. Avoid `width`, `height`, `top`, `left` when transforms achieve the same effect.
185
-
186
- ### will-change
187
-
188
- ```css
189
- will-change: transform;
190
- ```
191
-
192
- Only on elements that actually animate.
193
-
194
- ### gsap.quickTo() for Frequent Updates
195
-
196
- ```javascript
197
- let xTo = gsap.quickTo("#id", "x", { duration: 0.4, ease: "power3" }),
198
- yTo = gsap.quickTo("#id", "y", { duration: 0.4, ease: "power3" });
199
- container.addEventListener("mousemove", (e) => {
200
- xTo(e.pageX);
201
- yTo(e.pageY);
202
- });
203
- ```
204
-
205
- ### Stagger > Many Tweens
206
-
207
- Use `stagger` instead of separate tweens with manual delays.
208
-
209
- ### Cleanup
210
-
211
- Pause or kill off-screen animations.
212
-
213
- ---
214
-
215
- ## References (loaded on demand)
216
-
217
- - **[references/effects.md](references/effects.md)** — Drop-in effects: typewriter text, audio visualizer. Read when needing ready-made effect patterns for HyperFrames.
218
-
219
- ## Best Practices
220
-
221
- - Use camelCase property names; prefer transform aliases and autoAlpha.
222
- - Prefer timelines over chaining with delay; use the position parameter.
223
- - Add labels with `addLabel()` for readable sequencing.
224
- - Pass defaults into timeline constructor.
225
- - Store tween/timeline return value when controlling playback.
226
-
227
- ## Do Not
228
-
229
- - Animate layout properties (width/height/top/left) when transforms suffice.
230
- - Use both svgOrigin and transformOrigin on the same SVG element.
231
- - Chain animations with delay when a timeline can sequence them.
232
- - Create tweens before the DOM exists.
233
- - Skip cleanup — always kill tweens when no longer needed.
234
- - Use infinite repeat values in HyperFrames compositions. Use finite repeat counts computed from the visible duration.
235
-
236
- ## Credits And References
237
-
238
- - HyperFrames adapter source: `packages/core/src/runtime/adapters/gsap.ts`.
239
- - GSAP documentation: https://gsap.com/docs/v3/
240
- - GSAP timeline pause and seek behavior: https://gsap.com/docs/v3/GSAP/Timeline/pause%28%29/