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