From 29cf749567822fdf54e1fc34d3b4776cc2e18ee2 Mon Sep 17 00:00:00 2001 From: Shreyas Karnik Date: Wed, 8 Jul 2026 13:05:26 -0700 Subject: [PATCH] =?UTF-8?q?feat:=20argo=20=C3=97=20hyperframes=20integrati?= =?UTF-8?q?on=20=E2=80=94=20shaders,=20catalog,=20block=20pre-render,=20sh?= =?UTF-8?q?owcase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four tracks (squashed from 35 local commits; full history on the local feat/hyperframes-integration branch): Track 1 — Shader transitions: 11 GLSL shaders ported from hyperframes (Apache-2.0, attribution headers), 5 -> 16 total. New export.transition.accent config tints accent-aware shaders; accent is part of the shader cache key. Track 2 — argo add + registry: installs blocks/components from the hyperframes registry (native HTML, verbatim) into blocksDir with path-traversal guards. Tier-1 component adapter: hf-component overlay cue + applyComponent()/removeComponent() page injection with validated CSS-var params. ARGO_BLOCKS_DIR env bridge at all three record() sites; argo validate checks installs + accent hex. Track 3 — Block pre-render: hf-block overlay cue -> export-time chromium pre-render (seeks window.__timelines with suppressEvents=false, alpha PNG sequences, content-addressed cache salted by RENDERER_VERSION) composited via ffmpeg overlay/enable — cutaway semantics, wired at all four export paths. Boundary extraction clamps past-video-end marks. Track 4 — Showcase demo (demos/hyperframes-showcase.*): 13-scene full-tour dogfooding everything; "crafted with Playwright, composed via HyperFrames" narrative. Video artifact distributed outside git (see PR). 720+ tests green (66 -> 74 files). Specs + implementation plans in docs/superpowers/. --- CLAUDE.md | 31 +- README.md | 85 +- blocks/data-chart/data-chart.html | 457 ++++++ blocks/data-chart/registry-item.json | 42 + blocks/grain-overlay/grain-overlay.html | 75 + blocks/grain-overlay/registry-item.json | 23 + blocks/logo-outro/logo-outro.html | 226 +++ blocks/logo-outro/registry-item.json | 42 + blocks/shimmer-sweep/registry-item.json | 23 + blocks/shimmer-sweep/shimmer-sweep.html | 66 + blocks/vignette/registry-item.json | 23 + blocks/vignette/vignette.html | 51 + demos/hyperframes-showcase.config.mjs | 35 + demos/hyperframes-showcase.demo.ts | 213 +++ demos/hyperframes-showcase.html | 233 +++ demos/hyperframes-showcase.scenes.json | 101 ++ .../2026-07-06-hyperframes-shader-port.md | 1008 ++++++++++++ .../plans/2026-07-07-argo-add-registry.md | 1373 +++++++++++++++++ .../plans/2026-07-07-hf-block-prerender.md | 831 ++++++++++ ...26-07-06-hyperframes-integration-design.md | 123 ++ skills/argo-guide/SKILL.md | 47 +- .../references/config-and-quality.md | 2 + src/cli.ts | 73 + src/config.ts | 8 + src/export.ts | 28 +- src/hf/add.ts | 86 ++ src/hf/apply-component.ts | 130 ++ src/hf/block-filter.ts | 72 + src/hf/block-render.ts | 318 ++++ src/hf/component.ts | 49 + src/hf/registry-client.ts | 98 ++ src/index.ts | 7 + src/overlays/index.ts | 29 + src/overlays/templates.ts | 8 + src/overlays/types.ts | 36 +- src/pipeline.ts | 41 +- src/preview.ts | 17 + src/record.ts | 3 + src/transitions/accent.ts | 28 + src/transitions/shader-page.html.ts | 20 +- src/transitions/shader-render.ts | 40 +- src/transitions/shaders/README.md | 33 +- src/transitions/shaders/chromatic-split.glsl | 27 + src/transitions/shaders/cinematic-zoom.glsl | 35 + src/transitions/shaders/domain-warp.glsl | 44 + .../shaders/flash-through-white.glsl | 21 + .../shaders/gravitational-lens.glsl | 28 + src/transitions/shaders/index.ts | 17 +- src/transitions/shaders/ridged-burn.glsl | 52 + src/transitions/shaders/ripple-waves.glsl | 31 + src/transitions/shaders/sdf-iris.glsl | 26 + src/transitions/shaders/swirl-vortex.glsl | 45 + .../shaders/thermal-distortion.glsl | 45 + src/transitions/shaders/whip-pan.glsl | 32 + src/validate.ts | 43 +- tests/config.test.ts | 1 + tests/hf/add.test.ts | 105 ++ tests/hf/apply-component.test.ts | 83 + tests/hf/block-filter.test.ts | 49 + tests/hf/block-render.test.ts | 118 ++ tests/hf/component.test.ts | 71 + tests/hf/config-blocks.test.ts | 19 + tests/hf/export-hf-blocks.test.ts | 14 + tests/hf/hf-block-cue.test.ts | 27 + tests/hf/hf-component-cue.test.ts | 53 + tests/hf/registry-client.test.ts | 93 ++ tests/hf/render-hf-blocks.test.ts | 82 + tests/hf/validate-hf.test.ts | 131 ++ tests/transitions/accent.test.ts | 33 + tests/transitions/shader-render.test.ts | 124 +- 70 files changed, 7634 insertions(+), 49 deletions(-) create mode 100644 blocks/data-chart/data-chart.html create mode 100644 blocks/data-chart/registry-item.json create mode 100644 blocks/grain-overlay/grain-overlay.html create mode 100644 blocks/grain-overlay/registry-item.json create mode 100644 blocks/logo-outro/logo-outro.html create mode 100644 blocks/logo-outro/registry-item.json create mode 100644 blocks/shimmer-sweep/registry-item.json create mode 100644 blocks/shimmer-sweep/shimmer-sweep.html create mode 100644 blocks/vignette/registry-item.json create mode 100644 blocks/vignette/vignette.html create mode 100644 demos/hyperframes-showcase.config.mjs create mode 100644 demos/hyperframes-showcase.demo.ts create mode 100644 demos/hyperframes-showcase.html create mode 100644 demos/hyperframes-showcase.scenes.json create mode 100644 docs/superpowers/plans/2026-07-06-hyperframes-shader-port.md create mode 100644 docs/superpowers/plans/2026-07-07-argo-add-registry.md create mode 100644 docs/superpowers/plans/2026-07-07-hf-block-prerender.md create mode 100644 docs/superpowers/specs/2026-07-06-hyperframes-integration-design.md create mode 100644 src/hf/add.ts create mode 100644 src/hf/apply-component.ts create mode 100644 src/hf/block-filter.ts create mode 100644 src/hf/block-render.ts create mode 100644 src/hf/component.ts create mode 100644 src/hf/registry-client.ts create mode 100644 src/transitions/accent.ts create mode 100644 src/transitions/shaders/chromatic-split.glsl create mode 100644 src/transitions/shaders/cinematic-zoom.glsl create mode 100644 src/transitions/shaders/domain-warp.glsl create mode 100644 src/transitions/shaders/flash-through-white.glsl create mode 100644 src/transitions/shaders/gravitational-lens.glsl create mode 100644 src/transitions/shaders/ridged-burn.glsl create mode 100644 src/transitions/shaders/ripple-waves.glsl create mode 100644 src/transitions/shaders/sdf-iris.glsl create mode 100644 src/transitions/shaders/swirl-vortex.glsl create mode 100644 src/transitions/shaders/thermal-distortion.glsl create mode 100644 src/transitions/shaders/whip-pan.glsl create mode 100644 tests/hf/add.test.ts create mode 100644 tests/hf/apply-component.test.ts create mode 100644 tests/hf/block-filter.test.ts create mode 100644 tests/hf/block-render.test.ts create mode 100644 tests/hf/component.test.ts create mode 100644 tests/hf/config-blocks.test.ts create mode 100644 tests/hf/export-hf-blocks.test.ts create mode 100644 tests/hf/hf-block-cue.test.ts create mode 100644 tests/hf/hf-component-cue.test.ts create mode 100644 tests/hf/registry-client.test.ts create mode 100644 tests/hf/render-hf-blocks.test.ts create mode 100644 tests/hf/validate-hf.test.ts create mode 100644 tests/transitions/accent.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index ac25301..eafeca5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,9 +65,9 @@ Both the primary export path and blur-fill format variants (1:1, 9:16) are encod Pre-rendered WebGL shader transitions. At export time, a pre-pass extracts two boundary frames per scene boundary (last frame of outgoing, first frame of incoming) via ffmpeg, then Playwright Chromium renders the GLSL shader at each of `N = D × fps` progress values, producing a PNG sequence. `buildShaderSpliceFilter` generates a filter_complex three-segment concat (`scene_a + PNG_seq + scene_b`) that replaces the fade window. -Cache key: `sha256(shader, durationMs, fps, width, height, sha256(aPng), sha256(bPng))`. Cached at `.argo//shaders//`. Second export with unchanged boundaries hits cache with no browser launch. +Cache key: `sha256(shader, durationMs, fps, width, height, sha256(aPng), sha256(bPng), accent)`. Cached at `.argo//shaders//`. Second export with unchanged boundaries hits cache with no browser launch. -Shaders live in `src/transitions/shaders/*.glsl`. Build step copies `.glsl` files to `dist/` (tsc does not). v1 ships: `crosswarp`, `swirl`, `ripple`, `luma-mask`, `light-leak` — adapted from gl-transitions.com (MIT). +Shaders live in `src/transitions/shaders/*.glsl`. Build step copies `.glsl` files to `dist/` (tsc does not). v1 ships: `crosswarp`, `swirl`, `ripple`, `luma-mask`, `light-leak` — adapted from gl-transitions.com (MIT), plus 11 hyperframes ports (Apache-2.0): `domain-warp`, `ridged-burn`, `thermal-distortion`, `swirl-vortex`, `whip-pan`, `gravitational-lens`, `cinematic-zoom`, `chromatic-split`, `flash-through-white`, `sdf-iris`, `ripple-waves`. `export.transition.accent` (default `'#0ea5e9'`) tints accent-aware shaders: `domain-warp`, `ridged-burn`, `thermal-distortion`, `sdf-iris`, `ripple-waves`. Per-boundary shader selection is NOT supported in v1 — `export.transition.shader` applies to all boundaries. Future work: a sidecar for per-boundary overrides. @@ -111,7 +111,27 @@ Static v1 blocks: `x-post`, `macos-notification`, `yt-lower-third`, `data-chart` Animated blocks (ship with `defaultMotion` using GSAP): `instagram-follow` (pulsing Follow button), `tiktok-follow` (rotating avatar ring + side slide), `reddit-post` (upvote card, simple entrance), `logo-outro` (scale-in end-card), `flowchart` (stacked nodes + arrows revealed with stagger), `app-showcase` (hero card with floating icon loop), `ui-3d-reveal` (perspective tilt-to-flat reveal of a screenshot). These use `BlockDefinition.defaultMotion` — a cue-level `motion` still overrides. Inspired by hyperframes blocks of the same names (Apache-2.0); implementations are original. Selector hooks used by motion loops/staggers: `.argo-ig-follow-btn`, `.argo-tt-ring`, `.argo-app-hero`, `.argo-3d-image`, `.argo-flow-node, .argo-flow-arrow`. -Folder format is designed for a future `argo add ` command (not shipped yet). +These built-in blocks ship inside the package (`src/blocks/`) — distinct from the hyperframes registry items installed into `blocksDir` by `argo add` (see HyperFrames Catalog below). + +### HyperFrames Catalog (`src/hf/`) + +`argo add ` installs blocks/components from the hyperframes registry (default `https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry`, override via `--registry ` or config `registry.url`) into `blocksDir` (config, default `blocks/`, git-tracked). `argo add --list` (+ `--json`) browses the registry. Registry examples (`hyperframes:example`) are not installable. Item files are stored verbatim in native hyperframes format at `blocks//` plus a `registry-item.json` sidecar. Modules: `registry-client.ts` (fetch-injectable client — unit tests never touch the network), `add.ts` (`installItem`/`listItems`, path-traversal guards on item names and file paths), `component.ts` (snippet parser + CSS param validators), `apply-component.ts` (page injection). + +Overlay cue: `{ "type": "hf-component", "name": "vignette", "params": { "--vignette-size": "40%" } }` — full-frame injection (fixed, pointer-events none, high z-index) that bypasses the zone/theme/template machinery; duration comes from `showOverlay`. Script API: `applyComponent(page, name, { params?, blocksDir? })` / `removeComponent(page, name)` exported from the package — persists until removed. `params` are validated CSS custom properties (`--kebab-case` names, conservative value allowlist — no `url()`, `;{}<>`, control chars). Injection uses the same no-op `page.evaluate()` render fence as overlays and the same disposal-error-swallowing pattern as `showConfetti`. + +Trust model: components are trusted-at-install (user ran `argo add`, files are git-reviewable); only runtime `params` are validated. Component ` + + + +
+
+ +
+

Monthly Revenue vs. Conversion Rate

+

Jan–Jun 2024, in thousands

+
+
+
+ Revenue +
+
+
+ Conversion Rate +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Source: Internal analytics
+
+ + + + +
+ + diff --git a/blocks/data-chart/registry-item.json b/blocks/data-chart/registry-item.json new file mode 100644 index 0000000..d6c8147 --- /dev/null +++ b/blocks/data-chart/registry-item.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", + "name": "data-chart", + "type": "hyperframes:block", + "title": "Data Chart", + "description": "Animated bar + line chart with staggered reveal, NYT-style typography, and value labels", + "tags": [ + "data", + "chart", + "statistics" + ], + "dimensions": { + "width": 1920, + "height": 1080 + }, + "duration": 15, + "files": [ + { + "path": "data-chart.html", + "target": "compositions/data-chart.html", + "type": "hyperframes:composition" + } + ], + "preview": { + "video": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/data-chart.mp4", + "poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/data-chart.png" + }, + "params": [ + { + "key": "--bg-color", + "label": "Background", + "type": "color", + "default": "#faf9f6" + }, + { + "key": "--text-color", + "label": "Text color", + "type": "color", + "default": "#333333" + } + ] +} \ No newline at end of file diff --git a/blocks/grain-overlay/grain-overlay.html b/blocks/grain-overlay/grain-overlay.html new file mode 100644 index 0000000..6bd06c3 --- /dev/null +++ b/blocks/grain-overlay/grain-overlay.html @@ -0,0 +1,75 @@ + + +
+
+
+ + diff --git a/blocks/grain-overlay/registry-item.json b/blocks/grain-overlay/registry-item.json new file mode 100644 index 0000000..0c934ad --- /dev/null +++ b/blocks/grain-overlay/registry-item.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", + "name": "grain-overlay", + "type": "hyperframes:component", + "title": "Grain Overlay", + "description": "Animated film grain texture overlay using CSS keyframes — adds warmth and analog character to any composition", + "tags": [ + "texture", + "grain", + "overlay", + "film" + ], + "files": [ + { + "path": "grain-overlay.html", + "target": "compositions/components/grain-overlay.html", + "type": "hyperframes:snippet" + } + ], + "preview": { + "poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/grain-overlay.png" + } +} \ No newline at end of file diff --git a/blocks/logo-outro/logo-outro.html b/blocks/logo-outro/logo-outro.html new file mode 100644 index 0000000..96c2808 --- /dev/null +++ b/blocks/logo-outro/logo-outro.html @@ -0,0 +1,226 @@ + + + + + + Logo Outro + + + + + + + +
+
+ +
+ + +
+ + + + + + + + +
+ +
+
Demos as code. Motion as catalog.
+
+ argo × hyperframes +
+
+
+ + + + +
+ + diff --git a/blocks/logo-outro/registry-item.json b/blocks/logo-outro/registry-item.json new file mode 100644 index 0000000..a44c982 --- /dev/null +++ b/blocks/logo-outro/registry-item.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", + "name": "logo-outro", + "type": "hyperframes:block", + "title": "Logo Outro", + "description": "Cinematic logo reveal with piece-by-piece assembly, glow bloom, tagline fade-in, and URL pill", + "tags": [ + "branding", + "outro", + "logo" + ], + "dimensions": { + "width": 1920, + "height": 1080 + }, + "duration": 6, + "files": [ + { + "path": "logo-outro.html", + "target": "compositions/logo-outro.html", + "type": "hyperframes:composition" + } + ], + "preview": { + "video": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/logo-outro.mp4", + "poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/logo-outro.png" + }, + "params": [ + { + "key": "--bg-color", + "label": "Background", + "type": "color", + "default": "#0a0a0f" + }, + { + "key": "--accent-color", + "label": "Accent", + "type": "color", + "default": "#1a1a1f" + } + ] +} \ No newline at end of file diff --git a/blocks/shimmer-sweep/registry-item.json b/blocks/shimmer-sweep/registry-item.json new file mode 100644 index 0000000..aa8cde1 --- /dev/null +++ b/blocks/shimmer-sweep/registry-item.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", + "name": "shimmer-sweep", + "type": "hyperframes:component", + "title": "Shimmer Sweep", + "description": "Animated light sweep across text or elements using a CSS gradient mask — ideal for AI accents and premium reveals", + "tags": [ + "text", + "shimmer", + "highlight", + "effect" + ], + "files": [ + { + "path": "shimmer-sweep.html", + "target": "compositions/components/shimmer-sweep.html", + "type": "hyperframes:snippet" + } + ], + "preview": { + "poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/shimmer-sweep.png" + } +} \ No newline at end of file diff --git a/blocks/shimmer-sweep/shimmer-sweep.html b/blocks/shimmer-sweep/shimmer-sweep.html new file mode 100644 index 0000000..84d3be4 --- /dev/null +++ b/blocks/shimmer-sweep/shimmer-sweep.html @@ -0,0 +1,66 @@ + + + + + + + diff --git a/blocks/vignette/registry-item.json b/blocks/vignette/registry-item.json new file mode 100644 index 0000000..a1c0283 --- /dev/null +++ b/blocks/vignette/registry-item.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", + "name": "vignette", + "type": "hyperframes:component", + "title": "Vignette", + "description": "Cinematic radial vignette overlay using a pure-CSS gradient — darkens the edges to pull focus toward the center", + "tags": [ + "vignette", + "overlay", + "cinematic", + "effect" + ], + "files": [ + { + "path": "vignette.html", + "target": "compositions/components/vignette.html", + "type": "hyperframes:snippet" + } + ], + "preview": { + "poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/vignette.png" + } +} \ No newline at end of file diff --git a/blocks/vignette/vignette.html b/blocks/vignette/vignette.html new file mode 100644 index 0000000..18ba2d0 --- /dev/null +++ b/blocks/vignette/vignette.html @@ -0,0 +1,51 @@ + + +
+ + + + diff --git a/demos/hyperframes-showcase.config.mjs b/demos/hyperframes-showcase.config.mjs new file mode 100644 index 0000000..702b5bb --- /dev/null +++ b/demos/hyperframes-showcase.config.mjs @@ -0,0 +1,35 @@ +import { defineConfig } from '@argo-video/cli'; + +export default defineConfig({ + baseURL: 'http://localhost:8976', + demosDir: 'demos', + outputDir: 'videos', + blocksDir: 'blocks', + tts: { defaultVoice: 'af_heart', defaultSpeed: 1.0 }, + video: { + width: 1920, + height: 1080, + fps: 30, + browser: 'chromium', + captureMode: 'jpeg-stitch', + // q88 (not 95): the catalog scene captures a playing video preview — + // q95 frames of video noise saturate the stitch writer. + jpegQuality: 88, + // The live-site scenes occasionally wedge the renderer under screencast; + // one retry re-runs the demo rather than failing the pipeline. + retries: 1, + showActions: false, + }, + export: { + preset: 'slow', + // Dark story-page backdrops — same banding rationale as the main showcase. + crf: 14, + encoder: 'cpu', + // Track 1 dogfood: hyperframes-ported shader at every boundary, tinted + // with the brand accent (domain-warp uses accentDark/accentBright for its + // edge glow). + // whip-pan: fast camera-language cut — matches the "choreography" thesis + // and never smears on-screen text the way long warps do. + transition: { type: 'shader', shader: 'whip-pan', durationMs: 1600, accent: '#0ea5e9' }, + }, +}); diff --git a/demos/hyperframes-showcase.demo.ts b/demos/hyperframes-showcase.demo.ts new file mode 100644 index 0000000..bccc75d --- /dev/null +++ b/demos/hyperframes-showcase.demo.ts @@ -0,0 +1,213 @@ +/** + * Argo × HyperFrames — comprehensive "full tour" showcase. + * + * Covers every major feature of both systems in one take: + * argo: multi-voice TTS, all overlay templates + blocks, GSAP motion, + * spotlight/focusRing/dimAround, post-export zoomTo, cursorHighlight, + * confetti (burst + emoji), freeze-frame hold, 16 shader transitions, + * chapters/subtitles/meta (narrated). + * hyperframes: 142-item catalog (live site), vignette/grain/shimmer-sweep + * components, data-chart block cutaway, edited logo-outro end card. + * + * Prerequisites: + * 1. npx argo add vignette grain-overlay shimmer-sweep data-chart logo-outro (one per call) + * 2. python3 -m http.server 8976 --directory demos + * 3. npx tsx bin/argo.js pipeline hyperframes-showcase --config demos/hyperframes-showcase.config.mjs + */ +import { test } from '@argo-video/cli'; +import { showOverlay, applyComponent, showConfetti } from '@argo-video/cli'; +import { zoomTo, spotlight, focusRing, dimAround, resetCamera } from '@argo-video/cli'; +import { cursorHighlight, resetCursor } from '@argo-video/cli'; + +test('hyperframes-showcase', async ({ page, narration }) => { + // 15 min: the recording is ~3.5 min of content, but a loaded machine can + // run the screencast writer 2x+ slower — give slow runs room to finish + // rather than dying at the outro (mark-drift clamps handle the rest). + test.setTimeout(900_000); + + await page.goto('/hyperframes-showcase.html'); + await page.waitForTimeout(700); + + await narration.startRecording(page); + + // ── 1. hook ─────────────────────────────────────────────────────────────── + narration.mark('hook'); + const hookMs = narration.sceneDuration('hook'); + void showOverlay(page, 'hook', Math.floor(hookMs * 0.75)); + await page.waitForTimeout(narration.durationFor('hook')); + + // ── 2. catalog (live site — three movements for energy) ───────────────── + // Screencast + jpeg-stitch note: pages full of autoplaying