chore: import upstream snapshot with attribution
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "hyperframes",
|
||||
"owner": {
|
||||
"name": "HeyGen",
|
||||
"email": "hyperframes@heygen.com",
|
||||
"url": "https://hyperframes.heygen.com"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "hyperframes",
|
||||
"source": "./",
|
||||
"description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.",
|
||||
"homepage": "https://hyperframes.heygen.com",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "hyperframes",
|
||||
"description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.",
|
||||
"version": "0.7.55",
|
||||
"author": {
|
||||
"name": "HeyGen",
|
||||
"email": "hyperframes@heygen.com",
|
||||
"url": "https://hyperframes.heygen.com"
|
||||
},
|
||||
"homepage": "https://hyperframes.heygen.com",
|
||||
"repository": "https://github.com/heygen-com/hyperframes",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "hyperframes",
|
||||
"version": "0.7.55",
|
||||
"description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.",
|
||||
"author": {
|
||||
"name": "HeyGen",
|
||||
"email": "hyperframes@heygen.com",
|
||||
"url": "https://hyperframes.heygen.com"
|
||||
},
|
||||
"homepage": "https://hyperframes.heygen.com",
|
||||
"repository": "https://github.com/heygen-com/hyperframes",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
"hyperframes",
|
||||
"video",
|
||||
"html",
|
||||
"tailwind",
|
||||
"gsap",
|
||||
"lottie",
|
||||
"three",
|
||||
"waapi",
|
||||
"animejs",
|
||||
"animation",
|
||||
"composition",
|
||||
"rendering",
|
||||
"captions",
|
||||
"tts",
|
||||
"audio-reactive"
|
||||
],
|
||||
"skills": "./skills/",
|
||||
"interface": {
|
||||
"displayName": "HyperFrames by HeyGen",
|
||||
"shortDescription": "Write HTML, render video",
|
||||
"longDescription": "Build videos from HTML with HyperFrames. Author compositions with HTML, CSS, Tailwind v4 browser-runtime styles, GSAP, Anime.js, Lottie, Three.js, and WAAPI adapter patterns, use the CLI for the dev loop (init/preview/render), preprocess assets (tts/transcribe/remove-background) for compositions, install reusable registry blocks and components, and turn any website into a video with the 7-step capture-to-video pipeline.",
|
||||
"developerName": "HeyGen",
|
||||
"category": "Creativity",
|
||||
"capabilities": ["Read", "Write"],
|
||||
"websiteURL": "https://hyperframes.heygen.com",
|
||||
"defaultPrompt": [
|
||||
"Turn this website into a 20-second product promo",
|
||||
"Create an animated title card with kinetic type",
|
||||
"Add synced captions to this voiceover"
|
||||
],
|
||||
"brandColor": "#0a0a0a",
|
||||
"composerIcon": "./assets/icon.png",
|
||||
"logo": "./assets/logo.png"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node -e \"\nconst chunks = [];\nprocess.stdin.on('data', d => chunks.push(d));\nprocess.stdin.on('end', () => {\n const input = JSON.parse(Buffer.concat(chunks).toString());\n const cmd = input.tool_input?.command || '';\n if (!/git\\\\s+commit\\\\b/.test(cmd)) process.exit(0);\n const { execSync } = require('child_process');\n const cwd = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();\n const steps = [\n ['bun run build', 'Build'],\n ['bun run lint', 'Lint'],\n ['bun run --filter \\'*\\' typecheck 2>&1 | grep -v \\'vitest\\\\|test\\\\.ts\\' || true', 'Typecheck'],\n ];\n const failures = [];\n for (const [script, label] of steps) {\n try { execSync(script, { cwd, stdio: 'pipe' }); }\n catch (e) {\n failures.push(label + ':\\\\n' + (e.stdout?.toString() || e.message).slice(0, 400));\n }\n }\n if (failures.length > 0) {\n process.stdout.write(JSON.stringify({\n continue: false,\n stopReason: '\\u274c Pre-commit checks failed:\\\\n\\\\n' + failures.join('\\\\n\\\\n') + '\\\\n\\\\nFix the issues above before committing.',\n }));\n }\n});\"",
|
||||
"timeout": 180,
|
||||
"statusMessage": "Running build + lint + typecheck before commit…"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://cursor.com/schemas/cursor-plugin/plugin.json",
|
||||
"name": "hyperframes",
|
||||
"displayName": "HyperFrames by HeyGen",
|
||||
"version": "0.7.55",
|
||||
"description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.",
|
||||
"author": {
|
||||
"name": "HeyGen",
|
||||
"email": "hyperframes@heygen.com"
|
||||
},
|
||||
"publisher": "HeyGen",
|
||||
"homepage": "https://hyperframes.heygen.com",
|
||||
"repository": "https://github.com/heygen-com/hyperframes",
|
||||
"license": "Apache-2.0",
|
||||
"logo": "assets/logo.png",
|
||||
"category": "developer-tools",
|
||||
"keywords": [
|
||||
"hyperframes",
|
||||
"video",
|
||||
"html",
|
||||
"tailwind",
|
||||
"gsap",
|
||||
"lottie",
|
||||
"three",
|
||||
"waapi",
|
||||
"animejs",
|
||||
"animation",
|
||||
"composition",
|
||||
"rendering",
|
||||
"captions",
|
||||
"tts",
|
||||
"audio-reactive"
|
||||
],
|
||||
"tags": ["video", "animation", "design", "creative", "workflow"],
|
||||
"skills": "./skills/"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1,5 @@
|
||||
# No environment variables required for basic usage.
|
||||
# Run `bun run dev` to start the studio, `npx hyperframes render` to render video.
|
||||
|
||||
# Optional integrations:
|
||||
# GEMINI_API_KEY= # AI image captioning during website capture (~$0.001/image, https://aistudio.google.com/apikey)
|
||||
+624
@@ -0,0 +1,624 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/config-schema.json",
|
||||
"entry": [
|
||||
"packages/producer/src/**/*.test.ts",
|
||||
"packages/aws-lambda/src/**/*.test.ts",
|
||||
"packages/gcp-cloud-run/src/**/*.test.ts",
|
||||
"packages/producer/src/regression-harness.ts",
|
||||
"packages/producer/src/regression-harness-distributed.test.ts",
|
||||
"packages/producer/src/regression-harness-lambda-local.ts",
|
||||
"packages/producer/src/transparency-test.ts",
|
||||
"packages/producer/src/parity-harness.ts",
|
||||
"packages/producer/src/parity-fixtures.ts",
|
||||
"packages/producer/src/perf-gate.ts",
|
||||
"packages/producer/src/runtime-conformance.ts",
|
||||
"packages/producer/src/benchmark.ts",
|
||||
"packages/producer/scripts/generate-font-data.ts",
|
||||
"packages/producer/we-render.mjs",
|
||||
"packages/producer/scripts/validate-fast-video.ts",
|
||||
"packages/cli/scripts/generate-font-data.ts",
|
||||
"packages/engine/scripts/test-fitTextFontSize-browser.ts",
|
||||
"packages/aws-lambda/scripts/*.ts",
|
||||
// Built as standalone IIFE for the browser-side sandbox runtime;
|
||||
// referenced by file path (not import) in build-hyperframes-runtime-artifact.ts.
|
||||
"packages/core/src/runtime/entry.ts",
|
||||
// Bundled as a standalone IIFE by the position-edits render artifact
|
||||
// generator; referenced by file path rather than imported by TypeScript.
|
||||
"packages/core/stubs/position-edits-render-entry.ts",
|
||||
// In-page audit scripts read as raw strings and injected via
|
||||
// page.addScriptTag (see layout.ts / validate.ts) — referenced by file
|
||||
// path, never imported, so they have no import-graph referrer.
|
||||
"packages/cli/src/commands/layout-audit.browser.js",
|
||||
"packages/cli/src/commands/contrast-audit.browser.js",
|
||||
"packages/cli/src/commands/motion-sample.browser.js",
|
||||
// Worker entry points loaded dynamically by their *Pool.ts companions.
|
||||
"packages/producer/src/services/pngDecodeBlitWorker.ts",
|
||||
"packages/producer/src/services/shaderTransitionWorker.ts",
|
||||
// Off-main-thread /health endpoint, spawned by path from healthWorker.ts.
|
||||
"packages/producer/src/services/healthWorkerThread.ts",
|
||||
// Test fixture worker, spawned by path via the pools' workerEntryPath
|
||||
// option from the crash-recovery tests; has no import-graph referrer.
|
||||
"packages/producer/src/services/__fixtures__/crashOnMessageWorker.mjs",
|
||||
"scripts/*.{ts,mjs,js}",
|
||||
"scripts/*/run.mjs",
|
||||
// Keyframe UI components — wired dynamically via EaseCurveSection/MotionPanel.
|
||||
"packages/studio/src/components/editor/KeyframeDiamond.tsx",
|
||||
"packages/studio/src/components/editor/SpringEaseEditor.tsx",
|
||||
// NLE notice — rendered conditionally via NLELayout when timeline is first shown.
|
||||
"packages/studio/src/components/nle/TimelineEditorNotice.tsx",
|
||||
// Zoom hook extracted for downstream razor-blade PRs (#1330, #1331).
|
||||
"packages/studio/src/player/components/useTimelineZoom.ts",
|
||||
// Cached O(1) GSAP target lookup, replacing O(n²) inline checks.
|
||||
// Consumers migrate in a follow-up once useDomGeometryCommits adopts it.
|
||||
"packages/studio/src/hooks/gsapTargetCache.ts",
|
||||
// Preview helper consumed dynamically from the studio iframe bridge.
|
||||
"packages/studio/src/hooks/gsapRuntimePreview.ts",
|
||||
// TEMP(studio-dnd): shipped unwired ahead of the NLE integration;
|
||||
// the app-shell swap PR (studio-dnd/pr22) wires the consumers and removes this block.
|
||||
"packages/studio/src/components/editor/CanvasContextMenu.tsx",
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"docs/**",
|
||||
// Chrome browser binaries downloaded by puppeteer — not project source.
|
||||
"chrome/**",
|
||||
// Standalone spike scripts and benchmark runners used during R&D.
|
||||
"packages/engine/spikes/**",
|
||||
"packages/producer/de-*.mjs",
|
||||
"packages/producer/tests/**",
|
||||
"packages/player/tests/**",
|
||||
"packages/engine/tests/**",
|
||||
"skills/**/test-corpus/**",
|
||||
"skills/**/scripts/**",
|
||||
// Agent-invoked motion-graphics tools co-located with their docs (run via
|
||||
// `node <path>` per grounding/PROTOCOL.md / categories/maps/module.md
|
||||
// prose), not import-graph reachable.
|
||||
"skills/motion-graphics/grounding/**",
|
||||
"skills/motion-graphics/categories/**",
|
||||
// Agent-invoked reference materials (template + motion-primitive HTML, catalogs),
|
||||
// forked by path by the frame-worker per SKILL.md prose, not import-graph reachable.
|
||||
"skills/music-to-video/references/**",
|
||||
// Bundled @font-face data (read at runtime via fs.readFileSync, invisible
|
||||
// to the import graph) + its manual rebuild tool.
|
||||
"skills/**/fonts/**",
|
||||
// Golden snapshot files: data consumed by toMatchFileSnapshot, not importable modules.
|
||||
"packages/**/__goldens__/**",
|
||||
"registry/**",
|
||||
"examples/**",
|
||||
"packages/sdk/examples/**",
|
||||
".github/workflows/fixtures/**",
|
||||
// Auto-generated TS client for the HeyGen cloud API. Regenerated by
|
||||
// experiment-framework/scripts/generate_hyperframes_cli_client.py via
|
||||
// the sync-hyperframes-codegen.yml workflow; complexity/dead-code
|
||||
// findings on this file are not actionable from this repo.
|
||||
"packages/cli/src/cloud/_gen/**",
|
||||
],
|
||||
"ignoreExports": [
|
||||
// TEMP(studio-dnd): consumers land later in the stack; removed by studio-dnd/pr22.
|
||||
{
|
||||
"file": "packages/studio/src/components/editor/canvasContextMenuZOrder.ts",
|
||||
"exports": ["readEffectiveZIndex"],
|
||||
},
|
||||
// drawElementService is the bottom of the fast-capture Graphite stack
|
||||
// (#1917): its consumers (frameCapture in #1919) land two PRs upstack, so
|
||||
// a per-PR audit diffing against the merge base sees these exports as
|
||||
// unused. Consumed for real once the stack merges; safe to drop this
|
||||
// entry after #1919 lands.
|
||||
{
|
||||
"file": "packages/engine/src/services/drawElementService.ts",
|
||||
"exports": [
|
||||
"instrumentAcceleratedCanvases",
|
||||
"injectDrawElementCanvas",
|
||||
"captureDrawElementFrame",
|
||||
"initDrawElementWorkerEncode",
|
||||
"cleanupDrawElementWorkerEncode",
|
||||
"produceDrawElementFrame",
|
||||
],
|
||||
},
|
||||
// CLI command files: every command exports a const `examples` per the
|
||||
// convention documented in CLAUDE.md. This is a namespace barrel, not a
|
||||
// collision.
|
||||
{ "file": "packages/cli/src/commands/*.ts", "exports": ["examples"] },
|
||||
// Options type for the render-queue hook's public startRender callback —
|
||||
// consumed structurally by callers (StudioRightPanel), not by import.
|
||||
{
|
||||
"file": "packages/studio/src/components/renders/useRenderQueue.ts",
|
||||
"exports": ["StartRenderOptions"],
|
||||
},
|
||||
// Independent ML model managers each declare their own DEFAULT_MODEL /
|
||||
// MODELS_DIR / ensureModel for their model namespace.
|
||||
{
|
||||
"file": "packages/cli/src/{background-removal,tts,whisper}/manager.ts",
|
||||
"exports": ["DEFAULT_MODEL", "MODELS_DIR", "ensureModel"],
|
||||
},
|
||||
// `isPathInside` is documented as exported-for-tests only in fileServer.ts;
|
||||
// it has different semantics (symlink resolution) from utils/paths.ts.
|
||||
{
|
||||
"file": "packages/producer/src/services/fileServer.ts",
|
||||
"exports": ["isPathInside"],
|
||||
},
|
||||
// Studio telemetry: consumed by useRenderQueue.ts / StudioFeedbackBar.tsx
|
||||
// (deep relative imports) but fallow's static analyzer doesn't trace
|
||||
// them. Same path-resolution quirk — trackStudioSessionStart from the
|
||||
// same file resolves fine.
|
||||
{
|
||||
"file": "packages/studio/src/telemetry/events.ts",
|
||||
"exports": ["trackStudioRenderStart", "trackStudioFeedback"],
|
||||
},
|
||||
// domEditingLayers: these exports are consumed via the browser iframe
|
||||
// runtime context (not traceable by static import analysis from the
|
||||
// studio entry point) or re-exported through the domEditing barrel but
|
||||
// have no downstream consumers yet.
|
||||
{
|
||||
"file": "packages/studio/src/components/editor/domEditingLayers.ts",
|
||||
"exports": [
|
||||
"isEditableTextLeaf",
|
||||
"collectDomEditTextFields",
|
||||
"buildElementLabel",
|
||||
"refreshDomEditSelection",
|
||||
],
|
||||
},
|
||||
// domEditing barrel: re-exports consumed throughout the studio but
|
||||
// fallow's static analyzer can't trace re-exports through barrel files.
|
||||
{
|
||||
"file": "packages/studio/src/components/editor/domEditing.ts",
|
||||
"exports": ["*"],
|
||||
},
|
||||
// Exported for render.test.ts (exported-for-tests pattern).
|
||||
{
|
||||
"file": "packages/cli/src/commands/render.ts",
|
||||
"exports": ["resolveBrowserGpuForCli", "renderLocal", "checkRenderResolutionPreflight"],
|
||||
},
|
||||
// initThreeDProjectionInPage: passed to page.evaluate() for browser-side execution —
|
||||
// Puppeteer serializes it at runtime, not an import-graph consumer.
|
||||
{
|
||||
"file": "packages/engine/src/services/threeDProjection.ts",
|
||||
"exports": ["initThreeDProjectionInPage"],
|
||||
},
|
||||
// captureCost.ts: constants and helpers consumed by the runCaptureCalibration
|
||||
// orchestration function and tests, but the entry-point graph doesn't
|
||||
// reach them because the orchestrator's caller resolves them dynamically.
|
||||
{
|
||||
"file": "packages/producer/src/services/render/captureCost.ts",
|
||||
"exports": [
|
||||
"CAPTURE_CALIBRATION_TARGET_MS",
|
||||
"MAX_MEASURED_CAPTURE_COST_MULTIPLIER",
|
||||
"CAPTURE_CALIBRATION_PROTOCOL_TIMEOUT_MS",
|
||||
"measureCaptureCostFromSession",
|
||||
"logCaptureCalibrationResult",
|
||||
"createFailedCaptureCalibrationEstimate",
|
||||
],
|
||||
},
|
||||
// gsapParserExports.ts is the public-API barrel that re-exports constants,
|
||||
// types, and utilities from gsapConstants, gsapSerialize, and springEase.
|
||||
// The re-exports are intentional public API consumed by callers outside the
|
||||
// changed-file set (e.g. studio, aws-lambda) and therefore appear unused
|
||||
// to fallow's static analysis of the PR diff.
|
||||
{
|
||||
"file": "packages/parsers/src/gsapParserExports.ts",
|
||||
"exports": [
|
||||
"PROPERTY_GROUPS",
|
||||
"classifyPropertyGroup",
|
||||
"classifyTweenPropertyGroup",
|
||||
"SPRING_PRESETS",
|
||||
"generateSpringEaseData",
|
||||
"GsapMethod",
|
||||
"GsapKeyframesData",
|
||||
"GsapKeyframeFormat",
|
||||
"PropertyGroupName",
|
||||
"SpringPreset",
|
||||
],
|
||||
},
|
||||
// Shared test helpers consumed by gsapParser.test.ts (same file,
|
||||
// fallow doesn't trace intra-file test consumption).
|
||||
{
|
||||
"file": "packages/parsers/src/gsapParser.test-helpers.ts",
|
||||
"exports": [
|
||||
"expectKeyframe",
|
||||
"expectKeyframesFormat",
|
||||
"convertAndReparse",
|
||||
"parseSplitAndAssert",
|
||||
],
|
||||
},
|
||||
// hfIds: EXCLUDED_TAGS is consumed by tests (htmlParser.test.ts) and
|
||||
// hfIdPersist.ts but fallow's static analyzer may not trace all consumers.
|
||||
{
|
||||
"file": "packages/parsers/src/hfIds.ts",
|
||||
"exports": ["EXCLUDED_TAGS", "mintHfId"],
|
||||
},
|
||||
// Shared timeline components extracted for downstream PRs in the
|
||||
// razor-blade stack (#1330, #1331). Consumers live on those branches.
|
||||
{
|
||||
"file": "packages/studio/src/player/components/timelineCallbacks.ts",
|
||||
"exports": ["*"],
|
||||
},
|
||||
// Shared timeline DOM barrel for downstream consumers; fallow does not
|
||||
// trace all re-export-only modules.
|
||||
{
|
||||
"file": "packages/studio/src/player/lib/timelineDOM.ts",
|
||||
"exports": ["*"],
|
||||
},
|
||||
// gsapTargetCache: cached O(1) GSAP target lookup, consumed by
|
||||
// useDomEditCommits and intended to replace the local copy in
|
||||
// useDomGeometryCommits once callers migrate.
|
||||
{
|
||||
"file": "packages/studio/src/hooks/gsapTargetCache.ts",
|
||||
"exports": ["isElementGsapTargeted"],
|
||||
},
|
||||
// Re-exports from useDomEditCommits: barrel-style re-exports
|
||||
// consumed by downstream studio code.
|
||||
{
|
||||
"file": "packages/studio/src/hooks/useDomEditCommits.ts",
|
||||
"exports": ["GSAP_CSS_FALLBACK_BLOCKED_MESSAGE", "PersistDomEditOperations"],
|
||||
},
|
||||
{
|
||||
"file": "packages/studio/src/utils/timelineElementSplit.ts",
|
||||
"exports": ["buildPatchTarget", "readFileContent"],
|
||||
},
|
||||
// freezeUrl and freezeLocalFile are public API re-exported from the figma
|
||||
// barrel (index.ts) for Task 4 manifest flow and the /figma skill integration;
|
||||
// not yet imported by current code outside the module.
|
||||
{
|
||||
"file": "packages/core/src/figma/freeze.ts",
|
||||
"exports": ["freezeUrl", "freezeLocalFile"],
|
||||
},
|
||||
// mediaDir, typeDirPath, isFigmaManifestRecord: re-exported from the figma
|
||||
// barrel (index.ts) via manifest.ts per Task 8 wiring. Consumed only by the
|
||||
// /figma skill integration, not by code in the current codebase.
|
||||
{
|
||||
"file": "packages/core/src/figma/manifest.ts",
|
||||
"exports": ["mediaDir", "typeDirPath", "isFigmaManifestRecord"],
|
||||
},
|
||||
],
|
||||
"ignoreDependencies": [
|
||||
// Runtime/dynamic deps not visible to static analysis: tsup `external`,
|
||||
// dynamic require() resolution, peer/static-file consumption in tests,
|
||||
// and bun-hoisted workspace devDeps (e.g. happy-dom in root package.json
|
||||
// resolves for every workspace, so workspaces don't redeclare it).
|
||||
// Required by @puppeteer/browsers and puppeteer-core at runtime; listed
|
||||
// as a direct dep to guarantee installation even when transitive
|
||||
// resolution fails (corrupted cache, dedup edge cases).
|
||||
"debug",
|
||||
"puppeteer",
|
||||
"puppeteer-core",
|
||||
"esbuild",
|
||||
"giget",
|
||||
"gsap",
|
||||
"happy-dom",
|
||||
"ffmpeg-static",
|
||||
"ffprobe-static",
|
||||
"@hyperframes/core",
|
||||
"@hyperframes/studio",
|
||||
"@hyperframes/producer",
|
||||
"@fontsource/archivo-black",
|
||||
"@fontsource/eb-garamond",
|
||||
"@fontsource/ibm-plex-mono",
|
||||
"@fontsource/inter",
|
||||
"@fontsource/jetbrains-mono",
|
||||
"@fontsource/league-gothic",
|
||||
"@fontsource/montserrat",
|
||||
"@fontsource/nunito",
|
||||
"@fontsource/oswald",
|
||||
"@fontsource/outfit",
|
||||
"@fontsource/space-mono",
|
||||
"@fontsource/lato",
|
||||
"@fontsource/noto-sans-jp",
|
||||
"@fontsource/open-sans",
|
||||
"@fontsource/playfair-display",
|
||||
"@fontsource/poppins",
|
||||
"@fontsource/roboto",
|
||||
"@fontsource/source-code-pro",
|
||||
],
|
||||
"duplicates": {
|
||||
// Raise from the default 5 to 6 lines so trivially short Hono route-handler
|
||||
// preambles (resolveProject + 404 + body-parse) are below the threshold.
|
||||
// The three 5-line groups in files.ts / render.ts are structural boilerplate
|
||||
// that naturally converges and is unlikely to diverge; extraction would
|
||||
// require intrusive middleware changes beyond this PR's scope.
|
||||
"minLines": 6,
|
||||
"ignore": [
|
||||
// sourcePatcher.ts: pre-existing internal clones between the inline-style
|
||||
// and attribute tag-patchers; only the PatchOperation type gained two
|
||||
// optional fields here, but the line shift makes fallow re-flag them.
|
||||
"packages/studio/src/utils/sourcePatcher.ts",
|
||||
// gsapParser.ts: recast/babel GSAP writer — intentional duplication between
|
||||
// recast and acorn parallel implementations (pre-existing, moved from core).
|
||||
"packages/parsers/src/gsapParser.ts",
|
||||
// hfIds.ts: 7-line clone with sdk/engine/mutate.ts — pre-existing duplication
|
||||
// from when hfIds lived in packages/core/src/parsers/. Moving the file to the
|
||||
// new package makes fallow see it as a fresh finding; the underlying clone
|
||||
// predates this refactor.
|
||||
"packages/parsers/src/hfIds.ts",
|
||||
// Parser test files: parallel arrange/act/assert test cases — pre-existing
|
||||
// duplication moved from packages/core/src/parsers/.
|
||||
"packages/parsers/src/gsapParser.test.ts",
|
||||
"packages/parsers/src/gsapParser.test-helpers.ts",
|
||||
"packages/parsers/src/gsapWriter.parity.test.ts",
|
||||
"packages/parsers/src/gsapWriterParity.corpus.test.ts",
|
||||
"packages/parsers/src/gsapWriterParity.acorn.test.ts",
|
||||
"packages/parsers/src/htmlParser.roundtrip.test.ts",
|
||||
"packages/parsers/src/htmlParser.test.ts",
|
||||
// @hyperframes/studio-server test files: parallel arrange/act/assert test cases
|
||||
// (pre-existing structure from when studio-api lived in packages/core/src/studio-api/).
|
||||
"packages/studio-server/src/routes/files.test.ts",
|
||||
"packages/studio-server/src/routes/render.test.ts",
|
||||
"packages/studio-server/src/routes/lint.test.ts",
|
||||
"packages/studio-server/src/routes/preview.test.ts",
|
||||
"packages/studio-server/src/routes/projects.test.ts",
|
||||
"packages/studio-server/src/helpers/backupJournal.test.ts",
|
||||
"packages/studio-server/src/helpers/finiteMutation.test.ts",
|
||||
"packages/studio-server/src/helpers/hfIdPersist.test.ts",
|
||||
"packages/studio-server/src/helpers/manualEditsRenderScript.test.ts",
|
||||
"packages/studio-server/src/helpers/mediaValidation.test.ts",
|
||||
"packages/studio-server/src/helpers/previewAdapter.test.ts",
|
||||
"packages/studio-server/src/helpers/safePath.test.ts",
|
||||
"packages/studio-server/src/helpers/sourceMutation.test.ts",
|
||||
"packages/studio-server/src/helpers/studioMotionRenderScript.test.ts",
|
||||
"packages/studio-server/src/helpers/subComposition.test.ts",
|
||||
// @hyperframes/lint rule test files: parallel arrange/act/assert test cases
|
||||
// (pre-existing structure from when lint lived in packages/core/src/lint/).
|
||||
"packages/lint/src/rules/adapters.test.ts",
|
||||
"packages/lint/src/rules/captions.test.ts",
|
||||
"packages/lint/src/rules/composition.test.ts",
|
||||
"packages/lint/src/rules/core.test.ts",
|
||||
"packages/lint/src/rules/fonts.test.ts",
|
||||
"packages/lint/src/rules/gsap.test.ts",
|
||||
"packages/lint/src/rules/media.test.ts",
|
||||
"packages/lint/src/rules/slideshow.test.ts",
|
||||
"packages/lint/src/rules/textures.test.ts",
|
||||
"packages/lint/src/hyperframeLinter.test.ts",
|
||||
// slideshowPanelHelpers.ts: setSlideNotes/addFragment/addHotspot share an
|
||||
// intentional parallel shape (signature + mapSlidesIn → exists-check →
|
||||
// map/append); the per-slide mutation differs, so a shared abstraction
|
||||
// would obscure more than it dedupes.
|
||||
"packages/studio/src/components/panels/slideshowPanelHelpers.ts",
|
||||
// SlideshowPanel.test.ts: parallel arrange/act/assert test cases — collapsing
|
||||
// them would hurt readability of what each case verifies.
|
||||
"packages/studio/src/components/panels/SlideshowPanel.test.ts",
|
||||
// hyperframes-player.test.ts: parallel arrange/act/assert test cases verifying
|
||||
// distinct behaviors (same-origin vs realm media, audio-locked permutations,
|
||||
// seek bridge variants). Each case is self-contained for readability;
|
||||
// extracting the iframe / mock-audio setup helpers would over-couple
|
||||
// unrelated scenarios under a shared fixture.
|
||||
"packages/player/src/hyperframes-player.test.ts",
|
||||
// present.ts mirrors play.ts's server startup + console-output block. The
|
||||
// shared low-level pieces (resolve*/injectRuntime/listenOnFreePort) are in
|
||||
// utils/compositionServer.ts; the remaining clone is per-command logging text
|
||||
// (different labels/help lines) — extracting it would over-abstract.
|
||||
"packages/cli/src/commands/present.ts",
|
||||
// skillsManifest.test.ts: parallel arrange/act/assert cases for locateInstall
|
||||
// (project vs global scope, per-agent host conventions, claude-code priority).
|
||||
// Each case seeds a dir then asserts the resolved location/agent; collapsing
|
||||
// the shared seed/assert shape would obscure what each scope/host verifies.
|
||||
"packages/cli/src/utils/skillsManifest.test.ts",
|
||||
// skills.test.ts: parallel prune cases (removed-in-global vs project, non-slug
|
||||
// rejection, --source/--dir plumbing) share a mock-checkSkills → runSkillsUpdate
|
||||
// → assert-remove-spawn shape; each verifies a distinct prune behavior, so
|
||||
// extracting the shared scaffold would obscure what each case asserts.
|
||||
"packages/cli/src/commands/skills.test.ts",
|
||||
// figma test files: freeze.test.ts and manifest.test.ts share a common
|
||||
// arrange/act/assert setup preamble (file creation + test dir handling) that
|
||||
// is minimal boilerplate; collapsing it into a shared fixture would reduce
|
||||
// readability of each test's independent setup.
|
||||
"packages/core/src/figma/freeze.test.ts",
|
||||
"packages/core/src/figma/manifest.test.ts",
|
||||
// layout-audit.browser.test.ts: parallel arrange/act/assert cases per audit
|
||||
// rule (overflow / overlap / occlusion) that each install their own mocked
|
||||
// geometry + computed-style before asserting. The clone groups are this
|
||||
// pre-existing per-rule scaffold; adding a clip-path case shifts lines and
|
||||
// re-flags it. Collapsing the per-rule installers would obscure each case.
|
||||
"packages/cli/src/commands/layout-audit.browser.test.ts",
|
||||
// gsapParserAcorn.motionEval.test.ts: parallel arrange/act/assert cases for
|
||||
// the staggered-collection honesty pass (.from reveal vs .to landing on the
|
||||
// rest pose). Each asserts a distinct keyframe shape; collapsing the shared
|
||||
// parse/keyframes-extraction scaffold would obscure what each case verifies.
|
||||
"packages/core/src/parsers/gsapParserAcorn.motionEval.test.ts",
|
||||
// Studio UX-review sweep (148 findings fixed across ~90 studio files):
|
||||
// heavily-edited files re-flag line-shifted inherited complexity, and the
|
||||
// new small handlers (a11y keydown/menu/dialog/error-state paths, mostly
|
||||
// 5-6 cyclomatic) trip the CRAP threshold absent coverage data. Reviewed
|
||||
// individually in the studio-ux PR stack rather than refactored here.
|
||||
"packages/studio/src/player/components/TimelineClipDiamonds.test.tsx",
|
||||
"packages/studio/src/hooks/useFileManager.ts",
|
||||
"packages/studio/src/captions/hooks/useCaptionSync.ts",
|
||||
"packages/studio/vite.adapter.ts",
|
||||
"packages/studio/src/components/sidebar/AudioRow.tsx",
|
||||
"packages/studio/src/components/sidebar/AssetsTab.tsx",
|
||||
"packages/studio/src/components/editor/propertyPanelFill.tsx",
|
||||
"packages/studio/src/captions/store.ts",
|
||||
"packages/studio/src/captions/components/CaptionOverlay.tsx",
|
||||
"packages/cli/src/server/studioServer.ts",
|
||||
// Sub-composition html/body scoping fix: inlineSubCompositions.ts has a
|
||||
// pre-existing head-vs-content script-extraction clone, and the scoping
|
||||
// test file has pre-existing parallel arrange/act/assert cases. Adding the
|
||||
// scopeRootSelectors handling shifts lines and re-flags both.
|
||||
"packages/core/src/compiler/inlineSubCompositions.ts",
|
||||
"packages/core/src/compiler/compositionScoping.test.ts",
|
||||
],
|
||||
},
|
||||
"health": {
|
||||
// useGsapTweenCache.ts: pre-existing large React-effect hooks (the populate
|
||||
// and runtime-scan effects, the per-element animations memo) whose
|
||||
// complexity pre-dates the computed-timeline work. Exempted at file level
|
||||
// rather than refactored as scope creep.
|
||||
"ignore": [
|
||||
// TEMP(studio-dnd): coexistence-window complexity flare (inherited/CRAP-no-coverage);
|
||||
// removed by studio-dnd/pr22 when the final config lands.
|
||||
"packages/studio/src/player/hooks/useTimelineSyncCallbacks.ts",
|
||||
"packages/studio/src/components/editor/CanvasContextMenu.tsx",
|
||||
"packages/studio/src/components/editor/canvasContextMenuZOrder.test.ts",
|
||||
"packages/studio/src/player/components/timelineCollision.test.ts",
|
||||
"packages/studio/src/player/components/timelineStackingSync.test.ts",
|
||||
// sourcePatcher.ts: resolveSourceFile / splitInlineStyleDeclarations /
|
||||
// patch*InTag pre-date this PR; only the PatchOperation type gained two
|
||||
// optional fields, but the line-shift fingerprint re-flags the inherited
|
||||
// complexity.
|
||||
"packages/studio/src/utils/sourcePatcher.ts",
|
||||
// timeline.ts: collectRuntimeTimelinePayload (CRITICAL) pre-dates this PR;
|
||||
// only an import line changed here (slideshow/sceneId → slideshow/index),
|
||||
// but the line-shift fingerprint makes fallow re-flag inherited complexity.
|
||||
"packages/core/src/runtime/timeline.ts",
|
||||
// sceneId.ts: trivial 5-cyclomatic guard, moved verbatim from
|
||||
// packages/core/src/slideshow/ into parsers; flagged only because the move
|
||||
// makes fallow treat it as a fresh finding.
|
||||
"packages/parsers/src/slideshow/sceneId.ts",
|
||||
// assetPaths.ts / rewriteSubCompPaths.ts: pure URL/asset-path helpers moved
|
||||
// verbatim from packages/core/src/compiler/ into parsers. The move makes
|
||||
// fallow score them as fresh (high CRAP = inherited complexity with no
|
||||
// coverage mapping yet); the logic is unchanged.
|
||||
"packages/parsers/src/assetPaths.ts",
|
||||
"packages/parsers/src/rewriteSubCompPaths.ts",
|
||||
// gsapParser.ts: the recast/babel GSAP writer is a 2500-line legacy parser;
|
||||
// moved from packages/core/src/parsers/ — same complexity rationale.
|
||||
"packages/parsers/src/gsapParser.ts",
|
||||
// htmlParser.ts has pre-existing complexity (moved from packages/core).
|
||||
"packages/parsers/src/htmlParser.ts",
|
||||
// studio-server files: pre-existing complexity (moved from packages/core/src/studio-api/).
|
||||
// files.ts: executeGsapMutationRecast/Acorn are CRITICAL; excluded as files.ts
|
||||
// was already in health.ignore at the old path (packages/core/src/studio-api/routes/files.ts).
|
||||
"packages/studio-server/src/routes/files.ts",
|
||||
"packages/studio-server/src/routes/render.ts",
|
||||
"packages/studio-server/src/routes/thumbnail.ts",
|
||||
"packages/studio-server/src/helpers/manualEditsRenderScript.ts",
|
||||
"packages/studio-server/src/helpers/studioMotionRenderScript.ts",
|
||||
"packages/studio-server/src/helpers/subComposition.ts",
|
||||
// lint rule implementations and project linter: pre-existing complexity
|
||||
// (moved from packages/core/src/lint/). File-level exemption avoids the
|
||||
// line-shift fingerprint problem for inherited findings.
|
||||
"packages/lint/src/rules/media.ts",
|
||||
"packages/lint/src/rules/textures.ts",
|
||||
"packages/lint/src/rules/gsap.ts",
|
||||
"packages/lint/src/project.ts",
|
||||
// SlideshowPanel.tsx: top-level editor panel that wires several independent
|
||||
// sections (slides/inspector/branches/hotspot). Its cyclomatic count comes
|
||||
// from that fan-out; splitting it would scatter shared state without
|
||||
// reducing real complexity. File-level exemption (not an inline comment)
|
||||
// avoids the line-shift fingerprint problem noted above.
|
||||
"packages/studio/src/components/panels/SlideshowPanel.tsx",
|
||||
// play.ts / present.ts: CLI command entrypoints whose cyclomatic count is
|
||||
// browser/arg validation + server wiring (same shape as preview.ts). The
|
||||
// serving logic is factored into utils/compositionServer.ts; the remaining
|
||||
// body is linear validation that reads clearly inline.
|
||||
"packages/cli/src/commands/play.ts",
|
||||
"packages/cli/src/commands/present.ts",
|
||||
// sync-agent-dirs.ts: a build-time codegen that regex-parses upstream
|
||||
// agents.ts. parseAgents/resolveGlobalExpr are branchy by nature (literal
|
||||
// vs base-var args, validation throws) but small and well-tested via the
|
||||
// generated table's shape test; this is dev tooling, not shipped runtime.
|
||||
"packages/cli/scripts/sync-agent-dirs.ts",
|
||||
// Files modified only for import-path updates (one-line changes to switch
|
||||
// from @hyperframes/core/* subpaths to the new packages). Their complexity
|
||||
// is pre-existing; the line-shift fingerprint problem makes fallow treat
|
||||
// the violations as new even though no logic changed.
|
||||
"packages/cli/src/server/studioServer.ts",
|
||||
"packages/core/src/core.types.ts",
|
||||
"packages/core/src/generators/hyperframes.ts",
|
||||
"packages/producer/src/services/htmlCompiler.ts",
|
||||
"packages/studio/src/hooks/gsapRuntimeBridge.ts",
|
||||
"packages/studio/src/hooks/gsapShared.ts",
|
||||
"packages/studio/src/hooks/gsapDragPositionCommit.ts",
|
||||
"packages/studio/src/hooks/gsapKeyframeCacheHelpers.ts",
|
||||
"packages/studio/vite.config.ts",
|
||||
"packages/cli/src/commands/lint.ts",
|
||||
"packages/cli/src/commands/preview.ts",
|
||||
"packages/cli/src/commands/publish.ts",
|
||||
"packages/cli/src/server/studioServer.ts",
|
||||
// set-version.ts: compareSemver helper has pre-existing complexity from
|
||||
// semver string parsing logic; line-shift fingerprint problem from new
|
||||
// packages added to PACKAGES array makes fallow treat it as new.
|
||||
"scripts/set-version.ts",
|
||||
// gsapRuntimeReaders.ts: pre-existing complexity in readAllAnimatedProperties;
|
||||
// line-shift fingerprint from import-path updates triggers the violation.
|
||||
"packages/studio/src/hooks/gsapRuntimeReaders.ts",
|
||||
// In-page audit scripts: single large browser-side IIFE wrappers
|
||||
// (auditLayout/__contrastAudit) with pre-existing CRITICAL helpers
|
||||
// (textOverflowFixHint, selectorFor, the WCAG walk). Adding the small
|
||||
// clip-path probe helpers shifts every function below it, so the line-shift
|
||||
// fingerprint re-flags inherited complexity even though the new helpers are
|
||||
// all at the lowest tier (<=5 cyclomatic).
|
||||
"packages/cli/src/commands/layout-audit.browser.js",
|
||||
"packages/cli/src/commands/contrast-audit.browser.js",
|
||||
// lottie.ts: the flagged `seek` handler (lottie-web/dotLottie dual-API
|
||||
// dispatch, unchanged by the duration-auto-inference work in this PR)
|
||||
// pre-dates this PR's scope. New functions added earlier in the file
|
||||
// (getInferredDurationSeconds + helpers) shifted its line numbers,
|
||||
// breaking fallow's inherited-detection fingerprint. File-level
|
||||
// exemption avoids the line-shift problem for this inherited finding.
|
||||
"packages/core/src/runtime/adapters/lottie.ts",
|
||||
// info.ts: the flagged `run` command handler pre-dates the keyframes-cli
|
||||
// PR; that PR only added the orientation()/durationFromHtml() helpers and
|
||||
// swapped a few `maxEnd` reads for the new `duration` variable, without
|
||||
// adding branches. The line-shift fingerprint re-flags the inherited
|
||||
// complexity even though the logic is unchanged.
|
||||
"packages/cli/src/commands/info.ts",
|
||||
// gsapParserAcorn.ts: the flagged `sameMemberAccess` (structural equality
|
||||
// of two member-access nodes) pre-dates this PR's motion-eval work
|
||||
// (added in #1760, unchanged since). The new const-folding / set-seeding /
|
||||
// label-position code added earlier in the file shifted its line number,
|
||||
// so the line-shift fingerprint re-flags this inherited finding.
|
||||
"packages/parsers/src/gsapParserAcorn.ts",
|
||||
// isFigmaManifestRecord: type guard with 19 cyclomatic due to chained
|
||||
// field validation (id/type/path/source types + value shape guards).
|
||||
// This is the correct shape for a discriminating type guard; refactoring
|
||||
// into smaller guards would obscure the unified validation contract.
|
||||
"packages/core/src/figma/manifest.ts",
|
||||
// Studio UX-review sweep (148 findings fixed across ~90 studio files):
|
||||
// heavily-edited files re-flag line-shifted inherited complexity, and the
|
||||
// new small handlers (a11y keydown/menu/dialog/error-state paths, mostly
|
||||
// 5-6 cyclomatic) trip the CRAP threshold absent coverage data. Reviewed
|
||||
// individually in the studio-ux PR stack rather than refactored here.
|
||||
"packages/studio/src/App.tsx",
|
||||
"packages/studio/src/captions/components/CaptionAnimationPanel.tsx",
|
||||
"packages/studio/src/captions/components/CaptionOverlay.tsx",
|
||||
"packages/studio/src/captions/components/CaptionOverlayUtils.ts",
|
||||
"packages/studio/src/captions/components/CaptionPropertyPanel.tsx",
|
||||
"packages/studio/src/captions/components/shared.tsx",
|
||||
"packages/studio/src/captions/hooks/useCaptionSync.ts",
|
||||
"packages/studio/src/components/AskAgentModal.tsx",
|
||||
"packages/studio/src/components/editor/BlockParamsPanel.tsx",
|
||||
"packages/studio/src/components/editor/DomEditOverlay.tsx",
|
||||
"packages/studio/src/components/editor/FileTree.tsx",
|
||||
"packages/studio/src/components/editor/FileTreeNodes.tsx",
|
||||
"packages/studio/src/components/editor/LayersPanel.tsx",
|
||||
"packages/studio/src/components/editor/MotionPathNode.tsx",
|
||||
"packages/studio/src/components/editor/PropertyPanel.tsx",
|
||||
"packages/studio/src/components/editor/propertyPanelFont.tsx",
|
||||
"packages/studio/src/components/editor/propertyPanelMediaSection.tsx",
|
||||
"packages/studio/src/components/editor/propertyPanelStyleSections.tsx",
|
||||
"packages/studio/src/components/editor/Transform3DCube.tsx",
|
||||
"packages/studio/src/components/LintModal.tsx",
|
||||
"packages/studio/src/components/MediaPreview.tsx",
|
||||
"packages/studio/src/components/nle/NLELayout.tsx",
|
||||
"packages/studio/src/components/nle/NLEPreview.tsx",
|
||||
"packages/studio/src/components/sidebar/AudioRow.tsx",
|
||||
"packages/studio/src/components/sidebar/BlocksTab.tsx",
|
||||
"packages/studio/src/components/sidebar/CompositionsTab.tsx",
|
||||
"packages/studio/src/components/sidebar/LeftSidebar.tsx",
|
||||
"packages/studio/src/components/storyboard/StoryboardLoaded.tsx",
|
||||
"packages/studio/src/components/StudioPreviewArea.tsx",
|
||||
"packages/studio/src/components/StudioRightPanel.tsx",
|
||||
"packages/studio/src/components/StudioToast.tsx",
|
||||
"packages/studio/src/components/ui/Tooltip.tsx",
|
||||
"packages/studio/src/components/ui/useDialogBehavior.ts",
|
||||
"packages/studio/src/hooks/useAppHotkeys.ts",
|
||||
"packages/studio/src/hooks/useCaptionDetection.ts",
|
||||
"packages/studio/src/hooks/useFileManager.ts",
|
||||
"packages/studio/src/hooks/useFrameCapture.ts",
|
||||
"packages/studio/src/hooks/usePanelLayout.ts",
|
||||
"packages/studio/src/player/components/menuKeyboardNav.ts",
|
||||
"packages/studio/src/player/components/Timeline.tsx",
|
||||
"packages/studio/src/player/components/TimelineCanvas.tsx",
|
||||
"packages/studio/src/player/components/TimelineClip.tsx",
|
||||
"packages/studio/src/player/components/TimelineClipDiamonds.tsx",
|
||||
// Sub-composition html/body scoping fix: these files carry pre-existing
|
||||
// CRITICAL/HIGH functions (inlineSubCompositions, bundleToSingleHtml,
|
||||
// mountCompositionContent/loadExternalCompositions, scopeSelector/
|
||||
// replaceAuthoredRootIdSelectors) that pre-date this PR. The change only
|
||||
// threads a scopeRootSelectors option through the existing scoping calls;
|
||||
// the line-shift fingerprint re-flags the inherited complexity.
|
||||
"packages/core/src/compiler/compositionScoping.ts",
|
||||
"packages/core/src/compiler/inlineSubCompositions.ts",
|
||||
"packages/core/src/compiler/htmlBundler.ts",
|
||||
"packages/core/src/runtime/compositionLoader.ts",
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
# Normalize text files to LF on checkout and in the repo, regardless of the
|
||||
# contributor's OS. Without this, files saved on Windows can land in PRs with
|
||||
# CRLF endings or a UTF-8 BOM, which makes every line differ at the byte level
|
||||
# and trips GitHub's "Binary file not shown" diff heuristic.
|
||||
* text=auto eol=lf
|
||||
|
||||
# Regression-test media under packages/producer/tests — RECURSIVE (`**`) so
|
||||
# media in ANY nested fixture dir routes to LFS. The earlier non-recursive
|
||||
# patterns (`tests/*/output/...`, `tests/*/src/...`) only matched one level
|
||||
# deep, so binaries in nested dirs like `tests/hdr-regression/hdr-pq/assets/*.mp4`
|
||||
# and `.../_renders/*.mp4` committed straight into the git pack and now live in
|
||||
# history forever. `**` closes that leak: any video/baseline anywhere under
|
||||
# tests/ is LFS, regardless of how deeply it is nested.
|
||||
packages/producer/tests/**/*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
packages/producer/tests/**/*.mov filter=lfs diff=lfs merge=lfs -text
|
||||
packages/producer/tests/**/*.webm filter=lfs diff=lfs merge=lfs -text
|
||||
packages/producer/tests/**/*.png filter=lfs diff=lfs merge=lfs -text
|
||||
packages/producer/tests/**/output/compiled.html filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# ONNX models must ALWAYS use LFS regardless of location: a 31 MB ppmattingv2
|
||||
# model was once committed raw into skills/ then deleted — but a raw commit
|
||||
# lives in history forever. No path in the repo legitimately ships a raw .onnx.
|
||||
# (Audio masters / .wav are intentionally NOT globalized here — registry blocks
|
||||
# ship raw audio so they stay portable when installed via `hyperframes add`.
|
||||
# The wav-in-LFS question is a coordinated policy decision left for later.)
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
# GitHub Linguist overrides — HTML files are compositions (user content / templates),
|
||||
# not the framework source. Hide them from the repo language stats so TypeScript,
|
||||
# which is the actual implementation, surfaces as the dominant language.
|
||||
registry/**/*.html linguist-vendored
|
||||
*.html linguist-detectable=false
|
||||
@@ -0,0 +1,81 @@
|
||||
name: Bug Report
|
||||
description: Report a bug to help us improve
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to report a bug! Before filing, please:
|
||||
- Search [existing issues](https://github.com/heygen-com/hyperframes/issues) to avoid duplicates
|
||||
- Make sure the issue reproduces without custom extensions or plugins
|
||||
- Test on the latest version (`npx hyperframes upgrade`)
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: reproduction-link
|
||||
attributes:
|
||||
label: Link to reproduction
|
||||
description: |
|
||||
A link to a **public** GitHub repository with a minimal reproduction of the issue.
|
||||
|
||||
Start from a clean project with `npx hyperframes init repro --non-interactive --example blank`, make only the changes needed to demonstrate the bug, push to a public repo, and paste the link here.
|
||||
|
||||
**Issues without a minimal reproduction may be closed.** A reproduction helps us diagnose and fix your issue faster — often in hours instead of days.
|
||||
placeholder: "https://github.com/username/my-hyperframes-repro"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Step-by-step instructions using the linked reproduction.
|
||||
placeholder: |
|
||||
1. Clone the repo above
|
||||
2. Run `npx hyperframes render`
|
||||
3. See error...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: What you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: actual
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: What actually happened. Include error messages or screenshots if applicable.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment
|
||||
description: Run `npx hyperframes doctor` and paste the output here.
|
||||
render: shell
|
||||
placeholder: |
|
||||
✓ Version 0.x.x (latest)
|
||||
✓ Node.js v22.x.x (darwin arm64)
|
||||
✓ FFmpeg ffmpeg version 7.x ...
|
||||
✓ Chrome bundled: /path/to/chrome
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Any other context, logs, or screenshots.
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for Hyperframes
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for suggesting an improvement! Please search [existing issues](https://github.com/heygen-com/hyperframes/issues) first to avoid duplicates.
|
||||
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: Problem
|
||||
description: What problem does this solve? What's the use case?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
description: How should it work? Include code examples or mockups if helpful.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives considered
|
||||
description: Any alternative approaches you've thought about.
|
||||
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Any other context, mockups, or examples.
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Install FFmpeg (Windows)
|
||||
description: >-
|
||||
Download a pinned FFmpeg GPL build for Windows from BtbN/FFmpeg-Builds and put
|
||||
ffmpeg.exe / ffprobe.exe on PATH. We bypass `choco install ffmpeg` because
|
||||
the Chocolatey community feed regularly returns 503 / 504 / NuGet resolver
|
||||
errors with no retry, which makes it unsuitable as a CI dependency. From the
|
||||
consumer's perspective this is equivalent — `where ffmpeg` (the PR #336
|
||||
validation) and `findFFmpeg()` both pass.
|
||||
|
||||
inputs:
|
||||
release-url:
|
||||
description: >-
|
||||
URL of a BtbN/FFmpeg-Builds zip to install. Pinned to a specific
|
||||
autobuild tag so a new upstream nightly can't silently change encoder
|
||||
behavior under us. The asset filename embeds the git hash, so both
|
||||
the tag and the filename must be bumped together when upgrading.
|
||||
required: false
|
||||
default: https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-04-30-13-44/ffmpeg-N-124278-gcc3ca17127-win64-gpl.zip
|
||||
max-attempts:
|
||||
description: Max download attempts before failing.
|
||||
required: false
|
||||
default: "8"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install FFmpeg from BtbN/FFmpeg-Builds
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$url = '${{ inputs.release-url }}'
|
||||
$maxAttempts = [int]'${{ inputs.max-attempts }}'
|
||||
|
||||
$zip = Join-Path $env:RUNNER_TEMP 'ffmpeg.zip'
|
||||
$dir = Join-Path $env:RUNNER_TEMP 'ffmpeg'
|
||||
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
||||
|
||||
for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
|
||||
Write-Host "--- Downloading ffmpeg from BtbN/FFmpeg-Builds (attempt $attempt/$maxAttempts) ---"
|
||||
try {
|
||||
Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing
|
||||
break
|
||||
} catch {
|
||||
Write-Warning "Download failed: $($_.Exception.Message)"
|
||||
if ($attempt -eq $maxAttempts) { throw }
|
||||
Start-Sleep -Seconds (30 * $attempt)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "--- Extracting ffmpeg ---"
|
||||
Expand-Archive -Path $zip -DestinationPath $dir -Force
|
||||
|
||||
$bin = Get-ChildItem -Path $dir -Recurse -Filter 'ffmpeg.exe' | Select-Object -First 1
|
||||
if (-not $bin) { throw "ffmpeg.exe not found after extracting $url" }
|
||||
|
||||
Add-Content -Path $env:GITHUB_PATH -Value $bin.Directory.FullName
|
||||
|
||||
Write-Host "--- ffmpeg sanity check ---"
|
||||
& $bin.FullName -version | Select-Object -First 1
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Preflight
|
||||
description: |
|
||||
Cheap lint + format gate that runs before expensive CI jobs (regression
|
||||
shards, perf shards, parity renders, Windows renders, catalog previews).
|
||||
Single source of truth for the gate's bun/node/cache/lint/format steps —
|
||||
tweak here and every preflight job picks it up.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4
|
||||
with:
|
||||
path: ~/.bun/install/cache
|
||||
key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }}
|
||||
restore-keys: |
|
||||
bun-${{ runner.os }}-
|
||||
|
||||
- shell: bash
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- shell: bash
|
||||
run: bun run lint
|
||||
|
||||
- shell: bash
|
||||
run: bun run format:check
|
||||
@@ -0,0 +1,28 @@
|
||||
name: Prepare FFMPEG_BIN for bun install
|
||||
description: >-
|
||||
Copies the system ffmpeg binary to a writable temp location and sets
|
||||
FFMPEG_BIN in the environment. ffmpeg-static's postinstall script checks
|
||||
whether a file already exists at FFMPEG_BIN; if it does and process.exit(0)
|
||||
is respected by the runtime, the CDN download is skipped entirely. If the
|
||||
runtime intercepts process.exit(0) and the download proceeds anyway, using
|
||||
a writable target prevents the EACCES failure that occurs when the
|
||||
destination is a system path like /usr/bin/ffmpeg.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Copy ffmpeg to writable path
|
||||
shell: bash
|
||||
run: |
|
||||
FFMPEG=$(which ffmpeg 2>/dev/null || echo "")
|
||||
if [ -n "$FFMPEG" ]; then
|
||||
cp "$FFMPEG" "$RUNNER_TEMP/hf-ffmpeg"
|
||||
else
|
||||
# ffmpeg not pre-installed; write a stub so ffmpeg-static's postinstall
|
||||
# finds a file at FFMPEG_BIN and exits early (statSync check) without
|
||||
# attempting the CDN download. Jobs that need a real ffmpeg binary
|
||||
# install it via apt before calling this action.
|
||||
printf '#!/bin/sh\nexec ffmpeg "$@"\n' > "$RUNNER_TEMP/hf-ffmpeg"
|
||||
fi
|
||||
chmod +x "$RUNNER_TEMP/hf-ffmpeg"
|
||||
echo "FFMPEG_BIN=$RUNNER_TEMP/hf-ffmpeg" >> "$GITHUB_ENV"
|
||||
@@ -0,0 +1,64 @@
|
||||
name: "Hyperframes CodeQL config"
|
||||
|
||||
# Use GitHub's default security-extended suite — it's a strict superset of the
|
||||
# default suite (more queries, slightly higher false-positive rate). Pair it with
|
||||
# the query-filters below so the extra queries don't drown the dashboard.
|
||||
queries:
|
||||
- uses: security-extended
|
||||
|
||||
# Per-rule path filters. The intent is to silence rules that have known false
|
||||
# positives on specific file shapes (generated test artifacts, CDN-script test
|
||||
# fixtures, functional-cleanup regex) WITHOUT excluding those paths from all
|
||||
# analysis — a malicious contributor adding e.g. a command-injection sink into
|
||||
# a "test fixture" would still get caught.
|
||||
#
|
||||
# To audit what changed: look at PR diffs touching this file. Reviewers should
|
||||
# treat it like CODEOWNERS — adding a new path exclusion is a policy change.
|
||||
query-filters:
|
||||
# Generated test artifacts (golden baselines written by the producer test
|
||||
# harness). Every compiled.html re-rasterizes the regex-stripped composition;
|
||||
# the same alerts fire on every fixture and on every re-render.
|
||||
- exclude:
|
||||
id: js/incomplete-sanitization
|
||||
paths:
|
||||
- "packages/producer/tests/**/output/compiled.html"
|
||||
- "packages/producer/tests/**/failures/*.html"
|
||||
|
||||
# Test fixtures and skill test corpora intentionally load CDN scripts without
|
||||
# SRI — pinning hashes there would fight the test's purpose (we want the test
|
||||
# to use whatever the registry hands back, the same way a composition would).
|
||||
- exclude:
|
||||
id: js/functionality-from-untrusted-source
|
||||
paths:
|
||||
- "packages/producer/tests/**"
|
||||
- "skills/**/test-corpus/**"
|
||||
- "skills/**/assets/test-corpus/**"
|
||||
|
||||
# The hand-rolled HTML cleanup regex in our build-time tooling looks like a
|
||||
# sanitizer to CodeQL but isn't one — it strips framework bootstraps from
|
||||
# captured pages before they're fed back into our own renderer (Puppeteer,
|
||||
# not a user-facing DOM). Same for the text normalizer in the whisper path
|
||||
# (caption text → SRT/VTT, no DOM emission). Scope these exclusions to the
|
||||
# exact files that contain functional regex, not to whole directories, so
|
||||
# any new code in cli/, core/, or producer/ that LOOKS like a sanitizer
|
||||
# still trips the rules.
|
||||
- exclude:
|
||||
id: js/bad-tag-filter
|
||||
paths:
|
||||
- "packages/cli/src/capture/index.ts"
|
||||
- "packages/cli/src/whisper/normalize.ts"
|
||||
- "packages/core/src/lint/utils.ts"
|
||||
- "packages/producer/src/services/htmlCompiler.ts"
|
||||
- exclude:
|
||||
id: js/incomplete-multi-character-sanitization
|
||||
paths:
|
||||
- "packages/cli/src/capture/index.ts"
|
||||
- "packages/cli/src/whisper/normalize.ts"
|
||||
|
||||
# Golden baselines inline vendor libraries (Three.js, GSAP) whose bundled
|
||||
# Math.random() calls trip insecure-randomness. These are test artifacts
|
||||
# from compiled compositions, not production code paths.
|
||||
- exclude:
|
||||
id: js/insecure-randomness
|
||||
paths:
|
||||
- "packages/producer/tests/**/output/compiled.html"
|
||||
@@ -0,0 +1,19 @@
|
||||
## What
|
||||
|
||||
Brief description of the change.
|
||||
|
||||
## Why
|
||||
|
||||
Why is this change needed?
|
||||
|
||||
## How
|
||||
|
||||
How was this implemented? Any notable design decisions?
|
||||
|
||||
## Test plan
|
||||
|
||||
How was this tested?
|
||||
|
||||
- [ ] Unit tests added/updated
|
||||
- [ ] Manual testing performed
|
||||
- [ ] Documentation updated (if applicable)
|
||||
@@ -0,0 +1,43 @@
|
||||
changelog:
|
||||
exclude:
|
||||
labels:
|
||||
- skip-changelog
|
||||
- dependencies
|
||||
authors:
|
||||
- dependabot
|
||||
- dependabot[bot]
|
||||
categories:
|
||||
- title: Breaking Changes
|
||||
labels:
|
||||
- breaking-change
|
||||
- breaking
|
||||
- title: Features
|
||||
labels:
|
||||
- enhancement
|
||||
- feature
|
||||
- title: Fixes
|
||||
labels:
|
||||
- bug
|
||||
- fix
|
||||
- title: Docs & Examples
|
||||
labels:
|
||||
- documentation
|
||||
- docs
|
||||
- examples
|
||||
- title: Catalog
|
||||
labels:
|
||||
- catalog
|
||||
- registry
|
||||
- title: Performance
|
||||
labels:
|
||||
- performance
|
||||
- perf
|
||||
- title: Internal
|
||||
labels:
|
||||
- internal
|
||||
- refactor
|
||||
- tests
|
||||
- ci
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- "*"
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended", ":semanticCommits", ":dependencyDashboard"],
|
||||
"schedule": ["before 6am on monday"],
|
||||
"timezone": "America/Los_Angeles",
|
||||
"prConcurrentLimit": 5,
|
||||
"prHourlyLimit": 2,
|
||||
"rangeStrategy": "bump",
|
||||
"lockFileMaintenance": {
|
||||
"enabled": true,
|
||||
"schedule": ["before 6am on monday"]
|
||||
},
|
||||
"vulnerabilityAlerts": {
|
||||
"enabled": true,
|
||||
"labels": ["security"]
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"matchDepTypes": ["devDependencies"],
|
||||
"groupName": "dev dependencies (non-major)"
|
||||
},
|
||||
{
|
||||
"matchUpdateTypes": ["patch"],
|
||||
"matchDepTypes": ["dependencies"],
|
||||
"groupName": "prod patch updates"
|
||||
},
|
||||
{
|
||||
"matchUpdateTypes": ["major"],
|
||||
"dependencyDashboardApproval": true
|
||||
},
|
||||
{
|
||||
"matchManagers": ["github-actions"],
|
||||
"groupName": "github-actions",
|
||||
"pinDigests": true
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"matchPackageNames": ["/^@hyperframes//"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Catalog Previews
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "registry/blocks/**"
|
||||
- "registry/components/**"
|
||||
- "scripts/generate-catalog-previews.ts"
|
||||
- ".github/workflows/catalog-previews.yml"
|
||||
|
||||
concurrency:
|
||||
group: catalog-previews-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
preflight:
|
||||
name: Preflight (lint + format)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: ./.github/actions/preflight
|
||||
|
||||
render-previews:
|
||||
name: Render catalog previews
|
||||
needs: preflight
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- run: bun install --frozen-lockfile
|
||||
|
||||
- run: bun run build
|
||||
|
||||
# Chrome headless shell for rendering
|
||||
- uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1
|
||||
with:
|
||||
chrome-version: stable
|
||||
|
||||
- name: Render changed block/component previews
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
run: |
|
||||
# Find which blocks/components changed in this PR
|
||||
CHANGED_ITEMS=$(git diff --name-only --diff-filter=ACMR "$BASE_SHA"...HEAD -- registry/blocks/ registry/components/ \
|
||||
| grep -E '^registry/(blocks|components)/' \
|
||||
| sed 's|^registry/[^/]*/\([^/]*\)/.*|\1|' \
|
||||
| sort -u)
|
||||
|
||||
if [ -z "$CHANGED_ITEMS" ]; then
|
||||
echo "No block/component changes detected."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Changed items: $CHANGED_ITEMS"
|
||||
FAILED=0
|
||||
|
||||
for item in $CHANGED_ITEMS; do
|
||||
echo "Rendering preview for: $item"
|
||||
if ! timeout 120 npx tsx scripts/generate-catalog-previews.ts --only "$item" --skip-video; then
|
||||
echo "::warning::Failed to render preview for $item"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$FAILED" -gt 0 ]; then
|
||||
echo "::warning::$FAILED item(s) failed to render"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload preview artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: catalog-previews
|
||||
path: docs/images/catalog/
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
@@ -0,0 +1,682 @@
|
||||
name: CI
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
# `edited` is required so the workflow re-fires when a PR's base ref is
|
||||
# set back to `main` after a Graphite stack restack momentarily flips
|
||||
# the base off of `main`. Without it, `pull_request` triggers are not
|
||||
# re-evaluated on `base_ref_changed`, leaving required checks skipped
|
||||
# for that head SHA forever.
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
outputs:
|
||||
code: ${{ steps.filter.outputs.code }}
|
||||
cli: ${{ steps.filter.outputs.cli }}
|
||||
skills: ${{ steps.filter.outputs.skills }}
|
||||
steps:
|
||||
# Force git-based change detection instead of the pull_request REST API.
|
||||
# The API path can fail the whole workflow on transient listFiles
|
||||
# timeouts before any real CI work starts.
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
token: ""
|
||||
filters: |
|
||||
code:
|
||||
- "packages/**"
|
||||
- "scripts/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
- "tsconfig*.json"
|
||||
- "Dockerfile*"
|
||||
- ".github/workflows/**"
|
||||
cli:
|
||||
- "packages/cli/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
- ".github/workflows/ci.yml"
|
||||
skills:
|
||||
- "skills/**"
|
||||
- "skills-manifest.json"
|
||||
- "package.json"
|
||||
- ".github/workflows/ci.yml"
|
||||
|
||||
build:
|
||||
name: Build
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: corepack enable
|
||||
- run: corepack prepare pnpm@10.17.1 --activate
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run build
|
||||
- run: bun run verify:packed-manifests
|
||||
|
||||
lint:
|
||||
name: Lint
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run lint
|
||||
|
||||
# `fallow audit` runs dead-code + complexity + duplication analysis scoped to
|
||||
# the changed files. The default `--gate new-only` means existing legacy
|
||||
# findings don't fail the build — only NEW issues introduced by the PR do.
|
||||
# This stops bleeding while letting incremental cleanup land separately.
|
||||
#
|
||||
# On findings, the job posts (or updates) a sticky comment on the PR so
|
||||
# reviewers see the full list inline instead of digging through CI logs.
|
||||
fallow:
|
||||
name: Fallow audit
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true' && github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
# Scope write access to this single job — the rest of `ci.yml` keeps the
|
||||
# workflow-level `pull-requests: read` default so build / lint / test
|
||||
# tokens can't post or modify PR comments. Job-level permissions override
|
||||
# the workflow block.
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
# Full history so `--base origin/main` can diff against the merge
|
||||
# base on stacked PRs, not just the shallow tip.
|
||||
fetch-depth: 0
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- name: Run fallow audit
|
||||
id: audit
|
||||
# `bun install` above made `bunx fallow` resolve from node_modules, so
|
||||
# we don't re-download fallow each run. The script disables `errexit`
|
||||
# so the audit's non-zero exit (on findings) doesn't abort before we
|
||||
# write the exit code to the step output. The size check guards
|
||||
# against fallow crashing before producing markdown (e.g. transient
|
||||
# parse failure) — without it we'd post a blank sticky comment.
|
||||
run: |
|
||||
set +e
|
||||
bunx fallow audit --base origin/main --fail-on-issues \
|
||||
--format pr-comment-github \
|
||||
> /tmp/fallow-comment.md
|
||||
echo "exit_code=$?" >> "$GITHUB_OUTPUT"
|
||||
if [ ! -s /tmp/fallow-comment.md ]; then
|
||||
echo "fallow produced no output — see the job logs above." > /tmp/fallow-comment.md
|
||||
fi
|
||||
- name: Post sticky comment (findings)
|
||||
if: steps.audit.outputs.exit_code != '0'
|
||||
# Fork PRs run with a read-only GITHUB_TOKEN regardless of the
|
||||
# workflow's `permissions:` block, so the comment post will fail on
|
||||
# forks. Don't fail the whole job — the audit gate below still fires.
|
||||
continue-on-error: true
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
||||
with:
|
||||
# `header` matches fallow's built-in `<!-- fallow-id: fallow-results -->`
|
||||
# sentinel so subsequent runs update the same comment.
|
||||
header: fallow-results
|
||||
path: /tmp/fallow-comment.md
|
||||
- name: Remove stale sticky comment (clean run)
|
||||
if: steps.audit.outputs.exit_code == '0'
|
||||
continue-on-error: true
|
||||
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
||||
with:
|
||||
header: fallow-results
|
||||
delete: true
|
||||
- name: Fail if audit found issues
|
||||
if: steps.audit.outputs.exit_code != '0'
|
||||
run: |
|
||||
echo "::error::Fallow audit found new issues — see the PR comment above for details."
|
||||
exit 1
|
||||
|
||||
format:
|
||||
name: Format
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run format:check
|
||||
|
||||
typecheck:
|
||||
name: Typecheck
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run build
|
||||
- run: bun run --filter '*' typecheck
|
||||
|
||||
test:
|
||||
name: Test
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run test:scripts
|
||||
- run: bun run --filter '@hyperframes/{parsers,lint,studio-server}' build
|
||||
- run: bun run --cwd packages/core build
|
||||
- run: bun run --cwd packages/core build:hyperframes-runtime
|
||||
- run: bun run --filter '!@hyperframes/producer' test
|
||||
|
||||
producer-source-tests:
|
||||
name: "Producer: ${{ matrix.lane }} tests"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lane: [unit, integration]
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install FFmpeg for integration tests
|
||||
if: matrix.lane == 'integration'
|
||||
run: |
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y --no-install-recommends ffmpeg
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run --filter '@hyperframes/{parsers,lint,studio-server}' build
|
||||
- run: bun run --cwd packages/core build
|
||||
- run: bun run --filter @hyperframes/engine build
|
||||
- run: bun run producer:test:${{ matrix.lane }}
|
||||
|
||||
# Tests under skills/**/*.test.mjs are bare `node --test` files with only
|
||||
# `node:` built-in imports. They aren't part of any workspace package, and
|
||||
# the main `Test` job's `code` path filter excludes `skills/**`, so without
|
||||
# this dedicated job they'd never run in CI. Examples:
|
||||
# * skills/media-use/scripts/resolve.test.mjs
|
||||
# * skills/media-use/scripts/lib/manifest.test.mjs
|
||||
# Several of these are regression guards (e.g. shell-injection cases), so
|
||||
# the whole point is that they fire on PRs that touch skills/.
|
||||
test-skills:
|
||||
name: "Test: skills"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.skills == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Discover and run skills tests
|
||||
# We expand the test list via bash so the job fails loudly when the
|
||||
# matcher comes back empty, rather than silently no-op'ing (which
|
||||
# would defeat the whole point of this job).
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mapfile -t SKILLS_TESTS < <(find skills -type f -name "*.test.mjs" | sort)
|
||||
if [ "${#SKILLS_TESTS[@]}" -eq 0 ]; then
|
||||
echo "::error::No skills/**/*.test.mjs files found. Did the layout change?"
|
||||
exit 1
|
||||
fi
|
||||
printf 'Running %d skills test file(s):\n' "${#SKILLS_TESTS[@]}"
|
||||
printf ' * %s\n' "${SKILLS_TESTS[@]}"
|
||||
node --test "${SKILLS_TESTS[@]}"
|
||||
|
||||
# Guards that skills-manifest.json (the published freshness fingerprint read
|
||||
# by `hyperframes skills check`) was regenerated when a skill changed. Runs
|
||||
# `gen:skills-manifest --check`, which compares per-skill content hashes; the
|
||||
# manifest carries no version/timestamp, so it only fails on real content
|
||||
# drift. bun runs the TS script directly, no install needed.
|
||||
skills-manifest:
|
||||
name: "Skills: manifest in sync"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.skills == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 3
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- name: Verify skills-manifest.json matches skills/
|
||||
run: bun packages/cli/scripts/gen-skills-manifest.ts --check
|
||||
|
||||
cli-npx-shim:
|
||||
name: "CLI: npx shim (${{ matrix.os }})"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.cli == 'true'
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install dependencies
|
||||
if: runner.os != 'Windows'
|
||||
run: bun install --frozen-lockfile --ignore-scripts
|
||||
- name: Install dependencies
|
||||
if: runner.os == 'Windows'
|
||||
run: bun install --frozen-lockfile --ignore-scripts --linker=hoisted
|
||||
- run: bun run --cwd packages/cli test src/utils/npxCommand.test.ts src/commands/skills.test.ts
|
||||
|
||||
sdk-tests:
|
||||
name: "SDK: unit + contract + smoke"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- run: bun install --frozen-lockfile
|
||||
# Build workspace deps so the sdk's @hyperframes/parsers + core subpath
|
||||
# imports resolve via the "node" export condition (dist) under vitest.
|
||||
- run: bun run --filter '@hyperframes/parsers' build
|
||||
- run: bun run --cwd packages/core build
|
||||
- run: bun run --filter @hyperframes/sdk test
|
||||
|
||||
test-runtime-contract:
|
||||
name: "Test: runtime contract"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
# Runtime coverage now imports core modules that consume workspace
|
||||
# subpaths. Build their dist exports before Vitest resolves them.
|
||||
- run: bun run --filter '@hyperframes/{parsers,lint,studio-server}' build
|
||||
- run: bun run --filter @hyperframes/core test:hyperframe-runtime-ci
|
||||
|
||||
studio-load-smoke:
|
||||
name: "Studio: load smoke"
|
||||
needs: [changes]
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
# Build workspace deps so the studio vite.config.ts (loaded by Node) can
|
||||
# resolve @hyperframes/core and @hyperframes/studio-server via the "node"
|
||||
# export condition (dist).
|
||||
- run: bun run --filter '@hyperframes/{parsers,lint,studio-server}' build
|
||||
- run: bun run --cwd packages/core build
|
||||
- run: bun run --cwd packages/core build:hyperframes-runtime
|
||||
- name: Start studio and check for runtime errors
|
||||
run: |
|
||||
# Start the studio Vite dev server (fast — no bundle step)
|
||||
bun run --filter '@hyperframes/studio' dev -- --port 5199 &
|
||||
SERVER_PID=$!
|
||||
|
||||
# Wait for the server to be ready (up to 20s)
|
||||
for i in $(seq 1 40); do
|
||||
if curl -sf http://localhost:5199/ >/dev/null 2>&1; then break; fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if ! curl -sf http://localhost:5199/ >/dev/null 2>&1; then
|
||||
echo "FAIL: studio dev server did not start"
|
||||
kill $SERVER_PID 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Load the studio in headless Chrome with API mocking to trigger
|
||||
# the full splash→main transition (catches hooks-after-early-return bugs)
|
||||
node scripts/studio-runtime-smoke.mjs http://localhost:5199/#project=smoke-test
|
||||
|
||||
kill $SERVER_PID 2>/dev/null || true
|
||||
|
||||
smoke-global-install:
|
||||
name: "Smoke: global install"
|
||||
needs: [changes, build]
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run build
|
||||
|
||||
# Pack the CLI as a tarball (simulates what `npm publish` produces)
|
||||
- name: Pack CLI tarball
|
||||
run: cd packages/cli && npm pack
|
||||
|
||||
# Install globally using --prefix to avoid sudo
|
||||
- name: Install globally via npm
|
||||
run: npm install -g --prefix /tmp/hf-smoke ./packages/cli/hyperframes-cli-*.tgz
|
||||
|
||||
# Scaffold a blank project
|
||||
- name: Init blank project
|
||||
run: |
|
||||
export PATH="/tmp/hf-smoke/bin:$PATH"
|
||||
mkdir /tmp/hf-project && cd /tmp/hf-project
|
||||
hyperframes init test-project --example blank
|
||||
|
||||
# Start preview, probe the runtime endpoint, assert no esbuild errors
|
||||
- name: Smoke-test preview server
|
||||
run: |
|
||||
export PATH="/tmp/hf-smoke/bin:$PATH"
|
||||
cd /tmp/hf-project/test-project
|
||||
|
||||
# Start the preview server in the background; capture stderr
|
||||
CI=true hyperframes preview --port 3099 2>/tmp/hf-stderr.log &
|
||||
SERVER_PID=$!
|
||||
|
||||
# Wait for the server to be ready (up to 15 s)
|
||||
for i in $(seq 1 30); do
|
||||
if curl -sf http://localhost:3099/ >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
# Probe the runtime JS endpoint
|
||||
BODY=$(curl -sf http://localhost:3099/api/runtime.js | head -c 200 || true)
|
||||
if [ -z "$BODY" ]; then
|
||||
echo "FAIL: /api/runtime.js returned empty response"
|
||||
kill $SERVER_PID 2>/dev/null || true
|
||||
cat /tmp/hf-stderr.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kill $SERVER_PID 2>/dev/null || true
|
||||
wait $SERVER_PID 2>/dev/null || true
|
||||
|
||||
# Assert stderr does not contain esbuild / runtime load errors
|
||||
if grep -qE '✘ \[ERROR\]|Failed to load runtime' /tmp/hf-stderr.log; then
|
||||
echo "FAIL: preview emitted runtime errors:"
|
||||
cat /tmp/hf-stderr.log
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "PASS: global install smoke test succeeded"
|
||||
|
||||
cli-smoke-required:
|
||||
name: "CLI smoke (required)"
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install FFmpeg
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ffmpeg
|
||||
- uses: ./.github/actions/prepare-ffmpeg-bin
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
- name: Build monorepo
|
||||
run: bun run build
|
||||
|
||||
- name: Create smoke input video
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ffmpeg -hide_banner -loglevel error \
|
||||
-f lavfi -i testsrc2=size=640x360:rate=30 \
|
||||
-f lavfi -i sine=frequency=880:sample_rate=48000 \
|
||||
-t 3 \
|
||||
-c:v libx264 \
|
||||
-pix_fmt yuv420p \
|
||||
-c:a aac \
|
||||
-shortest \
|
||||
-y /tmp/hf-cli-input.mp4
|
||||
test -s /tmp/hf-cli-input.mp4
|
||||
|
||||
- name: Smoke-test CLI from monorepo source
|
||||
# init's --skip-skills flag is neutered (see init.ts); opt out of the
|
||||
# GitHub skills check via this env so the smoke test stays offline/fast.
|
||||
env:
|
||||
HYPERFRAMES_SKIP_SKILLS: "1"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf /tmp/hf-cli-inside
|
||||
|
||||
bun run --filter @hyperframes/cli dev -- init /tmp/hf-cli-inside \
|
||||
--example warm-grain \
|
||||
--video /tmp/hf-cli-input.mp4 \
|
||||
--skip-transcribe \
|
||||
--non-interactive \
|
||||
--skip-skills
|
||||
|
||||
bun run --filter @hyperframes/cli dev -- lint /tmp/hf-cli-inside
|
||||
bun run --filter @hyperframes/cli dev -- validate /tmp/hf-cli-inside --timeout 3000
|
||||
bun run --filter @hyperframes/cli dev -- render /tmp/hf-cli-inside \
|
||||
--quality standard \
|
||||
--workers auto \
|
||||
--strict \
|
||||
--output /tmp/hf-cli-inside/renders/inside.mp4 2>&1 | tee /tmp/hf-cli-render.log
|
||||
|
||||
test -s /tmp/hf-cli-inside/renders/inside.mp4
|
||||
|
||||
- name: Assert page.goto completes under 5s budget
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Extract the longest page.goto time from render logs.
|
||||
# Format: [initSession:MODE] page.goto complete (NNNms)
|
||||
MAX_MS=$(grep -oP 'page\.goto complete \(\K[0-9]+' /tmp/hf-cli-render.log | sort -n | tail -1)
|
||||
if [ -z "$MAX_MS" ]; then
|
||||
echo "::error::No page.goto timing found in render logs — log format may have changed. Update the grep pattern."
|
||||
exit 1
|
||||
fi
|
||||
echo "Slowest page.goto: ${MAX_MS}ms (budget: 5000ms)"
|
||||
if [ "$MAX_MS" -gt 5000 ]; then
|
||||
echo "::error::page.goto took ${MAX_MS}ms — exceeds 5s budget. Possible Proxy/stub regression."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Pack CLI tarball
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p /tmp/hf-cli-pack
|
||||
cd packages/cli
|
||||
PACKED_TARBALL="$(npm pack --pack-destination /tmp/hf-cli-pack | tail -n 1)"
|
||||
test -n "$PACKED_TARBALL"
|
||||
test -f "/tmp/hf-cli-pack/$PACKED_TARBALL"
|
||||
echo "HF_CLI_TARBALL=/tmp/hf-cli-pack/$PACKED_TARBALL" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install packed CLI outside monorepo
|
||||
run: |
|
||||
set -euo pipefail
|
||||
npm install -g --prefix /tmp/hf-cli-global "$HF_CLI_TARBALL"
|
||||
|
||||
- name: Smoke-test packed CLI outside monorepo
|
||||
# init's --skip-skills flag is neutered (see init.ts); opt out of the
|
||||
# GitHub skills check via this env so the smoke test stays offline/fast.
|
||||
env:
|
||||
HYPERFRAMES_SKIP_SKILLS: "1"
|
||||
run: |
|
||||
set -euo pipefail
|
||||
export PATH="/tmp/hf-cli-global/bin:$PATH"
|
||||
rm -rf /tmp/hf-cli-outside
|
||||
|
||||
hyperframes init /tmp/hf-cli-outside \
|
||||
--example warm-grain \
|
||||
--video /tmp/hf-cli-input.mp4 \
|
||||
--skip-transcribe \
|
||||
--non-interactive \
|
||||
--skip-skills
|
||||
|
||||
hyperframes lint /tmp/hf-cli-outside
|
||||
hyperframes validate /tmp/hf-cli-outside --timeout 3000
|
||||
hyperframes render /tmp/hf-cli-outside \
|
||||
--quality standard \
|
||||
--workers auto \
|
||||
--strict \
|
||||
--output /tmp/hf-cli-outside/renders/outside.mp4
|
||||
|
||||
test -s /tmp/hf-cli-outside/renders/outside.mp4
|
||||
|
||||
filesize:
|
||||
name: File size check
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 1
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check file sizes (max 600 lines)
|
||||
# Scoped to files THIS PR changed under packages/studio. Walking the
|
||||
# whole tree blamed every unrelated PR for pre-existing offenders.
|
||||
# Falls back to a full scan on push events (no base ref available)
|
||||
# so the rule still guards main.
|
||||
run: |
|
||||
set -e
|
||||
if [ -n "${{ github.base_ref }}" ]; then
|
||||
mapfile -t files < <(
|
||||
git diff --name-only --diff-filter=ACMR \
|
||||
"origin/${{ github.base_ref }}...HEAD" -- \
|
||||
'packages/studio/**/*.ts' 'packages/studio/**/*.tsx' \
|
||||
| grep -vE '\.(test|spec)\.(ts|tsx)$|\.generated\.' || true
|
||||
)
|
||||
else
|
||||
mapfile -t files < <(
|
||||
find packages/studio -path '*/node_modules' -prune -o \
|
||||
\( -name '*.ts' -o -name '*.tsx' \) -print \
|
||||
| grep -vE '\.(test|spec)\.(ts|tsx)$|\.generated\.'
|
||||
)
|
||||
fi
|
||||
EXIT=0
|
||||
for f in "${files[@]}"; do
|
||||
[ -z "$f" ] && continue
|
||||
[ -f "$f" ] || continue # skip files deleted in this PR
|
||||
lines=$(wc -l < "$f")
|
||||
if [ "$lines" -gt 600 ]; then
|
||||
echo "::error file=$f::$f has $lines lines (max 600)"
|
||||
EXIT=1
|
||||
fi
|
||||
done
|
||||
exit $EXIT
|
||||
|
||||
semantic-pr-title:
|
||||
name: Semantic PR title
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
types: |
|
||||
feat
|
||||
fix
|
||||
docs
|
||||
style
|
||||
refactor
|
||||
perf
|
||||
test
|
||||
build
|
||||
ci
|
||||
chore
|
||||
revert
|
||||
@@ -0,0 +1,55 @@
|
||||
# CodeQL advanced setup. Replaces GitHub's default code-scanning setup; the
|
||||
# repo must have default setup disabled in Security → Code scanning → "Set up"
|
||||
# before this workflow can run.
|
||||
#
|
||||
# Languages were taken from the existing default-setup config (JS/TS, Python,
|
||||
# Actions). Triggers mirror what default setup ran: push to main, every PR
|
||||
# against main, and a weekly schedule.
|
||||
#
|
||||
# The rules and path filters live in .github/codeql/codeql-config.yml so policy
|
||||
# changes show up as a normal PR diff.
|
||||
name: CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
# Mondays at 14:39 UTC — matches the cadence default setup was running on.
|
||||
- cron: "39 14 * * 1"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
packages: read
|
||||
actions: read
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: actions
|
||||
build-mode: none
|
||||
- language: javascript-typescript
|
||||
build-mode: none
|
||||
- language: python
|
||||
build-mode: none
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
@@ -0,0 +1,52 @@
|
||||
name: Docs
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "DOCS_GUIDELINES.md"
|
||||
- "packages/core/schemas/**"
|
||||
- "scripts/sync-schemas.ts"
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "docs/**"
|
||||
- "DOCS_GUIDELINES.md"
|
||||
- "packages/core/schemas/**"
|
||||
- "scripts/sync-schemas.ts"
|
||||
|
||||
concurrency:
|
||||
group: docs-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: Validate docs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Check schema mirror (core → docs)
|
||||
run: npx tsx scripts/sync-schemas.ts --check
|
||||
|
||||
- name: Validate build
|
||||
working-directory: docs
|
||||
run: npx mint validate
|
||||
|
||||
- name: Check broken links
|
||||
working-directory: docs
|
||||
run: npx mint broken-links
|
||||
@@ -0,0 +1,55 @@
|
||||
# Validates the experimental fast-capture (drawElementImage) VIDEO path on a
|
||||
# native amd64 Linux runner — where chrome-headless-shell's per-frame BeginFrame
|
||||
# drives a real paint each frame, so drawElementImage's snapshot is fresh and
|
||||
# video captures correctly. This is the one part of the feature that could not be
|
||||
# validated locally (macOS has no BeginFrame; Docker-on-rosetta hung).
|
||||
# See docs/fast-capture-limitations.md (Limitation 2).
|
||||
#
|
||||
# Manual trigger: Actions → "Fast-capture video validation" → Run workflow.
|
||||
name: Fast-capture video validation
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
# Manual only. NOTE: currently fails by design — fast capture cannot capture
|
||||
# video on any platform yet (see docs/fast-capture-limitations.md, Limitation 2).
|
||||
# This is the regression gate for if/when fast video is implemented.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
composition:
|
||||
description: Test composition to render (must contain <video>)
|
||||
default: sub-composition-video
|
||||
min_psnr:
|
||||
description: Min fast-vs-baseline PSNR (dB) to pass
|
||||
default: "25"
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Build test Docker image (cached)
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.test
|
||||
load: true
|
||||
tags: hyperframes-producer:test
|
||||
cache-from: type=gha,scope=regression-test-image
|
||||
cache-to: type=gha,mode=max,scope=regression-test-image
|
||||
|
||||
- name: Validate fast-capture video (drawElement + BeginFrame)
|
||||
run: |
|
||||
docker run --rm \
|
||||
--security-opt seccomp=unconfined \
|
||||
--shm-size=4g \
|
||||
-e PRODUCER_VALIDATE_COMP='${{ inputs.composition }}' \
|
||||
-e PRODUCER_VALIDATE_MIN_PSNR='${{ inputs.min_psnr }}' \
|
||||
--workdir /app/packages/producer \
|
||||
--entrypoint bunx \
|
||||
hyperframes-producer:test tsx scripts/validate-fast-video.ts
|
||||
@@ -0,0 +1,81 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
color: #f4eee4;
|
||||
font-family:
|
||||
system-ui,
|
||||
-apple-system,
|
||||
"Segoe UI",
|
||||
sans-serif;
|
||||
}
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
gap: 40px;
|
||||
}
|
||||
#headline {
|
||||
font-size: 180px;
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 0.9;
|
||||
color: #c7c4f7;
|
||||
text-align: center;
|
||||
}
|
||||
#sub {
|
||||
font-size: 36px;
|
||||
letter-spacing: 0.3em;
|
||||
text-transform: uppercase;
|
||||
color: #f4eee4;
|
||||
opacity: 0.7;
|
||||
}
|
||||
#bar {
|
||||
width: 560px;
|
||||
height: 4px;
|
||||
background: #9b95f0;
|
||||
transform-origin: left center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="root"
|
||||
data-composition-id="main"
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<div id="headline">HYPERFRAMES</div>
|
||||
<div id="sub">RENDERED ON WINDOWS</div>
|
||||
<div id="bar"></div>
|
||||
</div>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
tl.from("#headline", { y: 80, opacity: 0, duration: 0.9, ease: "power3.out" }, 0.2);
|
||||
tl.from("#sub", { y: 40, opacity: 0, duration: 0.7, ease: "power2.out" }, 0.6);
|
||||
tl.fromTo("#bar", { scaleX: 0 }, { scaleX: 1, duration: 1.2, ease: "power4.inOut" }, 1.0);
|
||||
tl.to("#headline", { letterSpacing: "-0.01em", duration: 4.0, ease: "sine.inOut" }, 2.5);
|
||||
tl.to(["#headline", "#sub", "#bar"], { opacity: 0, duration: 0.8, ease: "power2.in" }, 7.0);
|
||||
window.__timelines["main"] = tl;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,167 @@
|
||||
name: Player perf
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
concurrency:
|
||||
group: player-perf-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
outputs:
|
||||
perf: ${{ steps.filter.outputs.perf }}
|
||||
steps:
|
||||
# Force git-based change detection instead of the pull_request REST API.
|
||||
# The API path can fail the perf workflow on transient listFiles timeouts.
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
token: ""
|
||||
filters: |
|
||||
perf:
|
||||
- "packages/player/**"
|
||||
- "packages/core/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
- ".github/workflows/player-perf.yml"
|
||||
|
||||
preflight:
|
||||
name: Preflight (lint + format)
|
||||
needs: changes
|
||||
if: needs.changes.outputs.perf == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: ./.github/actions/preflight
|
||||
|
||||
perf-shards:
|
||||
name: "Perf: ${{ matrix.shard }}"
|
||||
needs: [changes, preflight]
|
||||
if: needs.changes.outputs.perf == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include:
|
||||
- shard: load
|
||||
scenarios: load
|
||||
runs: "5"
|
||||
- shard: fps
|
||||
scenarios: fps
|
||||
runs: "3"
|
||||
- shard: scrub
|
||||
scenarios: scrub
|
||||
runs: "3"
|
||||
- shard: drift
|
||||
scenarios: drift
|
||||
runs: "3"
|
||||
- shard: parity
|
||||
scenarios: parity
|
||||
runs: "3"
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- run: bun install --frozen-lockfile
|
||||
|
||||
# Player perf loads packages/player/dist/hyperframes-player.global.js
|
||||
# and packages/core/dist/hyperframe.runtime.iife.js, so a full build is required.
|
||||
- run: bun run build
|
||||
|
||||
- name: Set up Chrome (headless shell)
|
||||
id: setup-chrome
|
||||
uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1
|
||||
with:
|
||||
chrome-version: stable
|
||||
|
||||
# The parity scenario shells out to `ffmpeg -lavfi ssim` to score the
|
||||
# live-playback frame against the sync-seek reference frame. ffmpeg is
|
||||
# not on the default ubuntu-latest runner image, and a missing binary
|
||||
# surfaces as ENOENT inside computeSsim() — informative, but cheaper
|
||||
# to just install it here so the shard never trips on infra.
|
||||
- name: Install ffmpeg (parity shard only)
|
||||
if: matrix.shard == 'parity'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends ffmpeg
|
||||
ffmpeg -version | head -n 1
|
||||
|
||||
- name: Run player perf — ${{ matrix.shard }} (measure mode)
|
||||
working-directory: packages/player
|
||||
env:
|
||||
PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
run: |
|
||||
bun run perf \
|
||||
--mode=measure \
|
||||
--scenarios=${{ matrix.scenarios }} \
|
||||
--runs=${{ matrix.runs }}
|
||||
|
||||
- name: Upload perf results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: player-perf-${{ matrix.shard }}
|
||||
path: packages/player/tests/perf/results/
|
||||
if-no-files-found: warn
|
||||
retention-days: 30
|
||||
|
||||
# Summary job — matches the required check name in branch protection.
|
||||
# Logs an explicit "skipped" / "passed" / "failed" line both to stdout and to
|
||||
# $GITHUB_STEP_SUMMARY so a false skip is obvious in the Checks UI without
|
||||
# having to dig into the changes-job logs.
|
||||
player-perf:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, perf-shards]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
env:
|
||||
PERF_FILTER_RESULT: ${{ needs.changes.outputs.perf }}
|
||||
PERF_SHARDS_RESULT: ${{ needs.perf-shards.result }}
|
||||
run: |
|
||||
{
|
||||
echo "## Player perf gate"
|
||||
echo ""
|
||||
echo "- paths-filter \`perf\` matched: \`${PERF_FILTER_RESULT}\`"
|
||||
echo "- perf-shards result: \`${PERF_SHARDS_RESULT}\`"
|
||||
echo ""
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
if [ "${PERF_FILTER_RESULT}" != "true" ]; then
|
||||
echo "::notice title=Player perf::SKIPPED — no changes under packages/player/**, packages/core/**, package.json, bun.lock, or .github/workflows/player-perf.yml. Auto-pass."
|
||||
echo "**Status:** SKIPPED (no player/core changes — auto-pass)" >> "$GITHUB_STEP_SUMMARY"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${PERF_SHARDS_RESULT}" != "success" ]; then
|
||||
echo "::error title=Player perf::FAILED — perf-shards result was '${PERF_SHARDS_RESULT}'. See the per-shard logs above."
|
||||
echo "**Status:** FAILED (perf-shards result: \`${PERF_SHARDS_RESULT}\`)" >> "$GITHUB_STEP_SUMMARY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "::notice title=Player perf::PASSED — all perf shards completed successfully."
|
||||
echo "**Status:** PASSED" >> "$GITHUB_STEP_SUMMARY"
|
||||
@@ -0,0 +1,163 @@
|
||||
name: preview-regression
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: preview-regression-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
outputs:
|
||||
preview: ${{ steps.filter.outputs.preview }}
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
token: ""
|
||||
filters: |
|
||||
preview:
|
||||
- "packages/core/**"
|
||||
- "packages/parsers/**"
|
||||
- "packages/studio-server/**"
|
||||
- "packages/lint/**"
|
||||
- "packages/player/**"
|
||||
- "packages/studio/**"
|
||||
- "packages/cli/**"
|
||||
- "packages/producer/src/parity-harness.ts"
|
||||
- "packages/producer/src/parity-fixtures.ts"
|
||||
- "packages/producer/tests/parity/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
- ".github/workflows/preview-regression.yml"
|
||||
|
||||
preflight:
|
||||
name: Preflight (lint + format)
|
||||
needs: changes
|
||||
if: needs.changes.outputs.preview == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: ./.github/actions/preflight
|
||||
|
||||
preview-parity:
|
||||
name: Preview parity
|
||||
needs: [changes, preflight]
|
||||
if: needs.changes.outputs.preview == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- run: bun install --frozen-lockfile
|
||||
|
||||
- name: Build workspace packages (required for vite config loading)
|
||||
run: |
|
||||
bun run --filter '@hyperframes/{parsers,lint,studio-server}' build
|
||||
bun run --cwd packages/core build
|
||||
|
||||
- name: Run Studio preview routing regression
|
||||
run: |
|
||||
bun run --cwd packages/studio test -- vite.thumbnail.test.ts src/utils/projectRouting.test.ts src/utils/frameCapture.test.ts
|
||||
bun run --cwd packages/studio-server test -- src/routes/thumbnail.test.ts
|
||||
|
||||
- name: Build preview runtime
|
||||
run: bun run --cwd packages/core build:hyperframes-runtime
|
||||
|
||||
- name: Prepare parity fixtures
|
||||
run: bun run --cwd packages/producer parity:fixtures:ci
|
||||
|
||||
- name: Install ffmpeg
|
||||
run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends ffmpeg
|
||||
|
||||
- name: Set up Chrome
|
||||
id: setup-chrome
|
||||
uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1
|
||||
with:
|
||||
chrome-version: stable
|
||||
|
||||
- name: Start parity fixture server
|
||||
run: |
|
||||
cd packages/producer/tests/parity/fixtures
|
||||
python3 -m http.server 4173 --bind 127.0.0.1 > /tmp/preview-parity-http.log 2>&1 &
|
||||
echo "$!" > /tmp/preview-parity-http.pid
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -fsS http://127.0.0.1:4173/minimal-wysiwyg.html >/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
cat /tmp/preview-parity-http.log
|
||||
exit 1
|
||||
|
||||
- name: Run preview parity check
|
||||
working-directory: packages/producer
|
||||
env:
|
||||
PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
run: bun run parity:check:ci
|
||||
|
||||
- name: Upload parity artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: preview-parity-artifacts
|
||||
path: packages/producer/.debug/parity-harness-ci/
|
||||
if-no-files-found: ignore
|
||||
retention-days: 30
|
||||
|
||||
preview-regression:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, preview-parity]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
env:
|
||||
PREVIEW_FILTER_RESULT: ${{ needs.changes.outputs.preview }}
|
||||
PREVIEW_PARITY_RESULT: ${{ needs.preview-parity.result }}
|
||||
run: |
|
||||
{
|
||||
echo "## Preview regression gate"
|
||||
echo ""
|
||||
echo "- paths-filter \`preview\` matched: \`${PREVIEW_FILTER_RESULT}\`"
|
||||
echo "- preview-parity result: \`${PREVIEW_PARITY_RESULT}\`"
|
||||
echo ""
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
if [ "${PREVIEW_FILTER_RESULT}" != "true" ]; then
|
||||
echo "::notice title=Preview regression::SKIPPED — no preview/runtime changes. Auto-pass."
|
||||
echo "**Status:** SKIPPED (no preview/runtime changes — auto-pass)" >> "$GITHUB_STEP_SUMMARY"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "${PREVIEW_PARITY_RESULT}" != "success" ]; then
|
||||
echo "**Status:** FAILED" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "Preview parity check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "**Status:** PASSED" >> "$GITHUB_STEP_SUMMARY"
|
||||
@@ -0,0 +1,191 @@
|
||||
name: Publish to npm
|
||||
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version to publish (e.g. 0.4.11). Tag v<version> must already exist."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Publish
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
environment: npm-publish
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
# Run on tag push, manual dispatch, OR when a release/* PR is merged
|
||||
if: >-
|
||||
github.event_name == 'push' ||
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event.pull_request.merged == true &&
|
||||
startsWith(github.event.pull_request.head.ref, 'release/v'))
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
# On manual dispatch, check out the existing tag so we publish the
|
||||
# exact commit that was tagged — not whatever is currently on main.
|
||||
ref: >-
|
||||
${{ github.event_name == 'workflow_dispatch'
|
||||
&& format('refs/tags/v{0}', inputs.version)
|
||||
|| github.ref }}
|
||||
|
||||
- name: Resolve version
|
||||
id: version
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
INPUT_VERSION: ${{ inputs.version }}
|
||||
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
if [ "$EVENT_NAME" = "push" ]; then
|
||||
VERSION="${GITHUB_REF_NAME#v}"
|
||||
elif [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
||||
VERSION="${INPUT_VERSION}"
|
||||
VERSION="${VERSION#v}"
|
||||
else
|
||||
BRANCH="${PR_HEAD_REF}"
|
||||
VERSION="${BRANCH#release/v}"
|
||||
fi
|
||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Detect pre-release tag (e.g. 0.1.16-alpha.1 → alpha, 0.1.16-beta.2 → beta)
|
||||
if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then
|
||||
DIST_TAG="${BASH_REMATCH[1]}"
|
||||
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
DIST_TAG="latest"
|
||||
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
echo "dist_tag=${DIST_TAG}" >> "$GITHUB_OUTPUT"
|
||||
echo "Resolved version=${VERSION} dist_tag=${DIST_TAG}"
|
||||
|
||||
- name: Validate release channel
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
DIST_TAG: ${{ steps.version.outputs.dist_tag }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
||||
run: node scripts/validate-release-channel.mjs
|
||||
|
||||
- name: Create release tag
|
||||
if: github.event_name == 'pull_request'
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
git tag "v$VERSION"
|
||||
git push origin "v$VERSION"
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 24
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- run: corepack enable
|
||||
- run: corepack prepare pnpm@10.17.1 --activate
|
||||
- run: bun install --frozen-lockfile
|
||||
- run: bun run build
|
||||
- run: bun run verify:packed-manifests
|
||||
|
||||
- name: Publish packages
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
DIST_TAG: ${{ steps.version.outputs.dist_tag }}
|
||||
run: |
|
||||
FAILED=0
|
||||
|
||||
publish_pkg() {
|
||||
local filter="$1"
|
||||
local name="$2"
|
||||
|
||||
# Check if this version is already published
|
||||
if npm view "${name}@${VERSION}" version >/dev/null 2>&1; then
|
||||
echo "⏭️ ${name}@${VERSION} already published — skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "📦 Publishing ${name}@${VERSION}..."
|
||||
if pnpm --filter "$filter" publish --access public --no-git-checks --tag "$DIST_TAG"; then
|
||||
echo "✅ ${name}@${VERSION} published"
|
||||
else
|
||||
echo "❌ ${name}@${VERSION} failed to publish"
|
||||
FAILED=1
|
||||
fi
|
||||
}
|
||||
|
||||
publish_pkg "@hyperframes/parsers" "@hyperframes/parsers"
|
||||
publish_pkg "@hyperframes/lint" "@hyperframes/lint"
|
||||
publish_pkg "@hyperframes/studio-server" "@hyperframes/studio-server"
|
||||
publish_pkg "@hyperframes/core" "@hyperframes/core"
|
||||
publish_pkg "@hyperframes/sdk" "@hyperframes/sdk"
|
||||
publish_pkg "@hyperframes/engine" "@hyperframes/engine"
|
||||
publish_pkg "@hyperframes/player" "@hyperframes/player"
|
||||
publish_pkg "@hyperframes/producer" "@hyperframes/producer"
|
||||
publish_pkg "@hyperframes/shader-transitions" "@hyperframes/shader-transitions"
|
||||
publish_pkg "@hyperframes/studio" "@hyperframes/studio"
|
||||
publish_pkg "@hyperframes/aws-lambda" "@hyperframes/aws-lambda"
|
||||
publish_pkg "@hyperframes/gcp-cloud-run" "@hyperframes/gcp-cloud-run"
|
||||
|
||||
# CLI is @hyperframes/cli in the monorepo but published as unscoped "hyperframes" on npm.
|
||||
# Rewrite the name in package.json before publishing, then use npm publish directly
|
||||
# since pnpm --filter won't match the rewritten name.
|
||||
if npm view "hyperframes@${VERSION}" version >/dev/null 2>&1; then
|
||||
echo "⏭️ hyperframes@${VERSION} already published — skipping"
|
||||
else
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const p = 'packages/cli/package.json';
|
||||
const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||
pkg.name = 'hyperframes';
|
||||
fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n');
|
||||
"
|
||||
echo "📦 Publishing hyperframes@${VERSION}..."
|
||||
if (cd packages/cli && npm publish --access public --tag "$DIST_TAG"); then
|
||||
echo "✅ hyperframes@${VERSION} published"
|
||||
else
|
||||
echo "❌ hyperframes@${VERSION} failed to publish"
|
||||
FAILED=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$FAILED" -ne 0 ]; then
|
||||
echo "::error::One or more packages failed to publish"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create GitHub Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
PRERELEASE: ${{ steps.version.outputs.prerelease }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
NOTES_FILE="releases/v${VERSION}.md"
|
||||
|
||||
# Skip if release already exists (idempotent re-runs)
|
||||
if gh release view "v${VERSION}" --repo "$REPO" >/dev/null 2>&1; then
|
||||
echo "Release v${VERSION} already exists — skipping"
|
||||
else
|
||||
FLAGS=(--repo "$REPO" --title "v${VERSION}")
|
||||
if [ -f "$NOTES_FILE" ]; then
|
||||
FLAGS+=(--notes-file "$NOTES_FILE")
|
||||
else
|
||||
echo "No reviewed release notes found at $NOTES_FILE — using GitHub generated notes"
|
||||
FLAGS+=(--generate-notes)
|
||||
fi
|
||||
if [ "$PRERELEASE" = "true" ]; then
|
||||
FLAGS+=(--prerelease)
|
||||
fi
|
||||
gh release create "v${VERSION}" "${FLAGS[@]}"
|
||||
fi
|
||||
@@ -0,0 +1,159 @@
|
||||
name: regression
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
# Graphite can update a branch and its PR base separately for the same head
|
||||
# SHA. Keep only the newest expensive regression run for each PR/ref.
|
||||
concurrency:
|
||||
group: regression-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
outputs:
|
||||
code: ${{ steps.filter.outputs.code }}
|
||||
steps:
|
||||
# Force git-based change detection instead of the pull_request REST API.
|
||||
# The API path can fail the whole workflow on transient listFiles
|
||||
# timeouts before any regression shard even starts.
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
token: ""
|
||||
filters: |
|
||||
code:
|
||||
- "packages/core/**"
|
||||
- "packages/producer/**"
|
||||
- "packages/engine/**"
|
||||
- "Dockerfile*"
|
||||
|
||||
preflight:
|
||||
name: Preflight (lint + format)
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: ./.github/actions/preflight
|
||||
|
||||
regression-shards:
|
||||
needs: [changes, preflight]
|
||||
if: needs.changes.outputs.code == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
# Shards are bin-packed by measured per-test duration (LPT heuristic on
|
||||
# CI run 25893372795) so each row carries ~15-16 min of work. When a
|
||||
# new fixture lands, drop it into the currently-lightest shard or
|
||||
# re-balance against fresh `test_suite_summary` timings. Worst-shard
|
||||
# work time was 19.3 min under the old tag-based split (styles-e);
|
||||
# the rebalance brings every shard within ~40s of the others.
|
||||
include:
|
||||
- shard: shard-1
|
||||
args: "hdr-regression style-5-prod style-3-prod mov-prores"
|
||||
- shard: shard-2
|
||||
args: "style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets"
|
||||
- shard: shard-3
|
||||
args: "style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9"
|
||||
- shard: shard-4
|
||||
args: "style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr"
|
||||
- shard: shard-5
|
||||
args: "style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression"
|
||||
- shard: shard-6
|
||||
args: "overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed"
|
||||
- shard: shard-7
|
||||
args: "sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector"
|
||||
- shard: shard-8
|
||||
args: "style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity"
|
||||
steps:
|
||||
- name: Checkout (with LFS)
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
- name: Validate LFS files
|
||||
run: |
|
||||
echo "Checking golden baseline MP4s are real files (not LFS pointers)..."
|
||||
for mp4 in packages/producer/tests/*/output/output.mp4; do
|
||||
if [ -f "$mp4" ]; then
|
||||
size=$(stat --format=%s "$mp4")
|
||||
if [ "$size" -lt 1000 ]; then
|
||||
echo "ERROR: $mp4 appears to be an LFS pointer ($size bytes)"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: $mp4 ($size bytes)"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Build test Docker image (cached)
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.test
|
||||
load: true
|
||||
tags: hyperframes-producer:test
|
||||
cache-from: type=gha,scope=regression-test-image
|
||||
# PR matrices can fan out across many stacked branches at once. Let
|
||||
# them consume the shared cache, but keep a single writer on main so
|
||||
# concurrent exports cannot exhaust the Actions cache service.
|
||||
cache-to: ${{ github.event_name == 'push' && 'type=gha,mode=max,scope=regression-test-image' || '' }}
|
||||
|
||||
- name: "Run regression shard: ${{ matrix.shard }}"
|
||||
run: |
|
||||
echo "Shard: ${{ matrix.shard }}"
|
||||
echo "Args: ${{ matrix.args }}"
|
||||
docker run --rm \
|
||||
--security-opt seccomp=unconfined \
|
||||
--shm-size=4g \
|
||||
-v ${{ github.workspace }}/packages/producer/tests:/app/packages/producer/tests \
|
||||
hyperframes-producer:test \
|
||||
${{ matrix.args }}
|
||||
|
||||
- name: Upload failure artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: regression-failures-${{ matrix.shard }}
|
||||
path: packages/producer/tests/*/failures/
|
||||
if-no-files-found: ignore
|
||||
|
||||
# Summary job — matches the required check name in branch protection
|
||||
regression:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, regression-shards]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check results
|
||||
run: |
|
||||
if [ "${{ needs.changes.outputs.code }}" != "true" ]; then
|
||||
echo "No code changes — skipping regression (auto-pass)"
|
||||
exit 0
|
||||
fi
|
||||
if [ "${{ needs.regression-shards.result }}" != "success" ]; then
|
||||
echo "One or more regression shards failed"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,66 @@
|
||||
name: Sync skills to ClawHub
|
||||
|
||||
# Publishes changed skills under skills/ to ClawHub (https://clawhub.ai/heygen-com)
|
||||
# whenever they land on main. `clawhub sync` only publishes skills whose content
|
||||
# changed vs. the registry, auto-bumping the patch version — unchanged skills are
|
||||
# a no-op, so this is safe to run on every push.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "skills/**"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: "Preview what would publish without publishing"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
# Serialize runs so two pushes don't race on the same skill version.
|
||||
concurrency:
|
||||
group: clawhub-sync
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
name: Publish changed skills
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
CLAWHUB_DISABLE_TELEMETRY: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install ClawHub CLI
|
||||
run: npm i -g clawhub@0.23.1
|
||||
|
||||
- name: Authenticate
|
||||
env:
|
||||
CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }}
|
||||
run: clawhub login --token "$CLAWHUB_TOKEN" --no-input --label "hyperframes CI"
|
||||
|
||||
- name: Sync skills
|
||||
env:
|
||||
DRY_RUN: ${{ github.event.inputs.dry_run }}
|
||||
run: |
|
||||
FLAGS=(
|
||||
--all
|
||||
--owner heygen-com
|
||||
--bump patch
|
||||
--changelog "Synced from ${GITHUB_SHA:0:7} (${GITHUB_REF_NAME})"
|
||||
--source-repo "$GITHUB_REPOSITORY"
|
||||
--source-commit "$GITHUB_SHA"
|
||||
--source-ref "$GITHUB_REF"
|
||||
)
|
||||
if [ "$DRY_RUN" = "true" ]; then
|
||||
FLAGS+=(--dry-run)
|
||||
fi
|
||||
clawhub sync "${FLAGS[@]}"
|
||||
@@ -0,0 +1,450 @@
|
||||
name: Windows render verification
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Suppress hyperframes CLI telemetry from HeyGen's own CI runs.
|
||||
# External users' CI continues to emit telemetry unless they set this themselves.
|
||||
env:
|
||||
HYPERFRAMES_NO_TELEMETRY: "1"
|
||||
|
||||
# Manually triggered smoke test that renders a HyperFrames composition on a
|
||||
# real Windows runner. Proves the PR #336 `where ffmpeg` fix actually works
|
||||
# end-to-end: FFmpeg is discovered natively on Windows, Chrome is installed
|
||||
# and launched, frames are captured, and an MP4 is produced — without Docker
|
||||
# or WSL.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
# `edited` is required so the workflow re-fires when a PR's base ref is
|
||||
# set back to `main` after a Graphite stack restack momentarily flips
|
||||
# the base off of `main`. Without it, `pull_request` triggers are not
|
||||
# re-evaluated on `base_ref_changed`, leaving required checks skipped
|
||||
# for that head SHA forever.
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
ref:
|
||||
description: "Git ref to render (branch / tag / SHA)."
|
||||
required: false
|
||||
default: "main"
|
||||
|
||||
concurrency:
|
||||
group: windows-render-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
name: Detect changes
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
outputs:
|
||||
code: ${{ steps.filter.outputs.code }}
|
||||
steps:
|
||||
# Force git-based change detection instead of the pull_request REST API.
|
||||
# The API path can fail the workflow on transient listFiles timeouts
|
||||
# before the Windows render jobs even start.
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
||||
id: filter
|
||||
with:
|
||||
token: ""
|
||||
filters: |
|
||||
code:
|
||||
- "packages/**"
|
||||
- "scripts/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
- ".github/workflows/windows-render.yml"
|
||||
|
||||
preflight:
|
||||
name: Preflight (lint + format)
|
||||
needs: changes
|
||||
if: needs.changes.outputs.code == 'true' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
- uses: ./.github/actions/preflight
|
||||
|
||||
render-windows:
|
||||
name: Render on windows-latest
|
||||
needs: [changes, preflight]
|
||||
if: needs.changes.outputs.code == 'true' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Disable Windows Defender real-time monitoring
|
||||
shell: pwsh
|
||||
continue-on-error: true
|
||||
run: Set-MpPreference -DisableRealtimeMonitoring $true
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
lfs: true
|
||||
|
||||
- name: Show platform info
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "OS: $([System.Environment]::OSVersion.VersionString)"
|
||||
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
|
||||
Write-Host "Runner: windows-latest"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Install FFmpeg via the shared composite action so the install logic
|
||||
# stays identical between this job and `test-windows` below. See
|
||||
# .github/actions/install-ffmpeg-windows for why we bypass Chocolatey.
|
||||
# -----------------------------------------------------------------
|
||||
- name: Install FFmpeg
|
||||
uses: ./.github/actions/install-ffmpeg-windows
|
||||
|
||||
- name: Set FFMPEG_BIN for bun install
|
||||
shell: pwsh
|
||||
run: |
|
||||
$path = (Get-Command ffmpeg.exe).Source
|
||||
"FFMPEG_BIN=$path" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Verify FFmpeg feature inventory.
|
||||
#
|
||||
# The engine shells out to a fixed set of encoders (libx264 for MP4,
|
||||
# libx265 for HEVC, libvpx-vp9 for WebM, prores_ks for transparent
|
||||
# MOV, aac for audio), muxers (mp4 / mov / webm), and demuxers
|
||||
# (image2pipe for streaming RGBA frames, rawvideo for HDR PQ frames,
|
||||
# mov,mp4 for video frame extraction). Some of these are GPL-only,
|
||||
# so a future build swap could silently drop one and break a code
|
||||
# path the canary render doesn't exercise. Fail fast here instead.
|
||||
# -----------------------------------------------------------------
|
||||
- name: Verify FFmpeg feature inventory
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Assert-FfmpegFeature {
|
||||
param(
|
||||
[Parameter(Mandatory)] [string] $Listing,
|
||||
[Parameter(Mandatory)] [string] $Name,
|
||||
[Parameter(Mandatory)] [string] $Kind
|
||||
)
|
||||
# `ffmpeg -encoders` etc. emit one feature per line as
|
||||
# `<flags> <name> <description>`, so a whitespace boundary on
|
||||
# each side is enough to disambiguate (e.g. `mov` vs `movflags`).
|
||||
$pattern = "(^|\s)$([regex]::Escape($Name))(\s|$)"
|
||||
if ($Listing -notmatch $pattern) {
|
||||
throw "Required FFmpeg $Kind '$Name' not present in this build"
|
||||
}
|
||||
Write-Host " ok: $Kind $Name"
|
||||
}
|
||||
|
||||
Write-Host "--- encoders ---"
|
||||
$encoders = (& ffmpeg -hide_banner -encoders 2>&1) -join "`n"
|
||||
foreach ($enc in @('libx264', 'libx265', 'libvpx-vp9', 'prores_ks', 'aac')) {
|
||||
Assert-FfmpegFeature -Listing $encoders -Name $enc -Kind 'encoder'
|
||||
}
|
||||
|
||||
Write-Host "--- muxers ---"
|
||||
$muxers = (& ffmpeg -hide_banner -muxers 2>&1) -join "`n"
|
||||
foreach ($mux in @('mp4', 'mov', 'webm')) {
|
||||
Assert-FfmpegFeature -Listing $muxers -Name $mux -Kind 'muxer'
|
||||
}
|
||||
|
||||
Write-Host "--- demuxers ---"
|
||||
$demuxers = (& ffmpeg -hide_banner -demuxers 2>&1) -join "`n"
|
||||
foreach ($dem in @('image2pipe', 'rawvideo', 'mov,mp4,m4a,3gp,3g2,mj2')) {
|
||||
Assert-FfmpegFeature -Listing $demuxers -Name $dem -Kind 'demuxer'
|
||||
}
|
||||
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
# Force the pre-1.3 "hoisted" linker on Windows. Bun 1.3.x's default
|
||||
# "isolated" linker creates nested workspace junctions that don't
|
||||
# materialize reliably on Windows GHA runners — manifests as
|
||||
# `Cannot find package 'esbuild'` walking up from
|
||||
# `packages/producer/build.mjs` and `EPERM stat` on
|
||||
# `packages/producer/node_modules/@fontsource/*` from generators.
|
||||
# See oven-sh/bun#23615, #18354, #10146. Linux CI keeps isolated;
|
||||
# the lockfile is linker-agnostic so this flag is safe with
|
||||
# --frozen-lockfile.
|
||||
run: bun install --frozen-lockfile --linker=hoisted
|
||||
|
||||
- name: Build all packages
|
||||
shell: pwsh
|
||||
run: bun run build
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Prove the PR #336 fix: hyperframes doctor exercises findFFmpeg()
|
||||
# and whichBinary() — both must pass on Windows without workarounds.
|
||||
# -----------------------------------------------------------------
|
||||
- name: hyperframes doctor (verifies `where ffmpeg` fix)
|
||||
shell: pwsh
|
||||
run: node packages/cli/dist/cli.js doctor
|
||||
|
||||
- name: Scaffold canary composition
|
||||
shell: pwsh
|
||||
# init's --skip-skills flag is neutered (see init.ts); opt out of the
|
||||
# GitHub skills check via this env so the canary scaffold stays offline.
|
||||
env:
|
||||
HYPERFRAMES_SKIP_SKILLS: "1"
|
||||
run: |
|
||||
New-Item -ItemType Directory -Force -Path "$env:RUNNER_TEMP\windows-canary" | Out-Null
|
||||
cd "$env:RUNNER_TEMP\windows-canary"
|
||||
node "$env:GITHUB_WORKSPACE\packages\cli\dist\cli.js" init canary --example blank --non-interactive --skip-skills
|
||||
|
||||
$fixtures = "$env:GITHUB_WORKSPACE\.github\workflows\fixtures"
|
||||
Copy-Item "$fixtures\windows-canary.html" "canary\index.html" -Force
|
||||
|
||||
- name: Render canary composition
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd "$env:RUNNER_TEMP\windows-canary\canary"
|
||||
node "$env:GITHUB_WORKSPACE\packages\cli\dist\cli.js" render `
|
||||
--fps 30 `
|
||||
--quality draft `
|
||||
--workers 2 `
|
||||
--output renders\canary.mp4
|
||||
|
||||
- name: Verify rendered MP4
|
||||
shell: pwsh
|
||||
run: |
|
||||
$mp4 = "$env:RUNNER_TEMP\windows-canary\canary\renders\canary.mp4"
|
||||
if (-not (Test-Path $mp4)) { throw "canary.mp4 not produced" }
|
||||
|
||||
$probe = ffprobe -v error -select_streams v:0 `
|
||||
-show_entries stream=width,height,r_frame_rate -show_entries format=duration `
|
||||
-of default=noprint_wrappers=1 $mp4
|
||||
Write-Host $probe
|
||||
|
||||
# Parse probe output
|
||||
$width = ($probe | Select-String '^width=(.+)$').Matches.Groups[1].Value
|
||||
$height = ($probe | Select-String '^height=(.+)$').Matches.Groups[1].Value
|
||||
$fps = ($probe | Select-String '^r_frame_rate=(.+)$').Matches.Groups[1].Value
|
||||
$duration = [double]($probe | Select-String '^duration=(.+)$').Matches.Groups[1].Value
|
||||
|
||||
if ([int]$width -ne 1920) { throw "expected 1920 width, got $width" }
|
||||
if ([int]$height -ne 1080) { throw "expected 1080 height, got $height" }
|
||||
if ($fps -ne "30/1") { throw "expected 30fps, got $fps" }
|
||||
if ($duration -lt 7.5 -or $duration -gt 8.5) { throw "expected ~8s duration, got $duration" }
|
||||
|
||||
Write-Host "canary.mp4 ok: ${width}x${height} @ $fps, ${duration}s"
|
||||
|
||||
- name: Scaffold issue #574 reused-video regression
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$project = "$env:RUNNER_TEMP\issue-574-reused-video"
|
||||
New-Item -ItemType Directory -Force -Path $project | Out-Null
|
||||
cd $project
|
||||
|
||||
ffmpeg -y `
|
||||
-f lavfi -i "testsrc2=size=1920x1080:rate=30:duration=12" `
|
||||
-f lavfi -i "sine=frequency=880:sample_rate=48000:duration=12" `
|
||||
-c:v libx264 `
|
||||
-pix_fmt yuv420p `
|
||||
-r 30 `
|
||||
-g 250 `
|
||||
-keyint_min 250 `
|
||||
-c:a aac `
|
||||
-shortest `
|
||||
1.mp4
|
||||
|
||||
@'
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Issue 574 reused video regression</title>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#root {
|
||||
position: relative;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="root"
|
||||
data-composition-id="root"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<video id="video1" src="1.mp4" data-start="0" muted data-duration="4" data-track-index="0" data-media-start="0"></video>
|
||||
<video id="video2" src="1.mp4" data-start="4" muted data-duration="4" data-track-index="0" data-media-start="4"></video>
|
||||
<video id="video3" src="1.mp4" data-start="8" muted data-duration="4" data-track-index="0" data-media-start="8"></video>
|
||||
</div>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
'@ | Set-Content -Path index.html -Encoding utf8
|
||||
|
||||
- name: Render issue #574 reused-video regression
|
||||
shell: pwsh
|
||||
env:
|
||||
PRODUCER_PLAYER_READY_TIMEOUT_MS: "15000"
|
||||
run: |
|
||||
cd "$env:RUNNER_TEMP\issue-574-reused-video"
|
||||
node "$env:GITHUB_WORKSPACE\packages\cli\dist\cli.js" render `
|
||||
--fps 30 `
|
||||
--quality standard `
|
||||
--workers 1 `
|
||||
--output renders\issue-574.mp4
|
||||
|
||||
- name: Verify issue #574 rendered MP4
|
||||
shell: pwsh
|
||||
run: |
|
||||
$mp4 = "$env:RUNNER_TEMP\issue-574-reused-video\renders\issue-574.mp4"
|
||||
if (-not (Test-Path $mp4)) { throw "issue-574.mp4 not produced" }
|
||||
|
||||
$probe = ffprobe -v error -select_streams v:0 `
|
||||
-show_entries stream=width,height,r_frame_rate -show_entries format=duration `
|
||||
-of default=noprint_wrappers=1 $mp4
|
||||
Write-Host $probe
|
||||
|
||||
$width = ($probe | Select-String '^width=(.+)$').Matches.Groups[1].Value
|
||||
$height = ($probe | Select-String '^height=(.+)$').Matches.Groups[1].Value
|
||||
$fps = ($probe | Select-String '^r_frame_rate=(.+)$').Matches.Groups[1].Value
|
||||
$duration = [double]($probe | Select-String '^duration=(.+)$').Matches.Groups[1].Value
|
||||
|
||||
if ([int]$width -ne 1920) { throw "expected 1920 width, got $width" }
|
||||
if ([int]$height -ne 1080) { throw "expected 1080 height, got $height" }
|
||||
if ($fps -ne "30/1") { throw "expected 30fps, got $fps" }
|
||||
if ($duration -lt 11.5 -or $duration -gt 12.5) { throw "expected ~12s duration, got $duration" }
|
||||
|
||||
Write-Host "issue-574.mp4 ok: ${width}x${height} @ $fps, ${duration}s"
|
||||
|
||||
- name: Upload rendered MP4 artifact
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: windows-render-${{ github.run_id }}
|
||||
path: |
|
||||
${{ runner.temp }}/windows-canary/canary/renders/canary.mp4
|
||||
${{ runner.temp }}/issue-574-reused-video/renders/issue-574.mp4
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Unit-test suites on Windows. Mirrors the Linux `test` job in ci.yml
|
||||
# so we catch Windows-specific regressions (path separators, shell
|
||||
# invocations, CRLF, file URLs, etc.) in existing vitest suites.
|
||||
# The producer package is skipped because its tests require Docker /
|
||||
# Linux-only tooling (Dockerfile.test, LFS golden MP4 baselines).
|
||||
# The aws-lambda package is skipped because it targets the AWS Lambda
|
||||
# Linux runtime exclusively (`@sparticuz/chromium` is Linux-only; the
|
||||
# ZIP layout is for `/var/task` on AL2023). Its handler.test.ts also
|
||||
# trips a bun-on-Windows workspace-symlink quirk reading the
|
||||
# producer's transitive `hono` dep.
|
||||
# -------------------------------------------------------------------
|
||||
test-windows:
|
||||
name: Tests on windows-latest
|
||||
needs: [changes, preflight]
|
||||
if: needs.changes.outputs.code == 'true' || github.event_name == 'workflow_dispatch'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
steps:
|
||||
- name: Disable Windows Defender real-time monitoring
|
||||
shell: pwsh
|
||||
continue-on-error: true
|
||||
run: Set-MpPreference -DisableRealtimeMonitoring $true
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
lfs: true
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Install FFmpeg so vitest suites that gate on `HAS_FFMPEG`
|
||||
# (e.g. packages/engine videoFrameExtractor.test.ts) actually run on
|
||||
# Windows. Without it those suites `describe.skipIf(!HAS_FFMPEG)`
|
||||
# themselves silently and any Windows-specific regression in the
|
||||
# FFmpeg-driven code paths would not be caught here.
|
||||
# -----------------------------------------------------------------
|
||||
- name: Install FFmpeg
|
||||
uses: ./.github/actions/install-ffmpeg-windows
|
||||
|
||||
- name: Set FFMPEG_BIN for bun install
|
||||
shell: pwsh
|
||||
run: |
|
||||
$path = (Get-Command ffmpeg.exe).Source
|
||||
"FFMPEG_BIN=$path" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
||||
|
||||
- name: Install Bun
|
||||
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Install dependencies
|
||||
shell: pwsh
|
||||
# Force the pre-1.3 "hoisted" linker on Windows. Bun 1.3.x's default
|
||||
# "isolated" linker creates nested workspace junctions that don't
|
||||
# materialize reliably on Windows GHA runners — manifests as
|
||||
# `Cannot find package 'esbuild'` walking up from
|
||||
# `packages/producer/build.mjs` and `EPERM stat` on
|
||||
# `packages/producer/node_modules/@fontsource/*` from generators.
|
||||
# See oven-sh/bun#23615, #18354, #10146. Linux CI keeps isolated;
|
||||
# the lockfile is linker-agnostic so this flag is safe with
|
||||
# --frozen-lockfile.
|
||||
run: bun install --frozen-lockfile --linker=hoisted
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: bun run build
|
||||
|
||||
- name: Run tests (all packages except producer + aws-lambda)
|
||||
shell: pwsh
|
||||
# Enumerate the packages we want to test instead of negating —
|
||||
# `bun run --filter "!a" --filter "!b"` composes as a union (any
|
||||
# package matching either negation runs), not an intersection.
|
||||
# That meant `@hyperframes/producer` was effectively still being
|
||||
# tested on Windows, which is what we explicitly want skipped
|
||||
# (Docker / LFS-baseline tooling).
|
||||
run: bun run --filter @hyperframes/core --filter @hyperframes/engine --filter @hyperframes/player --filter @hyperframes/cli --filter @hyperframes/studio --filter @hyperframes/shader-transitions test
|
||||
|
||||
- name: Run runtime contract test
|
||||
shell: pwsh
|
||||
run: bun run --filter "@hyperframes/core" test:hyperframe-runtime-ci
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Build output
|
||||
dist/
|
||||
*.tsbuildinfo
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Lefthook per-developer overrides (not shared; see lefthook.yml for shared hooks)
|
||||
lefthook-local.yml
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Docs media — served from CDN, not committed.
|
||||
# Regenerate with scripts/generate-{catalog,template}-previews.ts then upload
|
||||
# with `bun run upload:docs-images`. Add explicit negations below for any
|
||||
# non-generated assets (logos, svgs) that should stay in the repo.
|
||||
docs/images/
|
||||
|
||||
videos/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Test
|
||||
coverage/
|
||||
.debug/
|
||||
|
||||
# Producer regression test failures (generated debugging artifacts).
|
||||
# RECURSIVE (`**`) so a failures/ dump at ANY fixture depth is ignored — the
|
||||
# old non-recursive `tests/*/failures/` + `tests/distributed/*/failures/` rules
|
||||
# only matched one level deep, so a nested fixture like
|
||||
# `tests/hdr-regression/hdr-pq/failures/` could still get committed.
|
||||
packages/producer/tests/**/failures/
|
||||
packages/producer/tests/parity/fixtures/hyperframe.runtime.iife.js
|
||||
|
||||
# Player perf test results (generated each run, attached as CI artifact)
|
||||
packages/player/tests/perf/results/
|
||||
|
||||
# Rendered output (not test fixtures — those use git LFS)
|
||||
output/
|
||||
renders/
|
||||
!packages/producer/tests/*/output/
|
||||
!packages/producer/tests/distributed/*/output/
|
||||
# Source dir that the renders/ output rule accidentally shadows (its files are
|
||||
# tracked; without this, pre-commit's format re-stage fails on them).
|
||||
!packages/studio/src/components/renders/
|
||||
|
||||
# Composition source media (large binaries)
|
||||
compositions/**/*.mp4
|
||||
compositions/**/*.mov
|
||||
compositions/**/*.MOV
|
||||
|
||||
# npm pack artifacts
|
||||
*.tgz
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Temporary
|
||||
tmp/
|
||||
.tmp/
|
||||
|
||||
# Generated files
|
||||
packages/core/src/generated/*
|
||||
!packages/core/src/generated/position-edits-render-inline.ts
|
||||
!packages/core/src/generated/position-edits-render-inline.test.ts
|
||||
packages/producer/src/services/fontData.generated.ts
|
||||
|
||||
# Plan documents (working artifacts, not committed)
|
||||
docs/plans/
|
||||
|
||||
# Local proof / test artifacts
|
||||
qa-artifacts/
|
||||
my-video/
|
||||
# Studio project state (hf-id backups, per-file state) — always runtime-generated,
|
||||
# never committed. Broadened from .hyperframes/backup/ after preview-generated state
|
||||
# leaked into a fixture commit.
|
||||
.hyperframes/
|
||||
examples/*
|
||||
# Tracked OSS examples — negations override the blanket `examples/*` ignore.
|
||||
!examples/aws-lambda
|
||||
!examples/aws-lambda/**
|
||||
!examples/k8s-jobs
|
||||
!examples/k8s-jobs/**
|
||||
!examples/gcp-cloud-run
|
||||
!examples/gcp-cloud-run/**
|
||||
# …but never the local smoke run's build/render artifacts.
|
||||
examples/gcp-cloud-run/scripts/gcp-smoke-artifacts/
|
||||
packages/studio/data/
|
||||
|
||||
.desloppify/
|
||||
.worktrees/
|
||||
|
||||
# Playwright MCP browser cache
|
||||
.playwright-mcp/
|
||||
|
||||
# Installed skills (user-specific)
|
||||
.agents/
|
||||
.claude/skills/
|
||||
skills-lock.json
|
||||
|
||||
# Skills from other PRs (not managed here)
|
||||
skills/hyperframes-animation-map/
|
||||
skills/hyperframes-contrast/
|
||||
|
||||
# Capture outputs
|
||||
captures/
|
||||
# Legacy test captures at repo root (use captures/ instead)
|
||||
*-capture/
|
||||
*-demo/
|
||||
*-ad/
|
||||
*-tour/
|
||||
*-brand/
|
||||
|
||||
# Local regression-test and video project scratch directories.
|
||||
# These hold per-site captures, compositions, narration audio, rendered MP4s.
|
||||
cursor-tests/
|
||||
basecamp-video/
|
||||
launch-video*/
|
||||
!skills/launch-video/
|
||||
ab-test/
|
||||
compositions/
|
||||
video-6-2-patched/
|
||||
claude-design-hyperframes-video/
|
||||
# Per-site video work at the repo root (huly-*, raycast-*, etc.)
|
||||
# Anything under videos/ is already covered above, but agents sometimes write
|
||||
# project dirs to the repo root when iterating. Catch the common per-brand
|
||||
# patterns and any *-demo-N variants the *-demo/ rule above misses.
|
||||
huly-*/
|
||||
raycast-*/
|
||||
*-demo-*/
|
||||
test-runs/
|
||||
test-outputs/
|
||||
|
||||
# Claude Code worktrees + superpowers docs
|
||||
.claude/worktrees/
|
||||
.claude/
|
||||
docs/superpowers/
|
||||
.worktrees
|
||||
hyperframes-bench/
|
||||
tmp/
|
||||
# Studio-generated preview thumbnails
|
||||
.thumbnails/
|
||||
|
||||
# Local editor settings
|
||||
.zed/
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"semi": true,
|
||||
"useTabs": false,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
},
|
||||
"plugins": ["react", "typescript"],
|
||||
"ignorePatterns": [
|
||||
"dist/",
|
||||
"coverage/",
|
||||
"node_modules/",
|
||||
"playground/",
|
||||
"packages/producer/tests/**/src/vendor/**",
|
||||
"registry/blocks/**/lib/*.iife.js",
|
||||
"chrome/"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
docs/
|
||||
DOCS_GUIDELINES.md
|
||||
packages/producer/tests/
|
||||
*.generated.ts
|
||||
|
||||
# Cloud Workflows GCL — uses ${...} expressions that are not standard YAML.
|
||||
packages/gcp-cloud-run/terraform/workflow.yaml
|
||||
|
||||
# toMatchFileSnapshot golden files — vitest writes these; oxfmt must not reformat them.
|
||||
packages/**/__goldens__/
|
||||
|
||||
# vendored third-party bundles inside skills — never reformat
|
||||
skills/**/assets/vendor/
|
||||
skills/**/*.min.js
|
||||
# reference snippets with intentional pseudo-markup (literal "..." attributes)
|
||||
skills/talking-head-recut/references/frames/polaroid.html
|
||||
|
||||
# Generated demo compositions — large video-pipeline output (GSAP/Three/WebGL
|
||||
# embedded), not hand-authored source; reformatting them is churn + risk. Listed
|
||||
# explicitly (not registry/examples/**/*.html) so hand-authored example HTML still
|
||||
# gets formatted.
|
||||
registry/examples/airbnb-deck/index.html
|
||||
registry/examples/airbnb-deck/demo.html
|
||||
registry/examples/startup-pitch/index.html
|
||||
registry/examples/startup-pitch/demo.html
|
||||
registry/examples/slideshow-demo/index.html
|
||||
registry/examples/warm-grain/compositions/captions.html
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Adopters
|
||||
|
||||
This page lists organizations using HyperFrames in production or actively evaluating it. If your team is shipping with HyperFrames — whether you're rendering hundreds of videos a day, building agent-driven composition tooling, or experimenting with HTML-as-video for the first time — we'd love to hear about it.
|
||||
|
||||
Adding your organization helps the community understand how HyperFrames is being used in the wild and makes it easier for new users to find peers solving similar problems.
|
||||
|
||||
## How to add your organization
|
||||
|
||||
Open a pull request that adds a row to the table below. Keep entries short:
|
||||
|
||||
- **Organization** — your company or project name, linked to your website.
|
||||
- **Contact** — a GitHub handle or contact person who can answer questions about your usage.
|
||||
- **How HyperFrames is used** — one sentence on the use case (e.g., "Personalized video at scale," "Agent-authored marketing assets," "Slides-to-video pipeline").
|
||||
|
||||
If you'd rather not be listed publicly, that's fine — drop a note in [our Discord](https://discord.gg/EbK98HBPdk) instead. We always like hearing about how the project is being used.
|
||||
|
||||
## Production
|
||||
|
||||
| Organization | Contact | How HyperFrames is used |
|
||||
| ---------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
|
||||
| [HeyGen](https://www.heygen.com) | [@jrusso1020](https://github.com/jrusso1020) | Powers AI-generated video composition and rendering across HeyGen's video product surface. |
|
||||
| [tldraw](https://tldraw.com) | [@steveruizok](https://github.com/steveruizok) | Generates automated pull-request walkthrough videos with GSAP-animated code diffs, narration, and captions. |
|
||||
| [TanStack](https://tanstack.com) | [@AlemTuzlak](https://github.com/AlemTuzlak) | Exploring HyperFrames for short-form code demo videos and documentation. |
|
||||
| [OptinMonster](https://optinmonster.com) | Angie Meeker | Exploring HyperFrames for marketing and product video content. |
|
||||
| [reap](https://reap.video) | [@usamaabid](https://github.com/usamaabid) | Powers agent-first AI video clipping, editing, and rendering across reap.video's creator and agent workflows. |
|
||||
| [Typeframe](https://typeframe.app) | [@kiyeonjeon21](https://github.com/kiyeonjeon21) | Renders speech videos into shareable MP4 exports with word-timed typing captions and styled caption layouts. |
|
||||
@@ -0,0 +1,90 @@
|
||||
# Hyperframes
|
||||
|
||||
Open-source video rendering framework: write HTML, render video.
|
||||
|
||||
## Skills
|
||||
|
||||
This repo ships AI agent skills via [vercel-labs/skills](https://github.com/vercel-labs/skills). Install them before writing compositions — they encode framework-specific patterns that generic docs don't cover.
|
||||
|
||||
```bash
|
||||
npx skills add heygen-com/hyperframes
|
||||
```
|
||||
|
||||
**Creation workflows** route through one entry skill — read `/hyperframes` first: it orients you to the whole surface and maps "make me a…" intent — usually a video, but also a navigable deck (`/slideshow`) or a composition port (`/remotion-to-hyperframes`) — to a concrete workflow. Consult it before invoking a specific workflow:
|
||||
|
||||
- `/product-launch-video` — a **product** URL (or a pre-written script / text brief in no-capture mode) → product launch / promo video, up to ~3 min (sweet spot ~30-90s).
|
||||
- `/website-to-video` — a **general** website / URL → a video _of_ the site (tour / showcase / social clip from captured screenshots + assets); for a product **launch / promo**, use `/product-launch-video`.
|
||||
- `/faceless-explainer` — arbitrary text, **no URL and no website capture** → faceless explainer, up to ~3 min (sweet spot ~30-90s); every visual is LLM-invented (typography / abstract graphics / diagram / data-viz).
|
||||
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (verbatim rail + embedded climax, or pure-cinematic embed); the footage itself is untouched (no NLE-style editing).
|
||||
- `/talking-head-recut` — 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, footage untouched. For plain captions/subtitles → `/embedded-captions`.
|
||||
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → code-change explainer, up to ~3 min (changelog / feature reveal / fix / refactor). A PR link, not a product website.
|
||||
- `/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`.
|
||||
- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
|
||||
- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
|
||||
- `/general-video` — fallback for any other video creation (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes flow — design → plan → layout → build → validate, any length.
|
||||
|
||||
**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) video composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
|
||||
|
||||
## Build & Test
|
||||
|
||||
```bash
|
||||
bun install # Install dependencies (NOT pnpm — do not create pnpm-lock.yaml)
|
||||
bun run build # Build all packages
|
||||
bun run test # Run all tests
|
||||
```
|
||||
|
||||
### Linting & Formatting
|
||||
|
||||
Uses **oxlint** and **oxfmt** (not eslint, not prettier, not biome).
|
||||
|
||||
```bash
|
||||
bunx oxlint <files> # Lint
|
||||
bunx oxfmt <files> # Format
|
||||
bunx oxfmt --check <files> # Check formatting (CI / pre-commit)
|
||||
```
|
||||
|
||||
Always lint and format changed files before committing. Lefthook pre-commit hooks enforce this automatically.
|
||||
|
||||
### Composition Validation
|
||||
|
||||
After creating or editing any `.html` composition:
|
||||
|
||||
```bash
|
||||
npx hyperframes lint # Static HTML structure check
|
||||
npx hyperframes check # Browser gate (headless Chrome — runtime errors, layout, motion, WCAG contrast)
|
||||
```
|
||||
|
||||
Both must pass before previewing or considering work complete.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
packages/
|
||||
cli/ → hyperframes CLI (create, preview, lint, render)
|
||||
core/ → Types, parsers, generators, linter, runtime, frame adapters
|
||||
engine/ → Seekable page-to-video capture engine (Puppeteer + FFmpeg)
|
||||
player/ → Embeddable <hyperframes-player> web component
|
||||
producer/ → Full rendering pipeline (capture + encode + audio mix)
|
||||
shader-transitions/ → WebGL shader transitions for compositions
|
||||
studio/ → Browser-based composition editor UI
|
||||
registry/
|
||||
blocks/ → Installable sub-composition scenes (50+)
|
||||
components/ → Installable effects and snippets
|
||||
examples/ → Starter project templates
|
||||
docs/ → Mintlify documentation site (hyperframes.heygen.com)
|
||||
skills/ → AI agent skill definitions
|
||||
```
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- **Package manager**: bun (not pnpm, not npm for workspace operations)
|
||||
- **Commit format**: Conventional commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`)
|
||||
- **TypeScript**: Avoid `any` and `as T` assertions. Prefer type guards and narrowing.
|
||||
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. GSAP timelines must be paused and registered on `window.__timelines`.
|
||||
- **Frame Adapters**: Animation runtimes plug in via the seek-by-frame adapter pattern. GSAP is the primary adapter.
|
||||
- **Deterministic rendering**: No `Date.now()`, no unseeded `Math.random()`, no render-time network fetches.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Docs: https://hyperframes.heygen.com/introduction
|
||||
- Catalog (50+ blocks): https://hyperframes.heygen.com/catalog/blocks/data-chart
|
||||
@@ -0,0 +1,120 @@
|
||||
# Hyperframes
|
||||
|
||||
Open-source video rendering framework: write HTML, render video.
|
||||
|
||||
## Skills
|
||||
|
||||
This repo ships 20 AI agent skills via [vercel-labs/skills](https://github.com/vercel-labs/skills). Install them before writing compositions — they encode framework-specific patterns that generic docs don't cover.
|
||||
|
||||
```bash
|
||||
npx skills add heygen-com/hyperframes --full-depth # interactive picker
|
||||
npx skills add heygen-com/hyperframes --all --full-depth # install all 20 (skips picker)
|
||||
npx skills add heygen-com/hyperframes --skill <name> --full-depth # just one (bare name, no leading slash)
|
||||
```
|
||||
|
||||
Keep `--full-depth`: it installs the current `main`. Without it, `skills add` fetches the skills.sh registry blob, which lags `main` by hours (you'd get a stale skill). `hyperframes skills update` already uses full-depth.
|
||||
|
||||
**`/hyperframes` is the entry skill — read it first.** It's the capability map for the domain skills below AND the intent router for the creation workflows. The full README skills section mirrors this list; keep them in sync (see "Skill catalog maintenance" below).
|
||||
|
||||
### Creation workflows
|
||||
|
||||
- `/product-launch-video` — a **product** URL (or a pre-written script / text brief in no-capture mode) → product launch / promo video, up to ~3 min (sweet spot ~30-90s).
|
||||
- `/website-to-video` — a **general** website / URL → a video _of_ the site (tour / showcase / social clip from captured screenshots + assets); for a product **launch / promo**, use `/product-launch-video`.
|
||||
- `/faceless-explainer` — arbitrary text, **no URL and no website capture** → faceless explainer, up to ~3 min (sweet spot ~30-90s); every visual is LLM-invented (typography / abstract graphics / diagram / data-viz).
|
||||
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → code-change explainer, up to ~3 min (changelog / feature reveal / fix / refactor). A PR link, not a product website.
|
||||
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (verbatim rail + embedded climax, or pure-cinematic embed); the footage itself is untouched (no NLE-style editing).
|
||||
- `/talking-head-recut` — 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, footage untouched. For plain captions/subtitles → `/embedded-captions`.
|
||||
- `/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`.
|
||||
- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
|
||||
- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
|
||||
- `/general-video` — fallback for any other video creation (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes flow — design → plan → layout → build → validate, any length.
|
||||
- `/remotion-to-hyperframes` — port an existing Remotion (React) composition to HyperFrames HTML. One-way migration, not creation.
|
||||
|
||||
### Domain skills (loaded on demand)
|
||||
|
||||
Atomic capabilities the creation workflows compose against — pull one when you need that specific layer:
|
||||
|
||||
- `/hyperframes-core` — the composition contract: `data-*` timing attributes, `class="clip"`, tracks, sub-compositions, variables, framework-owned media playback, determinism rules. Read before writing composition HTML.
|
||||
- `/hyperframes-animation` — all animation knowledge: atomic motion rules, scene blueprints, transitions, runtime adapters (GSAP default, plus Lottie / Three.js / Anime.js / CSS / WAAPI / TypeGPU).
|
||||
- `/hyperframes-keyframes` — seek-safe keyframe authoring across runtimes: GSAP timelines, CSS keyframes, Anime.js, WAAPI, FLIP, paths, masks, SVG morph/draw, text trails, 3D depth; plus `hyperframes keyframes` diagnostics for surfacing and verifying rendered motion.
|
||||
- `/hyperframes-creative` — non-animation creative direction: `frame.md` / `design.md` handling, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns.
|
||||
- `/media-use` — the media OS: resolve any media need (BGM, SFX, image, icon, logo, voice, color grade, LUT) into a frozen local file or paste-ready block + ledger record; generate via TTS / music / image models when the catalog misses; transcribe, caption, remove backgrounds, and reuse assets across projects. One shared `scripts/audio.mjs` engine + manifest tracking; keeps search noise on disk.
|
||||
- `/hyperframes-cli` — CLI dev loop: `init`, `add`, `lint`, `check`, `snapshot`, `preview`, `render`, `publish`, `doctor`, `lambda` (AWS Lambda cloud rendering).
|
||||
- `/hyperframes-registry` — install and wire registry blocks and components into compositions via `hyperframes add`. Covers authoring a new block or component to contribute upstream.
|
||||
- `/figma` — import Figma assets, tokens, components, and storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI) plus Motion animations (MCP) and shaders (MCP source / native export) into a composition.
|
||||
|
||||
## Skill catalog maintenance
|
||||
|
||||
When adding a new skill, or substantially renaming / repurposing an existing one, update all agent-facing discoverability surfaces in lockstep:
|
||||
|
||||
1. The skill list above (CLAUDE.md) AND the workflow list in the root `AGENTS.md` (it carries workflows only, no domain-skill section) AND the `## Skills` section in `README.md` AND `docs/guides/skills.mdx` (rendered at [hyperframes.heygen.com/guides/skills](https://hyperframes.heygen.com/guides/skills)). Out-of-date entries silently kill discovery.
|
||||
2. The scaffolded project template `packages/cli/src/templates/_shared/CLAUDE.md` + `AGENTS.md` — written into every `hyperframes init` project, so a stale entry there ships to users. The two template files must stay byte-identical.
|
||||
3. If the skill changes the routing surface for "make a video" requests, also update the capability map and intent router in `skills/hyperframes/SKILL.md` — that's the canonical router agents read first.
|
||||
4. Mirror the Router / Creation workflows / Domain skills grouping across all surfaces so a skill always lives in the same column.
|
||||
5. Skill count appears in the README and CLAUDE.md intro lines ("20 AI agent skills…") — update on add/remove. The `docs/guides/skills.mdx` page and the CLI templates deliberately omit a count to avoid drift; keep them count-free.
|
||||
|
||||
The skill's own `SKILL.md` frontmatter `description:` is the source of truth for the one-line "use when" blurb; copy from there into the catalog rather than paraphrasing.
|
||||
|
||||
## Build & Test
|
||||
|
||||
```bash
|
||||
bun install # Install dependencies (NOT pnpm — do not create pnpm-lock.yaml)
|
||||
bun run build # Build all packages
|
||||
bun run test # Run all tests
|
||||
```
|
||||
|
||||
### Linting & Formatting
|
||||
|
||||
Uses **oxlint** and **oxfmt** (not eslint, not prettier, not biome).
|
||||
|
||||
```bash
|
||||
bunx oxlint <files> # Lint
|
||||
bunx oxfmt <files> # Format
|
||||
bunx oxfmt --check <files> # Check formatting (CI / pre-commit)
|
||||
```
|
||||
|
||||
Always lint and format changed files before committing. Lefthook pre-commit hooks enforce this automatically.
|
||||
|
||||
### Composition Validation
|
||||
|
||||
After creating or editing any `.html` composition:
|
||||
|
||||
```bash
|
||||
npx hyperframes lint # Static HTML structure check
|
||||
npx hyperframes check # Browser gate (headless Chrome — runtime errors, layout, motion, WCAG contrast)
|
||||
```
|
||||
|
||||
Both must pass before previewing or considering work complete.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
packages/
|
||||
cli/ → hyperframes CLI (create, preview, lint, render)
|
||||
core/ → Types, parsers, generators, linter, runtime, frame adapters
|
||||
engine/ → Seekable page-to-video capture engine (Puppeteer + FFmpeg)
|
||||
player/ → Embeddable <hyperframes-player> web component
|
||||
producer/ → Full rendering pipeline (capture + encode + audio mix)
|
||||
shader-transitions/ → WebGL shader transitions for compositions
|
||||
studio/ → Browser-based composition editor UI
|
||||
registry/
|
||||
blocks/ → Installable sub-composition scenes (50+)
|
||||
components/ → Installable effects and snippets
|
||||
examples/ → Starter project templates
|
||||
docs/ → Mintlify documentation site (hyperframes.heygen.com)
|
||||
skills/ → AI agent skill definitions
|
||||
```
|
||||
|
||||
## Key Conventions
|
||||
|
||||
- **Package manager**: bun (not pnpm, not npm for workspace operations)
|
||||
- **Commit format**: Conventional commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`)
|
||||
- **TypeScript**: Avoid `any` and `as T` assertions. Prefer type guards and narrowing.
|
||||
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. GSAP timelines must be paused and registered on `window.__timelines`.
|
||||
- **Frame Adapters**: Animation runtimes plug in via the seek-by-frame adapter pattern. GSAP is the primary adapter.
|
||||
- **Deterministic rendering**: No `Date.now()`, no unseeded `Math.random()`, no render-time network fetches.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Docs: https://hyperframes.heygen.com/introduction
|
||||
- Catalog (50+ blocks): https://hyperframes.heygen.com/catalog/blocks/data-chart
|
||||
@@ -0,0 +1,40 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior:
|
||||
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the project maintainers via [GitHub Issues](https://github.com/heygen-com/hyperframes/issues). All complaints will
|
||||
be reviewed and investigated promptly and fairly.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
# Contributing to Hyperframes
|
||||
|
||||
Thanks for your interest in contributing to Hyperframes! This guide will help you get started.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Fork the repository
|
||||
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/hyperframes.git`
|
||||
3. Install dependencies: `bun install`
|
||||
4. Create a branch: `git checkout -b my-feature`
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
bun install # Install all dependencies
|
||||
bun run dev # Run the studio (composition editor)
|
||||
bun run build # Build all packages
|
||||
bun run --filter '*' typecheck # Type-check all packages
|
||||
bun run lint # Lint all packages
|
||||
bun run format:check # Check formatting
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
bun run --filter @hyperframes/core test # Core unit tests (vitest)
|
||||
bun run --filter @hyperframes/engine test # Engine unit tests (vitest)
|
||||
bun run --filter @hyperframes/core test:hyperframe-runtime-ci # Runtime contract tests
|
||||
```
|
||||
|
||||
### Linting & Formatting
|
||||
|
||||
```bash
|
||||
bun run lint # Run oxlint
|
||||
bun run lint:fix # Run oxlint with auto-fix
|
||||
bun run format # Format all files with oxfmt
|
||||
bun run format:check # Check formatting without writing
|
||||
```
|
||||
|
||||
Git hooks (via [lefthook](https://github.com/evilmartians/lefthook)) run automatically after `bun install` and enforce linting + formatting on staged files before each commit.
|
||||
|
||||
#### Type-safety conventions
|
||||
|
||||
We aim for honest types — code that lies to the compiler eventually lies to users. The underlying convention is:
|
||||
|
||||
- **Avoid `any`.** Use `unknown` and narrow it where possible.
|
||||
- **Avoid `as T` type assertions.** They suppress type-checker warnings without telling the compiler anything new. Prefer:
|
||||
- Type guards (`function isFoo(x): x is Foo`)
|
||||
- `instanceof` / `typeof` narrowing
|
||||
- Centralized narrowing helpers (e.g. `resolveIframe`)
|
||||
- Properly-typed interfaces at the source
|
||||
- **Acceptable `as` use, with a comment explaining why:**
|
||||
- `as const` — literal narrowing; always safe
|
||||
- `as unknown as T` — explicit double-cast at hard type-system boundaries (e.g. parsing untrusted JSON, FFI/postMessage). Pair with a one-line justification.
|
||||
- **Avoid `!` non-null assertions** outside of post-`if`-checked code paths. Use `??` defaults or guard clauses instead.
|
||||
|
||||
If you must add a cast, add a comment:
|
||||
|
||||
```ts
|
||||
// `postMessage` data is `unknown`; the runtime guarantees this shape.
|
||||
const event = data as unknown as RuntimeEvent;
|
||||
```
|
||||
|
||||
## Adding Registry Items (Blocks & Components)
|
||||
|
||||
The registry at `registry/` contains reusable items installable via `hyperframes add <name>`. Each item lives in its own directory under `registry/blocks/` or `registry/components/`.
|
||||
|
||||
### Directory structure
|
||||
|
||||
```
|
||||
registry/blocks/<name>/
|
||||
registry-item.json # Manifest (name, type, description, tags, files)
|
||||
<name>.html # The composition HTML
|
||||
|
||||
registry/components/<name>/
|
||||
registry-item.json # Manifest (no dimensions/duration for components)
|
||||
<name>.html # The snippet HTML to paste into a composition
|
||||
demo.html # Required — standalone demo showing the effect
|
||||
```
|
||||
|
||||
### The `demo.html` convention
|
||||
|
||||
Every **component** must ship a companion `demo.html`. This file:
|
||||
|
||||
1. Is a complete, standalone HTML document (with `<!doctype html>`, GSAP CDN, etc.)
|
||||
2. Shows the component effect applied to representative content
|
||||
3. Registers a GSAP timeline on `window.__timelines` so it can be previewed in the Studio and rendered by the CI preview pipeline
|
||||
4. Uses `data-composition-id="<name>-demo"` to avoid ID collisions
|
||||
|
||||
Blocks don't need `demo.html` — they are already standalone compositions.
|
||||
|
||||
### Checklist for new items
|
||||
|
||||
1. Create `registry/<blocks|components>/<name>/registry-item.json` following the [schema](packages/core/schemas/registry-item.json)
|
||||
2. Add the item to `registry/registry.json`
|
||||
3. For components: include a `demo.html`
|
||||
4. Run `npx hyperframes lint` and `npx hyperframes validate` on your HTML
|
||||
5. Test the install flow: `hyperframes add <name> --dir /tmp/test-project`
|
||||
|
||||
### Auto-generated docs
|
||||
|
||||
When you add a new block or component, its documentation page is generated automatically — you don't need to write MDX by hand.
|
||||
|
||||
Run the codegen script after adding items:
|
||||
|
||||
```bash
|
||||
npx tsx scripts/generate-catalog-pages.ts
|
||||
```
|
||||
|
||||
This produces:
|
||||
|
||||
- `docs/catalog/blocks/<name>.mdx` — per-block detail page
|
||||
- `docs/catalog/components/<name>.mdx` — per-component detail page
|
||||
- `docs/public/catalog-index.json` — flat manifest for the catalog grid page
|
||||
- Updates `docs/docs.json` navigation with the new pages
|
||||
|
||||
The script wipes `docs/catalog/` before regenerating, so deleted items are automatically cleaned up.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
- Use [conventional commit](https://www.conventionalcommits.org/) format for **all commits** (e.g., `feat: add timeline export`, `fix: resolve seek overflow`). Enforced by a git hook.
|
||||
- CI must pass before merge (build, typecheck, tests, semantic PR title)
|
||||
- PRs require at least 1 approval
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Description |
|
||||
| ----------------------- | ------------------------------------------- |
|
||||
| `@hyperframes/core` | Types, HTML generation, runtime, linter |
|
||||
| `@hyperframes/engine` | Seekable page-to-video capture engine |
|
||||
| `@hyperframes/producer` | Full rendering pipeline (capture + encode) |
|
||||
| `@hyperframes/studio` | Composition editor UI |
|
||||
| `hyperframes` | CLI for creating, previewing, and rendering |
|
||||
|
||||
## Releasing (Maintainers)
|
||||
|
||||
All packages use **fixed versioning** — every release bumps all packages to the same version.
|
||||
|
||||
### Stable releases
|
||||
|
||||
```bash
|
||||
bun run release:prepare 0.2.0 # drafts changelog if needed, then creates the release commit/tag after review
|
||||
git push origin main # push the release commit
|
||||
git push origin v0.2.0 # push the tag → triggers the publish workflow
|
||||
```
|
||||
|
||||
> Push the **specific tag**, not `git push --tags` — the latter pushes every local tag and the whole push is rejected if any one already exists on the remote.
|
||||
|
||||
The `release:prepare` script drafts missing release notes on the first run and stops for manual review. After the generated TODO summary is rewritten, rerun the same command; it delegates to `set-version`, which creates a `chore: release v<version>` commit and a `v<version>` git tag. Pushing the tag triggers CI to publish all packages to npm and create a GitHub Release.
|
||||
|
||||
`set-version` also refuses to tag if a **higher** semver tag already exists (a stale higher tag would hijack tag-sorting installers like `npx skills`). Delete the stray tag (`git tag -d <tag> && git push origin :refs/tags/<tag>`) or, only if intentional, pass `--skip-monotonicity-check`.
|
||||
|
||||
### Pre-releases (alpha / beta / rc)
|
||||
|
||||
Use a pre-release suffix to publish to a named npm dist-tag instead of `latest`:
|
||||
|
||||
```bash
|
||||
bun run set-version 0.2.0-alpha.1 # first alpha
|
||||
git push origin v0.2.0-alpha.1 # publishes to npm with --tag alpha
|
||||
|
||||
bun run set-version 0.2.0-alpha.2 # iterate
|
||||
bun run set-version 0.2.0-beta.1 # promote to beta (--tag beta)
|
||||
bun run set-version 0.2.0-rc.1 # release candidate (--tag rc)
|
||||
bun run set-version 0.2.0 # final stable release (--tag latest)
|
||||
```
|
||||
|
||||
Consumers install pre-releases with `npm install @hyperframes/core@alpha` (or `@beta`, `@rc`). The `latest` tag is never touched by pre-releases, so `npm install @hyperframes/core` always gets the last stable version.
|
||||
|
||||
Pre-releases also create GitHub Releases marked as **pre-release**.
|
||||
|
||||
### Options
|
||||
|
||||
If you need to bump versions without committing (e.g., for a release PR), pass `--no-tag`:
|
||||
|
||||
```bash
|
||||
bun run set-version 0.2.0 --no-tag # updates package.json files only
|
||||
```
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
- Use [GitHub Issues](https://github.com/heygen-com/hyperframes/issues) for bug reports and feature requests
|
||||
- Search existing issues before creating a new one
|
||||
- Include reproduction steps for bugs
|
||||
|
||||
## AI-Assisted Contributions
|
||||
|
||||
We welcome contributions that use AI tools (GitHub Copilot, Claude, ChatGPT, etc.). If you used AI to help write a PR, there is no need to disclose it — we review all code on its merits. However:
|
||||
|
||||
- You are responsible for the correctness of any code you submit, regardless of how it was generated.
|
||||
- AI-generated tests must actually test meaningful behavior, not just assert truthy values.
|
||||
- Do not submit AI-generated code you don't understand. If you can't explain what a change does during review, it will be rejected.
|
||||
|
||||
## Governance
|
||||
|
||||
Hyperframes uses a **BDFL (Benevolent Dictator for Life)** governance model. The core maintainers at HeyGen have final say on the project's direction, API design, and what gets merged. This keeps the project focused and moving fast.
|
||||
|
||||
Community input is valued and encouraged — open issues, propose RFCs, and discuss in PRs. But final decisions rest with the maintainers.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the project's license. See [LICENSE](LICENSE) for details.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# Credits
|
||||
|
||||
## Prior art
|
||||
|
||||
HyperFrames was inspired by prior work in the browser-based video rendering space.
|
||||
In particular, we want to acknowledge:
|
||||
|
||||
- **[Remotion](https://www.remotion.dev)** pioneered the approach of using a
|
||||
headless browser + FFmpeg `image2pipe` pipeline to turn web primitives into
|
||||
deterministic video in the JavaScript ecosystem. Several of HyperFrames'
|
||||
architectural ideas — ordered async barriers for parallel frame capture,
|
||||
multi-host port availability probing for dev servers, and the broader shape
|
||||
of a "render HTML to video" CLI — were informed by studying how Remotion
|
||||
approaches these problems.
|
||||
|
||||
All code in this repository is independently implemented and distributed
|
||||
under the [Apache 2.0 License](LICENSE). HyperFrames is not affiliated with
|
||||
Remotion.
|
||||
|
||||
## Thanks
|
||||
|
||||
Thanks also to the authors and maintainers of the open-source projects
|
||||
HyperFrames builds on, including Puppeteer, FFmpeg, GSAP, Hono, and the
|
||||
broader Node.js ecosystem.
|
||||
|
||||
## Third-party licenses
|
||||
|
||||
- **[mediabunny](https://github.com/nicoch/mediabunny)** — media toolkit used
|
||||
in the studio for fast metadata extraction from file headers. Licensed under
|
||||
the [Mozilla Public License 2.0 (MPL-2.0)](https://mozilla.org/MPL/2.0/).
|
||||
@@ -0,0 +1,301 @@
|
||||
# HyperFrames Design System & Style Guide
|
||||
|
||||
Use this guide to configure Mintlify docs or any other platform to match the HyperFrames brand.
|
||||
|
||||
---
|
||||
|
||||
## Color Palette
|
||||
|
||||
### Light Mode
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ------------------ | --------- | ------------------------------------------------ |
|
||||
| `--bg` | `#f6f5f1` | Page background |
|
||||
| `--surface` | `#ffffff` | Cards, panels, elevated surfaces |
|
||||
| `--surface2` | `#eeedea` | Secondary surfaces, timeline, subtle backgrounds |
|
||||
| `--border` | `#e0dfdb` | Default borders |
|
||||
| `--border-light` | `#d0cfcb` | Hover/active borders |
|
||||
| `--text` | `#1a1a1a` | Primary body text |
|
||||
| `--text-secondary` | `#6b6b6b` | Secondary/muted text |
|
||||
| `--text-tertiary` | `#999999` | Tertiary/placeholder text |
|
||||
| `--heading` | `#0a0a0a` | Headings, nav brand, buttons |
|
||||
| `--code-bg` | `#ffffff` | Code block backgrounds |
|
||||
|
||||
#### Accent Colors (Light)
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ------------------------ | ----------------------- | ---------------------------- |
|
||||
| `--accent-green` | `#1a7a0a` | Success, recommended badges |
|
||||
| `--accent-green-light` | `rgba(26,122,10,0.07)` | Green badge backgrounds |
|
||||
| `--accent-green-border` | `rgba(26,122,10,0.25)` | Green badge borders |
|
||||
| `--accent-blue` | `#2563eb` | Links, info badges |
|
||||
| `--accent-blue-light` | `rgba(37,99,235,0.06)` | Blue badge backgrounds |
|
||||
| `--accent-blue-border` | `rgba(37,99,235,0.2)` | Blue badge borders |
|
||||
| `--accent-purple` | `#7c3aed` | Highlights, special elements |
|
||||
| `--accent-purple-light` | `rgba(124,58,237,0.06)` | Purple badge backgrounds |
|
||||
| `--accent-purple-border` | `rgba(124,58,237,0.2)` | Purple badge borders |
|
||||
|
||||
#### Syntax Highlighting (Light)
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ---------------------- | --------- | ------------------------------- |
|
||||
| `--syntax-keyword` | `#9333ea` | Keywords (const, let, function) |
|
||||
| `--syntax-function` | `#0891b2` | Function names |
|
||||
| `--syntax-string` | `#16a34a` | Strings, values |
|
||||
| `--syntax-number` | `#d97706` | Numbers |
|
||||
| `--syntax-property` | `#6366f1` | Object properties |
|
||||
| `--syntax-punctuation` | `#aaaaaa` | Brackets, semicolons |
|
||||
| `--syntax-tag` | `#b45309` | HTML/JSX tags |
|
||||
| `--syntax-attribute` | `#555555` | HTML attributes |
|
||||
| `--syntax-comment` | `#bbbbbb` | Comments |
|
||||
|
||||
---
|
||||
|
||||
### Dark Mode
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ------------------ | --------- | -------------------------------- |
|
||||
| `--bg` | `#0a0a0a` | Page background |
|
||||
| `--surface` | `#141414` | Cards, panels, elevated surfaces |
|
||||
| `--surface2` | `#1a1a1a` | Secondary surfaces |
|
||||
| `--border` | `#2a2a2a` | Default borders |
|
||||
| `--border-light` | `#3a3a3a` | Hover/active borders |
|
||||
| `--text` | `#e5e5e5` | Primary body text |
|
||||
| `--text-secondary` | `#a0a0a0` | Secondary/muted text |
|
||||
| `--text-tertiary` | `#666666` | Tertiary/placeholder text |
|
||||
| `--heading` | `#f5f5f5` | Headings |
|
||||
| `--code-bg` | `#141414` | Code block backgrounds |
|
||||
|
||||
#### Accent Colors (Dark)
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ------------------------ | ----------------------- | ---------------------------- |
|
||||
| `--accent-green` | `#22c55e` | Success, recommended badges |
|
||||
| `--accent-green-light` | `rgba(34,197,94,0.1)` | Green badge backgrounds |
|
||||
| `--accent-green-border` | `rgba(34,197,94,0.3)` | Green badge borders |
|
||||
| `--accent-blue` | `#3b82f6` | Links, info badges |
|
||||
| `--accent-blue-light` | `rgba(59,130,246,0.1)` | Blue badge backgrounds |
|
||||
| `--accent-blue-border` | `rgba(59,130,246,0.3)` | Blue badge borders |
|
||||
| `--accent-purple` | `#a78bfa` | Highlights, special elements |
|
||||
| `--accent-purple-light` | `rgba(167,139,250,0.1)` | Purple badge backgrounds |
|
||||
| `--accent-purple-border` | `rgba(167,139,250,0.3)` | Purple badge borders |
|
||||
|
||||
#### Syntax Highlighting (Dark)
|
||||
|
||||
| Token | Hex | Usage |
|
||||
| ---------------------- | --------- | -------------------- |
|
||||
| `--syntax-keyword` | `#c084fc` | Keywords |
|
||||
| `--syntax-function` | `#22d3ee` | Function names |
|
||||
| `--syntax-string` | `#4ade80` | Strings, values |
|
||||
| `--syntax-number` | `#fbbf24` | Numbers |
|
||||
| `--syntax-property` | `#818cf8` | Object properties |
|
||||
| `--syntax-punctuation` | `#666666` | Brackets, semicolons |
|
||||
| `--syntax-tag` | `#fb923c` | HTML/JSX tags |
|
||||
| `--syntax-attribute` | `#a0a0a0` | HTML attributes |
|
||||
| `--syntax-comment` | `#555555` | Comments |
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Families
|
||||
|
||||
| Token | Stack | Usage |
|
||||
| ---------------- | ----------------------------------------------------------------------------- | ---------------------- |
|
||||
| `--font-display` | `'ABC Solar Display', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif` | Headlines, nav brand |
|
||||
| `--font-body` | `'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif` | Body text, UI elements |
|
||||
| `--font-mono` | `'IBM Plex Mono', 'SF Mono', 'Fira Code', monospace` | Code, terminals |
|
||||
|
||||
### Google Fonts Import
|
||||
|
||||
```css
|
||||
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Inter:wght@300;400;500;600;700&display=swap");
|
||||
```
|
||||
|
||||
### Type Scale
|
||||
|
||||
| Element | Size | Weight | Letter Spacing | Line Height |
|
||||
| ---------- | ------------------------------ | ------ | -------------- | ----------- |
|
||||
| H1 | `clamp(2.6rem, 6vw, 4.5rem)` | 400 | `-0.02em` | 1.0 |
|
||||
| H2 | `clamp(1.6rem, 3.5vw, 2.2rem)` | 400 | `-0.02em` | 1.2 |
|
||||
| H3 | `1rem` | 600 | `-0.01em` | 1.4 |
|
||||
| Body | `1rem` | 400 | `normal` | 1.6 |
|
||||
| Body Small | `0.95rem` | 400 | `normal` | 1.7 |
|
||||
| Caption | `0.82rem` | 400 | `normal` | 1.6 |
|
||||
| Code | `0.75rem` | 400 | `normal` | 1.9 |
|
||||
| Mono Small | `0.65rem` | 500 | `normal` | 1.6 |
|
||||
|
||||
---
|
||||
|
||||
## Spacing
|
||||
|
||||
| Token | Value | Usage |
|
||||
| ----- | --------------- | ------------------- |
|
||||
| `xs` | `0.25rem` (4px) | Tight gaps |
|
||||
| `sm` | `0.5rem` (8px) | Small gaps |
|
||||
| `md` | `1rem` (16px) | Default gaps |
|
||||
| `lg` | `1.5rem` (24px) | Section gaps |
|
||||
| `xl` | `2rem` (32px) | Large spacing |
|
||||
| `2xl` | `4rem` (64px) | Section padding |
|
||||
| `3xl` | `8rem` (128px) | Hero/footer padding |
|
||||
|
||||
---
|
||||
|
||||
## Border Radius
|
||||
|
||||
| Token | Value | Usage |
|
||||
| ----- | --------------- | ---------------------- |
|
||||
| `sm` | `4px` | Badges, small elements |
|
||||
| `md` | `6px` | Buttons, inputs |
|
||||
| `lg` | `8px` | Cards, panels |
|
||||
| `xl` | `10px` - `12px` | Large cards |
|
||||
|
||||
---
|
||||
|
||||
## Shadows & Effects
|
||||
|
||||
- **No heavy shadows** — HyperFrames uses a flat, minimal aesthetic
|
||||
- **Borders over shadows** — Use `1px solid var(--border)` instead of box-shadows
|
||||
- **Backdrop blur** for nav: `backdrop-filter: blur(12px)`
|
||||
- **Selection color**: `rgba(128,128,128,0.2)` (light) / `rgba(255,255,255,0.15)` (dark)
|
||||
|
||||
---
|
||||
|
||||
## Mintlify Configuration
|
||||
|
||||
The docs site at `docs/docs.json` implements this design system. Key settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"theme": "maple",
|
||||
"colors": {
|
||||
"primary": "#0a0a0a",
|
||||
"light": "#f6f5f1",
|
||||
"dark": "#0a0a0a"
|
||||
},
|
||||
"background": {
|
||||
"color": {
|
||||
"light": "#f6f5f1",
|
||||
"dark": "#0a0a0a"
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"family": "Inter",
|
||||
"heading": { "family": "Inter" }
|
||||
},
|
||||
"appearance": {
|
||||
"default": "light"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additional overrides (code font, CSS variables, heading tracking) live in `docs/custom.css`.
|
||||
|
||||
---
|
||||
|
||||
## Component Patterns
|
||||
|
||||
### Cards
|
||||
|
||||
```css
|
||||
.card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: var(--border-light);
|
||||
}
|
||||
```
|
||||
|
||||
### Buttons
|
||||
|
||||
```css
|
||||
.btn-primary {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 6px;
|
||||
background: var(--heading);
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .btn-primary {
|
||||
background: var(--heading);
|
||||
color: #0a0a0a;
|
||||
}
|
||||
```
|
||||
|
||||
### Code Blocks / Terminals
|
||||
|
||||
```css
|
||||
.terminal {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.terminal-bar {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.terminal-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--border-light);
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
padding: 0.85rem 1.1rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
line-height: 1.9;
|
||||
}
|
||||
```
|
||||
|
||||
### Badges
|
||||
|
||||
```css
|
||||
.badge-green {
|
||||
color: var(--accent-green);
|
||||
background: var(--accent-green-light);
|
||||
border: 1px solid var(--accent-green-border);
|
||||
}
|
||||
|
||||
.badge-blue {
|
||||
color: var(--accent-blue);
|
||||
background: var(--accent-blue-light);
|
||||
border: 1px solid var(--accent-blue-border);
|
||||
}
|
||||
|
||||
.badge-purple {
|
||||
color: var(--accent-purple);
|
||||
background: var(--accent-purple-light);
|
||||
border: 1px solid var(--accent-purple-border);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Animation Guidelines
|
||||
|
||||
- **Duration**: 0.15s - 0.2s for micro-interactions, 0.5s for reveals
|
||||
- **Easing**: `ease` or `ease-out` for most transitions
|
||||
- **Hover states**: Use `opacity: 0.85` or border color changes
|
||||
- **Scroll reveals**: `translateY(20px)` with opacity fade
|
||||
|
||||
---
|
||||
|
||||
## Brand Assets
|
||||
|
||||
- **Logo**: "HyperFrames" in `--font-display` at 600 weight
|
||||
- **Primary color**: `#0a0a0a` (near-black)
|
||||
- **Warm neutral palette**: Beige/cream tones, not pure grays
|
||||
@@ -0,0 +1,148 @@
|
||||
# Documentation Guidelines
|
||||
|
||||
Standards for writing and maintaining Hyperframes documentation. Based on patterns from Remotion, Stripe, Tailwind CSS, and Astro.
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **One-sentence intro rule** — Every page opens with a single sentence telling the reader what this page helps them do or understand. No preamble, no history.
|
||||
|
||||
2. **Outcome before implementation** — Show what the code produces (rendered result, terminal output, file structure) before showing the code itself.
|
||||
|
||||
3. **Show, don't tell** — Use concrete examples with realistic values. Never use `foo`/`bar`/`baz`. Prefer a working HTML snippet over a description of what to write.
|
||||
|
||||
4. **Two content modes** — Guides build narratives with progressive complexity. References enable scanning with standardized structure. Never mix them.
|
||||
|
||||
5. **No dead ends** — Every page links forward (next steps), backward (prerequisites), and sideways (related concepts). Readers should never reach a page with nowhere to go.
|
||||
|
||||
## Page Structure
|
||||
|
||||
### Guides (concepts/, guides/)
|
||||
|
||||
```
|
||||
Title
|
||||
├── One-sentence purpose statement
|
||||
├── What this looks like (output, demo, or visual)
|
||||
├── Minimal working example
|
||||
├── Deeper explanation with progressive complexity
|
||||
├── Common patterns / best practices
|
||||
├── Warnings and pitfalls (sparingly)
|
||||
└── Next steps (cards or links to related pages)
|
||||
```
|
||||
|
||||
### Reference pages (reference/)
|
||||
|
||||
```
|
||||
Title
|
||||
├── One-sentence definition
|
||||
├── Complete attribute/API table
|
||||
├── Detailed section per item (type, default, description, example)
|
||||
├── Rules and constraints
|
||||
└── Related pages
|
||||
```
|
||||
|
||||
### Package pages (packages/)
|
||||
|
||||
```
|
||||
Title
|
||||
├── One-line description + install command
|
||||
├── When to use this package (and when NOT to)
|
||||
├── Key features list
|
||||
├── Minimal usage example with expected output
|
||||
├── Configuration reference
|
||||
└── Related packages
|
||||
```
|
||||
|
||||
## Writing Style
|
||||
|
||||
- **Second person, active voice, imperative mood**: "Use X to do Y." Not "The developer should consider using X."
|
||||
- **Present tense**: "The runtime manages media playback." Not "The runtime will manage..."
|
||||
- **Be direct**: "This breaks rendering." Not "This may potentially cause issues with the rendering pipeline."
|
||||
- **Prerequisites at point of need**: State requirements where they matter, not in a wall at the top.
|
||||
- **Conversational but precise**: Friendly tone, exact technical details.
|
||||
|
||||
## Code Examples
|
||||
|
||||
### Always annotate code blocks
|
||||
|
||||
```mdx
|
||||
```html index.html
|
||||
<div data-composition-id="root" ...>
|
||||
```
|
||||
```
|
||||
|
||||
The filename after the language tag tells readers where the code goes.
|
||||
|
||||
### Use numbered comments for multi-step code
|
||||
|
||||
```javascript
|
||||
// 1. Create a paused timeline
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
// 2. Add animations
|
||||
tl.from("#title", { opacity: 0, y: -50, duration: 1 }, 0);
|
||||
|
||||
// 3. Register the timeline
|
||||
window.__timelines["my-video"] = tl;
|
||||
```
|
||||
|
||||
### Show expected output
|
||||
|
||||
After CLI commands, show what the user should see:
|
||||
|
||||
```bash
|
||||
npx hyperframes preview
|
||||
# ✓ Server running at http://localhost:3000
|
||||
# ✓ Watching for changes...
|
||||
```
|
||||
|
||||
### Use CodeGroup for multi-platform commands
|
||||
|
||||
```mdx
|
||||
<CodeGroup>
|
||||
```bash macOS
|
||||
brew install ffmpeg
|
||||
```
|
||||
```bash Ubuntu
|
||||
sudo apt install ffmpeg
|
||||
```
|
||||
</CodeGroup>
|
||||
```
|
||||
|
||||
## Mintlify Components — When to Use
|
||||
|
||||
| Component | Use When |
|
||||
|-----------|----------|
|
||||
| `<Steps>` | Sequential setup or tutorial instructions |
|
||||
| `<CodeGroup>` | Same action across platforms/languages |
|
||||
| `<Tabs>` | Alternative approaches with equal weight |
|
||||
| `<Card>` / `<Columns>` | Navigation to related pages, next steps |
|
||||
| `<Accordion>` | FAQ or optional detail that would bloat the page |
|
||||
| `<Note>` | Non-obvious behavior the reader should know |
|
||||
| `<Warning>` | Something that will break if ignored |
|
||||
| `<Tip>` | Helpful shortcut or best practice |
|
||||
| `<Info>` | Context that aids understanding |
|
||||
| `<Tree>` | File/directory structure |
|
||||
| `<Frame>` | Screenshots or diagrams with captions |
|
||||
|
||||
### Callout budget: max 2-3 per page
|
||||
|
||||
More than 3 callouts creates alert fatigue and readers skip them all. Reserve `<Warning>` for things that genuinely break. Use inline prose for tips.
|
||||
|
||||
## Cross-Linking
|
||||
|
||||
- **Link at the point of curiosity**: When you mention a concept that has its own page, link it immediately. Don't hoard links.
|
||||
- **"See also" at page bottom**: Only for genuinely related content that doesn't fit inline.
|
||||
- **Next steps cards**: End guide pages with `<Card>` links to logical next pages.
|
||||
|
||||
## File Conventions
|
||||
|
||||
- All doc pages are `.mdx` (not `.md`)
|
||||
- Use kebab-case for filenames: `frame-adapters.mdx`, not `frameAdapters.mdx`
|
||||
- Frontmatter requires `title` and `description`
|
||||
- Description should be under 160 characters (used for SEO/social)
|
||||
|
||||
## Maintenance
|
||||
|
||||
- Docs live in the repo at `/docs` and deploy automatically on merge to `main`
|
||||
- PRs that change user-facing behavior should update relevant doc pages
|
||||
- Run `mint validate` and `mint broken-links` before pushing doc changes
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
# HyperFrames Producer - Regression Test Image
|
||||
#
|
||||
# Matches the production rendering environment (same Chromium, fonts, FFmpeg)
|
||||
# but includes the full source + devDependencies for running the test harness.
|
||||
#
|
||||
# This ensures golden baselines match what production actually renders.
|
||||
#
|
||||
# Usage:
|
||||
# docker build -f Dockerfile.test -t hyperframes-producer:test .
|
||||
# docker run --rm -v ./packages/producer/tests:/app/packages/producer/tests hyperframes-producer:test
|
||||
# docker run --rm -v ./packages/producer/tests:/app/packages/producer/tests hyperframes-producer:test --update
|
||||
|
||||
FROM node:22-bookworm-slim
|
||||
|
||||
# ── System dependencies (identical to production) ────────────────────────────
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
unzip \
|
||||
ffmpeg \
|
||||
chromium \
|
||||
libgbm1 \
|
||||
libnss3 \
|
||||
libatk-bridge2.0-0 \
|
||||
libdrm2 \
|
||||
libxcomposite1 \
|
||||
libxdamage1 \
|
||||
libxrandr2 \
|
||||
libcups2 \
|
||||
libasound2 \
|
||||
libpangocairo-1.0-0 \
|
||||
libxshmfence1 \
|
||||
libgtk-3-0 \
|
||||
# Font support — matches production
|
||||
fonts-liberation \
|
||||
fonts-noto-color-emoji \
|
||||
fonts-noto-cjk \
|
||||
fonts-noto-core \
|
||||
fonts-noto-extra \
|
||||
fonts-noto-ui-core \
|
||||
fonts-freefont-ttf \
|
||||
fonts-dejavu-core \
|
||||
fontconfig \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean \
|
||||
&& fc-cache -fv
|
||||
|
||||
# Use system Chromium (same as production)
|
||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
||||
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||
ENV CONTAINER=true
|
||||
|
||||
# Install chrome-headless-shell for deterministic BeginFrame rendering.
|
||||
# This lightweight Chrome binary supports HeadlessExperimental.beginFrame.
|
||||
# Install to ~/.cache/puppeteer/ where resolveHeadlessShellPath() looks.
|
||||
#
|
||||
# Pinned to a specific build (NOT @stable) so the regression-test golden
|
||||
# baselines in packages/producer/tests/*/output/output.mp4 stay reproducible.
|
||||
# Each Chrome stable bump shifts pixel output enough to fail PSNR. Bump this
|
||||
# version together with regenerating baselines via `docker:test:update`.
|
||||
RUN npx --yes @puppeteer/browsers install chrome-headless-shell@148.0.7778.167 \
|
||||
--path /root/.cache/puppeteer \
|
||||
&& find /root/.cache/puppeteer/chrome-headless-shell -name "chrome-headless-shell" -type f \
|
||||
&& echo "chrome-headless-shell installed"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install bun
|
||||
RUN curl -fsSL https://bun.sh/install | BUN_INSTALL="/root/.bun" bash -s "bun-v1.3.13"
|
||||
ENV PATH="/root/.bun/bin:$PATH"
|
||||
|
||||
# Install dependencies (full, including devDependencies for tsx + test harness).
|
||||
# Every workspace member (packages/*) must be COPYed here — `bun install
|
||||
# --frozen-lockfile` treats any member missing from the build context as a
|
||||
# lockfile change and fails.
|
||||
COPY package.json bun.lock ./
|
||||
COPY packages/parsers/package.json packages/parsers/package.json
|
||||
COPY packages/lint/package.json packages/lint/package.json
|
||||
COPY packages/studio-server/package.json packages/studio-server/package.json
|
||||
COPY packages/core/package.json packages/core/package.json
|
||||
COPY packages/engine/package.json packages/engine/package.json
|
||||
COPY packages/player/package.json packages/player/package.json
|
||||
COPY packages/producer/package.json packages/producer/package.json
|
||||
COPY packages/cli/package.json packages/cli/package.json
|
||||
COPY packages/studio/package.json packages/studio/package.json
|
||||
COPY packages/shader-transitions/package.json packages/shader-transitions/package.json
|
||||
COPY packages/aws-lambda/package.json packages/aws-lambda/package.json
|
||||
COPY packages/gcp-cloud-run/package.json packages/gcp-cloud-run/package.json
|
||||
COPY packages/sdk/package.json packages/sdk/package.json
|
||||
COPY packages/sdk-playground/package.json packages/sdk-playground/package.json
|
||||
RUN bun install --frozen-lockfile
|
||||
|
||||
# Copy source
|
||||
COPY packages/parsers/ packages/parsers/
|
||||
COPY packages/lint/ packages/lint/
|
||||
COPY packages/studio-server/ packages/studio-server/
|
||||
COPY packages/core/ packages/core/
|
||||
COPY packages/engine/ packages/engine/
|
||||
COPY packages/producer/ packages/producer/
|
||||
|
||||
# Build workspace packages so "node" export conditions resolve to built dist
|
||||
RUN bun run --filter '@hyperframes/{parsers,lint,studio-server}' build \
|
||||
&& bun run --cwd packages/core build
|
||||
|
||||
# Build core runtime artifacts (needed by renderer)
|
||||
RUN bun run --filter @hyperframes/core build:hyperframes-runtime:modular
|
||||
|
||||
# Generate embedded font data (deterministicFonts.ts imports this at runtime)
|
||||
RUN cd packages/producer && bunx tsx scripts/generate-font-data.ts
|
||||
|
||||
WORKDIR /app/packages/producer
|
||||
|
||||
ENTRYPOINT ["bunx", "tsx", "src/regression-harness.ts", "--", "--sequential"]
|
||||
@@ -0,0 +1,190 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to the Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by the Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding any notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2026 HeyGen, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,333 @@
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="docs/logo/dark.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="docs/logo/light.svg">
|
||||
<img alt="HyperFrames" src="docs/logo/light.svg" width="300">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/package/hyperframes"><img src="https://img.shields.io/npm/v/hyperframes.svg?style=flat" alt="npm version"></a>
|
||||
<a href="https://www.npmjs.com/package/hyperframes"><img src="https://img.shields.io/npm/dm/hyperframes.svg?style=flat" alt="npm downloads"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License"></a>
|
||||
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen" alt="Node.js"></a>
|
||||
<a href="https://discord.gg/EbK98HBPdk"><img src="https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white" alt="Discord"></a>
|
||||
</p>
|
||||
|
||||
<p align="center"><b>Write HTML. Render video. Built for agents.</b></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://hyperframes.heygen.com/quickstart">Quickstart</a> |
|
||||
<a href="https://hyperframes.heygen.com/showcase">Showcase</a> |
|
||||
<a href="https://www.hyperframes.dev/">Playground</a> |
|
||||
<a href="https://hyperframes.heygen.com/catalog/blocks/data-chart">Catalog</a> |
|
||||
<a href="https://hyperframes.heygen.com/introduction">Docs</a> |
|
||||
<a href="https://discord.gg/EbK98HBPdk">Discord</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/public/images/hyperframes-logo-motion-1280-trimmed.webp" alt="HyperFrames demo: HTML code on the left transforms into a rendered video on the right" width="800">
|
||||
</p>
|
||||
|
||||
HyperFrames is an open-source framework for turning HTML, CSS, media, and seekable animations into deterministic MP4 videos. Use it locally with the CLI, from AI coding agents with skills, or as the rendering core behind hosted authoring workflows.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### With an AI coding agent
|
||||
|
||||
Install the HyperFrames skills, then describe the video you want:
|
||||
|
||||
```bash
|
||||
npx skills add heygen-com/hyperframes --full-depth --yes
|
||||
```
|
||||
|
||||
> `--full-depth` does a full clone of the repo's current `main`. Without it, `skills add` fetches the skills.sh registry blob, which lags `main` by hours — you'd get an older copy of a skill. (`hyperframes skills update` already installs full-depth.)
|
||||
|
||||
Try a prompt like:
|
||||
|
||||
> Using `/hyperframes`, create a 10-second product intro with a fade-in title, a background video, and subtle background music.
|
||||
|
||||
The skills teach agents the HyperFrames production loop: plan the video, write valid HTML, wire seekable animations, add media, lint, preview, and render. They work with Claude Code, Cursor, Gemini CLI, Codex, and other coding agents that support skills.
|
||||
|
||||
## Skills
|
||||
|
||||
HyperFrames ships 20 skills agents load on demand. Read `/hyperframes` first — it's the router and capability map; it picks a workflow for any "make me a…" request — video, deck, or composition port — and points to the domain skills below.
|
||||
|
||||
Run `npx skills add heygen-com/hyperframes --full-depth` for the interactive picker, `npx skills add heygen-com/hyperframes --all --full-depth` to install all 20 at once (skips the picker), or `npx skills add heygen-com/hyperframes --skill <name> --full-depth` for just one (bare name, no leading `/`). Keep `--full-depth` — it installs the current `main`; without it `skills add` fetches the skills.sh blob, which lags by hours.
|
||||
|
||||
Installs stay lean after that: `npx hyperframes init` keeps the **core set** fresh (the router, the `hyperframes-*` domain skills, and `media-use` — plus whatever is already installed; `/figma` stays on demand) and never expands a partial install; the creation workflows install **on demand** — the router runs `npx hyperframes skills update <workflow>` before entering one. Nothing re-pulls the full set behind your back.
|
||||
|
||||
### Router
|
||||
|
||||
| Skill | Use when |
|
||||
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/hyperframes` | **Read first** for any request to make / create / edit / animate / render a video, animation, or motion graphic. Capability map for the domain skills and intent router for the creation workflows below. |
|
||||
|
||||
### Creation workflows
|
||||
|
||||
| Skill | Use when |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `/product-launch-video` | Marketing / launching / promoting a **product** — from its URL, a brief, or a script (even if the site is only named). Up to ~3 min (sweet spot 30-90s). |
|
||||
| `/website-to-video` | Turning a **general website** into a video — site tour, portfolio / landing-page showcase, social clip from the site's own visuals. |
|
||||
| `/faceless-explainer` | **Explaining a topic / concept** from arbitrary text — no product, no URL, no website capture; every visual is LLM-invented (typography / abstract / diagram / data-viz). |
|
||||
| `/pr-to-video` | A **GitHub pull request** (PR URL, `owner/repo#N` ref, or "this PR") → changelog / feature-reveal / fix / refactor explainer, read via the `gh` CLI. |
|
||||
| `/embedded-captions` | Adding **captions / subtitles** to an existing talking-head video (footage untouched) — verbatim rail, embedded climax behind the subject, or pure-cinematic embed. |
|
||||
| `/talking-head-recut` | Packaging an existing talking-head / interview / podcast video with **designed graphic overlays** — lower-thirds, data callouts, kinetic titles, pull-quotes, side panels, PiP. |
|
||||
| `/motion-graphics` | A short, **unnarrated, design-led motion graphic** (~under 10s) — kinetic type, stat / chart hit, logo sting, lower-third, animated tweet / headline. MP4 or transparent overlay. |
|
||||
| `/music-to-video` | A **music track** (audio file, or video to pull audio from) → a **beat-synced** video — lyric, slideshow, or kinetic promo; music drives pacing. |
|
||||
| `/slideshow` | A **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video. |
|
||||
| `/general-video` | **Anything else** — longer or multi-scene pieces, brand / sizzle reel, title card, static loop, freeform composition. Input- and length-agnostic fallback. |
|
||||
| `/remotion-to-hyperframes` | **Porting an existing Remotion** (React) composition's source to HyperFrames HTML. One-way migration, not creation. |
|
||||
|
||||
### Domain skills (loaded on demand)
|
||||
|
||||
Atomic capabilities the creation workflows compose against — pull one when you need that specific layer.
|
||||
|
||||
| Skill | Covers |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `/hyperframes-core` | The composition contract — `data-*` timing attributes, `class="clip"`, tracks, sub-compositions, variables, framework-owned media playback, determinism rules. |
|
||||
| `/hyperframes-animation` | All animation knowledge — atomic motion rules, scene blueprints, transitions, runtime adapters (GSAP / Lottie / Three.js / Anime.js / CSS / WAAPI / TypeGPU). |
|
||||
| `/hyperframes-keyframes` | Seek-safe keyframe authoring across runtimes — GSAP timelines, CSS keyframes, Anime.js, WAAPI, FLIP, paths, masks, SVG morph/draw, 3D depth — plus `hyperframes keyframes` diagnostics for rendered motion. |
|
||||
| `/hyperframes-creative` | Non-animation creative direction — `frame.md` / `design.md`, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns. |
|
||||
| `/media-use` | The media OS — resolve any media need (BGM, SFX, image, icon, logo, voice, color grade, LUT) into a frozen local file or paste-ready block + ledger record, generate via TTS/music/image models when the catalog misses, transcribe, caption, remove backgrounds, and reuse assets across projects. One shared audio engine + manifest tracking. |
|
||||
| `/hyperframes-cli` | CLI dev loop — `init`, `lint`, `check`, `snapshot`, `preview`, `render`, `publish`, `doctor`, plus AWS Lambda cloud rendering (`lambda deploy / render / progress`). |
|
||||
| `/hyperframes-registry` | Install and wire registry blocks and components into compositions via `hyperframes add`. Authoring a new block or component to contribute upstream. |
|
||||
| `/figma` | Import Figma assets, tokens, components, and storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI) plus Motion animations (MCP) and shaders (MCP source / native export) into a composition. |
|
||||
|
||||
For visual design handoff workflows, see the [Claude Design guide](https://hyperframes.heygen.com/guides/claude-design) and [Open Design guide](https://hyperframes.heygen.com/guides/open-design).
|
||||
|
||||
### Manually with the CLI
|
||||
|
||||
```bash
|
||||
npx hyperframes init my-video
|
||||
cd my-video
|
||||
npx hyperframes preview # preview in browser with live reload
|
||||
npx hyperframes render # render to MP4
|
||||
```
|
||||
|
||||
**Requirements:** Node.js 22+, FFmpeg
|
||||
|
||||
## What You Can Build
|
||||
|
||||
Need ideas? Browse the [Showcase](https://hyperframes.heygen.com/showcase) for finished videos you can watch, read, run, and remix.
|
||||
|
||||
- Product launch videos and feature announcements
|
||||
- PR walkthroughs with animated code diffs, narration, and captions
|
||||
- Data visualizations, chart races, and map animations
|
||||
- Social videos with kinetic captions, overlays, and music
|
||||
- Docs-to-video, PDF-to-video, and website-to-video explainers
|
||||
- Reusable motion graphics for automated content pipelines
|
||||
|
||||
## Frame.md
|
||||
|
||||
**frame.md — your design system, ready for video.**
|
||||
|
||||
Every brand has a `design.md`. None of them were written for a camera. `frame.md` is the missing translation layer: it takes your web-context design spec and inverts it for the frame — the same tokens, the same rules, but rewritten so an AI agent can compose a promo video without guessing at scale or reaching for web chrome.
|
||||
|
||||
The output is a `DESIGN.md` superset your whole toolchain can read. Atoms stay sacred. Composition stays free. Numbers come from the script.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/biennale-yellow"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/biennale-yellow.png" alt="Biennale Yellow" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/biennale-yellow">Biennale Yellow</a></b>
|
||||
</td>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/blockframe"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/blockframe.png" alt="BlockFrame" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/blockframe">BlockFrame</a></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/blue-professional"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/blue-professional.png" alt="Blue Professional" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/blue-professional">Blue Professional</a></b>
|
||||
</td>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/bold-poster"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/bold-poster.png" alt="Bold Poster" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/bold-poster">Bold Poster</a></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/broadside"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/broadside.png" alt="Broadside" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/broadside">Broadside</a></b>
|
||||
</td>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/capsule"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/capsule.png" alt="Capsule" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/capsule">Capsule</a></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/cartesian"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/cartesian.png" alt="Cartesian" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/cartesian">Cartesian</a></b>
|
||||
</td>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/cobalt-grid"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/cobalt-grid.png" alt="Cobalt Grid" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/cobalt-grid">Cobalt Grid</a></b>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/coral"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/coral.png" alt="Coral" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/coral">Coral</a></b>
|
||||
</td>
|
||||
<td width="50%" align="center">
|
||||
<a href="https://www.hyperframes.dev/design/creative-mode"><img src="https://static.heygen.ai/hyperframes-oss/docs/images/design-templates/creative-mode.png" alt="Creative Mode" width="100%"></a>
|
||||
<br><b><a href="https://www.hyperframes.dev/design/creative-mode">Creative Mode</a></b>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Browse and remix them all at [hyperframes.dev/design](https://www.hyperframes.dev/design).
|
||||
|
||||
## How It Works
|
||||
|
||||
Define a video as HTML. Add data attributes for timing and tracks. Use GSAP, CSS, Lottie, Three.js, Anime.js, WAAPI, or your own frame adapter for seekable animation.
|
||||
|
||||
```html
|
||||
<div id="stage" data-composition-id="launch" data-start="0" data-width="1920" data-height="1080">
|
||||
<video
|
||||
class="clip"
|
||||
data-start="0"
|
||||
data-duration="6"
|
||||
data-track-index="0"
|
||||
src="intro.mp4"
|
||||
muted
|
||||
playsinline
|
||||
></video>
|
||||
|
||||
<h1 id="title" class="clip" data-start="1" data-duration="4" data-track-index="1">Launch day</h1>
|
||||
|
||||
<audio
|
||||
data-start="0"
|
||||
data-duration="6"
|
||||
data-track-index="2"
|
||||
data-volume="0.5"
|
||||
src="music.wav"
|
||||
></audio>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
|
||||
<script>
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
tl.from("#title", { opacity: 0, y: 40, duration: 0.8 }, 1);
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines.launch = tl;
|
||||
</script>
|
||||
</div>
|
||||
```
|
||||
|
||||
Preview instantly in the browser. Render locally or in Docker. The renderer seeks each frame in headless Chrome and encodes the result with FFmpeg, so the same input produces the same video.
|
||||
|
||||
## HyperFrames Stack
|
||||
|
||||
HyperFrames is the open-source rendering engine, plus a growing set of tools around HTML-native video creation.
|
||||
|
||||
| Piece | Status | What it does |
|
||||
| ----------------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| CLI | Available | Scaffold, preview, lint, inspect, and render local video projects |
|
||||
| Core / Engine / Producer | Available | Parse compositions, drive headless Chrome, encode video, and mix audio |
|
||||
| Catalog | Available | Reusable blocks and components for transitions, overlays, captions, charts, maps, and effects |
|
||||
| Agent skills | Available | Teach coding agents the video-production patterns that generic web docs miss |
|
||||
| Studio | Available, evolving | Browser surface for previewing and editing compositions |
|
||||
| AWS Lambda rendering | Available | Deploy a distributed render stack and drive renders from your laptop or CI |
|
||||
| [hyperframes.dev](https://www.hyperframes.dev/) | Available | Community playground for previewing, iterating, sharing, and rendering HTML-native video projects |
|
||||
| [frame.md](https://www.hyperframes.dev/design) | Available | Invert your design system for the camera — a DESIGN.md superset an agent can compose video from |
|
||||
|
||||
## Catalog
|
||||
|
||||
Install ready-to-use blocks and components:
|
||||
|
||||
```bash
|
||||
npx hyperframes add flash-through-white # shader transition
|
||||
npx hyperframes add instagram-follow # social overlay
|
||||
npx hyperframes add data-chart # animated chart
|
||||
```
|
||||
|
||||
Browse the catalog at [hyperframes.heygen.com/catalog](https://hyperframes.heygen.com/catalog/blocks/data-chart).
|
||||
|
||||
## Why HyperFrames?
|
||||
|
||||
- **HTML-native:** compositions are HTML files with data attributes. No React requirement, no proprietary timeline format.
|
||||
- **Agent-friendly:** agents already write HTML, and the CLI is non-interactive by default.
|
||||
- **Deterministic:** same input, same frames, same output. Built for CI, regression tests, and automated rendering.
|
||||
- **No build step:** an `index.html` composition plays as-is and can be previewed directly in the browser.
|
||||
- **Adapter-based animation:** bring GSAP, CSS animations, Lottie, Three.js, Anime.js, WAAPI, or a custom runtime.
|
||||
- **Open source:** Apache 2.0 license, with no per-render fees or commercial-use thresholds.
|
||||
|
||||
## HyperFrames vs Remotion
|
||||
|
||||
HyperFrames is inspired by [Remotion](https://www.remotion.dev). Both tools render video with headless Chrome and FFmpeg. The main difference is the authoring model: Remotion's bet is React components; HyperFrames' bet is plain HTML that humans and agents can both write easily.
|
||||
|
||||
| | **HyperFrames** | **Remotion** |
|
||||
| ------------------------ | ------------------------------------- | --------------------------------------- |
|
||||
| Authoring | HTML + CSS + seekable animation | React components |
|
||||
| Build step | None; `index.html` plays as-is | Bundler required |
|
||||
| Agent handoff | Plain HTML files | JSX / React project |
|
||||
| Library-clock animations | Seekable, frame-accurate via adapters | Wall-clock animation patterns need care |
|
||||
| Distributed rendering | Local and AWS Lambda render paths | Remotion Lambda, mature cloud renderer |
|
||||
| License | Apache 2.0 | Source-available Remotion License |
|
||||
|
||||
Read the full comparison in the [HyperFrames vs Remotion guide](https://hyperframes.heygen.com/guides/hyperframes-vs-remotion).
|
||||
|
||||
## Documentation
|
||||
|
||||
Full documentation: [hyperframes.heygen.com/introduction](https://hyperframes.heygen.com/introduction)
|
||||
|
||||
- [Quickstart](https://hyperframes.heygen.com/quickstart)
|
||||
- [Showcase](https://hyperframes.heygen.com/showcase)
|
||||
- [Guides](https://hyperframes.heygen.com/guides/gsap-animation)
|
||||
- [API Reference](https://hyperframes.heygen.com/packages/core)
|
||||
- [Catalog](https://hyperframes.heygen.com/catalog/blocks/data-chart)
|
||||
- [Examples](https://hyperframes.heygen.com/examples)
|
||||
- [AWS Lambda rendering](https://hyperframes.heygen.com/deploy/aws-lambda)
|
||||
|
||||
## Packages
|
||||
|
||||
| Package | Description |
|
||||
| ---------------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| [`hyperframes`](packages/cli) | CLI for creating, previewing, linting, and rendering compositions |
|
||||
| [`@hyperframes/core`](packages/core) | Types, parsers, generators, linter, runtime, and frame adapters |
|
||||
| [`@hyperframes/engine`](packages/engine) | Seekable page-to-video capture engine using Puppeteer and FFmpeg |
|
||||
| [`@hyperframes/producer`](packages/producer) | Full rendering pipeline for capture, encode, and audio mix |
|
||||
| [`@hyperframes/studio`](packages/studio) | Browser-based composition editor UI |
|
||||
| [`@hyperframes/player`](packages/player) | Embeddable `<hyperframes-player>` web component |
|
||||
| [`@hyperframes/shader-transitions`](packages/shader-transitions) | WebGL shader transitions for compositions |
|
||||
| [`@hyperframes/aws-lambda`](packages/aws-lambda) | AWS Lambda SDK and deployment surface for distributed renders |
|
||||
|
||||
## Community
|
||||
|
||||
HyperFrames is used in production at [HeyGen](https://www.heygen.com), with community examples from teams like [tldraw](https://tldraw.com), [TanStack](https://tanstack.com), and others in [ADOPTERS.md](ADOPTERS.md). Open a PR if your team is using HyperFrames.
|
||||
|
||||
- Questions and ideas: [Discord](https://discord.gg/EbK98HBPdk)
|
||||
- Bugs and feature requests: [GitHub Issues](https://github.com/heygen-com/hyperframes/issues)
|
||||
- Security reports: [SECURITY.md](SECURITY.md)
|
||||
- Contributions: [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## Development Note
|
||||
|
||||
The repo uses [Git LFS](https://git-lfs.com) for golden regression-test baselines under `packages/producer/tests/**/output.mp4` (about 240 MB of `.mp4` files). If you're cloning the full repo for development, install Git LFS first:
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install git-lfs
|
||||
|
||||
# Ubuntu / Debian
|
||||
sudo apt install git-lfs
|
||||
|
||||
# Windows
|
||||
winget install GitHub.GitLFS
|
||||
|
||||
# Then, once per machine
|
||||
git lfs install
|
||||
```
|
||||
|
||||
If you only need source files, you can skip LFS content:
|
||||
|
||||
```bash
|
||||
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/heygen-com/hyperframes.git
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](LICENSE)
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`heygen-com/hyperframes`
|
||||
- 原始仓库:https://github.com/heygen-com/hyperframes
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you discover a security vulnerability in Hyperframes, please report it responsibly.
|
||||
|
||||
**Do not open a public GitHub issue for security vulnerabilities.**
|
||||
|
||||
Instead, open a [GitHub Security Advisory](https://github.com/heygen-com/hyperframes/security/advisories/new) with:
|
||||
|
||||
- A description of the vulnerability
|
||||
- Steps to reproduce
|
||||
- Potential impact
|
||||
- Suggested fix (if any)
|
||||
|
||||
We will acknowledge receipt within 48 hours and aim to provide a fix or mitigation plan within 7 days.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | --------- |
|
||||
| 0.x | Yes |
|
||||
|
||||
## Scope
|
||||
|
||||
This policy applies to all packages in the `@hyperframes/*` npm scope and the code in this repository.
|
||||
@@ -0,0 +1,15 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100" height="100" fill="black"/>
|
||||
<path d="M10.1851 57.8021L33.1145 73.8313C36.2202 75.9978 41.5173 73.5433 42.4816 69.4984L51.7611 30.4271C52.7253 26.3822 48.5802 23.9277 44.4602 26.0942L13.917 42.1235C6.96677 45.7676 4.97564 54.1579 10.1851 57.8021Z" fill="url(#paint0_linear_2204_3080)"/>
|
||||
<path d="M87.5129 57.5141L56.9696 73.5433C52.8371 75.7098 48.7046 73.2553 49.6688 69.2104L58.9483 30.1391C59.9125 26.0942 65.2097 23.6397 68.3154 25.8062L91.2447 41.8354C96.4668 45.4796 94.4631 53.8699 87.5129 57.5141Z" fill="url(#paint1_linear_2204_3080)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_2204_3080" x1="48.5676" y1="25" x2="44.7804" y2="71.9384" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#06E3FA"/>
|
||||
<stop offset="1" stop-color="#4FDB5E"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_2204_3080" x1="54.8282" y1="73.8392" x2="72.0989" y2="32.8932" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#06E3FA"/>
|
||||
<stop offset="1" stop-color="#4FDB5E"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,15 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="100" height="100" fill="white"/>
|
||||
<path d="M10.1851 57.8021L33.1145 73.8313C36.2202 75.9978 41.5173 73.5433 42.4816 69.4984L51.7611 30.4271C52.7253 26.3822 48.5802 23.9277 44.4602 26.0942L13.917 42.1235C6.96677 45.7676 4.97564 54.1579 10.1851 57.8021Z" fill="url(#paint0_linear_2204_3074)"/>
|
||||
<path d="M87.5129 57.5141L56.9696 73.5433C52.8371 75.7098 48.7046 73.2553 49.6688 69.2104L58.9483 30.1391C59.9125 26.0942 65.2097 23.6397 68.3154 25.8062L91.2447 41.8354C96.4668 45.4796 94.4631 53.8699 87.5129 57.5141Z" fill="url(#paint1_linear_2204_3074)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_2204_3074" x1="48.5676" y1="25" x2="44.7804" y2="71.9384" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#06E3FA"/>
|
||||
<stop offset="1" stop-color="#4FDB5E"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_2204_3074" x1="54.8282" y1="73.8392" x2="72.0989" y2="32.8932" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#06E3FA"/>
|
||||
<stop offset="1" stop-color="#4FDB5E"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,3 @@
|
||||
export default {
|
||||
extends: ["@commitlint/config-conventional"],
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "App Showcase"
|
||||
description: "Fitness app product showcase with three floating smartphone screens"
|
||||
---
|
||||
|
||||
# App Showcase
|
||||
|
||||
Fitness app product showcase with three floating smartphone screens
|
||||
|
||||
`showcase` `app` `3d`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/app-showcase.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/app-showcase.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add app-showcase
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 5.5s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `app-showcase.html` | `compositions/app-showcase.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="app-showcase" data-composition-src="compositions/app-showcase.html" data-start="0" data-duration="5.5" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "Apple Money Count"
|
||||
description: "Apple-style finance counter that counts from $0 to $10,000, flashes green, and bursts money icons with sound."
|
||||
---
|
||||
|
||||
# Apple Money Count
|
||||
|
||||
Apple-style finance counter that counts from $0 to $10,000, flashes green, and bursts money icons with sound.
|
||||
|
||||
`showcase` `finance` `kinetic` `youtube` `sfx`
|
||||
|
||||
Created by [Stronkter](https://x.com/Stronkter).
|
||||
|
||||
## Source Prompt
|
||||
|
||||
```text
|
||||
📷HyperFrames by HeyGen Make me a five-second video of, on a white background, of a Apple-style bold font counting from $0 to $10,000. Once it counts to $10,000, it changes to a green color and the screen also flashes green for a second, and then money icons come out of the $10,000 amount all over the screen and then disappear.
|
||||
```
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/apple-money-count.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/apple-money-count.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-money-count
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 5s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `apple-money-count.html` | `compositions/apple-money-count.html` | hyperframes:composition |
|
||||
| `assets/sfx-production.wav` | `assets/sfx-production.wav` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="apple-money-count" data-composition-src="compositions/apple-money-count.html" data-start="0" data-duration="5" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: "Blue Sweater Intro Video"
|
||||
description: "Warm AI creator intro sequence that resolves into an X follow card for @_blue_sweater_."
|
||||
---
|
||||
|
||||
# Blue Sweater Intro Video
|
||||
|
||||
Warm AI creator intro sequence that resolves into an X follow card for @_blue_sweater_.
|
||||
|
||||
`showcase` `ai` `creator` `sfx`
|
||||
|
||||
Created by [Joe Sai](https://x.com/_blue_sweater_).
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/blue-sweater-intro-video.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/blue-sweater-intro-video.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add blue-sweater-intro-video
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `blue-sweater-intro-video.html` | `compositions/blue-sweater-intro-video.html` | hyperframes:composition |
|
||||
| `assets/joe-sai-avatar.png` | `assets/joe-sai-avatar.png` | hyperframes:asset |
|
||||
| `assets/sfx/integrated-melodic-tech-mix.wav` | `assets/sfx/integrated-melodic-tech-mix.wav` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="blue-sweater-intro-video" data-composition-src="compositions/blue-sweater-intro-video.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Chromatic Radial Split"
|
||||
description: "Shader transition with chromatic aberration radial split"
|
||||
---
|
||||
|
||||
# Chromatic Radial Split
|
||||
|
||||
Shader transition with chromatic aberration radial split
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/chromatic-radial-split.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/chromatic-radial-split.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add chromatic-radial-split
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `chromatic-radial-split.html` | `compositions/chromatic-radial-split.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="chromatic-radial-split" data-composition-src="compositions/chromatic-radial-split.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Cinematic Zoom"
|
||||
description: "Shader transition with dramatic zoom blur"
|
||||
---
|
||||
|
||||
# Cinematic Zoom
|
||||
|
||||
Shader transition with dramatic zoom blur
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/cinematic-zoom.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/cinematic-zoom.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add cinematic-zoom
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `cinematic-zoom.html` | `compositions/cinematic-zoom.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="cinematic-zoom" data-composition-src="compositions/cinematic-zoom.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code 3D Extrude"
|
||||
description: "Syntax-highlighted code on a lit, beveled 3D slab that rotates through real space and settles to a readable rest — true WebGL depth and lighting, not a 2D transform."
|
||||
---
|
||||
|
||||
# Code 3D Extrude
|
||||
|
||||
Syntax-highlighted code on a lit, beveled 3D slab that rotates through real space and settles to a readable rest — true WebGL depth and lighting, not a 2D transform.
|
||||
|
||||
`code` `code-animation` `3d` `webgl` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-3d-extrude.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-3d-extrude.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-3d-extrude
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 8s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-3d-extrude.html` | `compositions/code-3d-extrude.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-3d-extrude" data-composition-src="compositions/code-3d-extrude.html" data-start="0" data-duration="8" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Diff"
|
||||
description: "An edit shown as a colored diff — removed lines collapse in red, added lines expand in green."
|
||||
---
|
||||
|
||||
# Code Diff
|
||||
|
||||
An edit shown as a colored diff — removed lines collapse in red, added lines expand in green.
|
||||
|
||||
`code` `code-animation` `diff` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-diff.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-diff.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-diff
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 6s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-diff.html` | `compositions/code-diff.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-diff" data-composition-src="compositions/code-diff.html" data-start="0" data-duration="6" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Highlight Sweep"
|
||||
description: "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line."
|
||||
---
|
||||
|
||||
# Code Highlight Sweep
|
||||
|
||||
A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line.
|
||||
|
||||
`code` `code-animation` `highlight` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-highlight.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-highlight.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-highlight
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 5s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-highlight.html` | `compositions/code-highlight.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-highlight" data-composition-src="compositions/code-highlight.html" data-start="0" data-duration="5" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Morph"
|
||||
description: "One snippet transforms into another — tokens glide between positions, leavers fade out, enterers fade in. Shiki Magic Move re-driven as a paused GSAP timeline."
|
||||
---
|
||||
|
||||
# Code Morph
|
||||
|
||||
One snippet transforms into another — tokens glide between positions, leavers fade out, enterers fade in. Shiki Magic Move re-driven as a paused GSAP timeline.
|
||||
|
||||
`code` `code-animation` `morph` `refactor` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-morph.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-morph.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-morph
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 7s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-morph.html` | `compositions/code-morph.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-morph" data-composition-src="compositions/code-morph.html" data-start="0" data-duration="7" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Particle Assemble"
|
||||
description: "Thousands of GPU points scatter through space and fly to the exact glyph pixels of the code, resolving into readable syntax-highlighted text — a particle system, not a token tween."
|
||||
---
|
||||
|
||||
# Code Particle Assemble
|
||||
|
||||
Thousands of GPU points scatter through space and fly to the exact glyph pixels of the code, resolving into readable syntax-highlighted text — a particle system, not a token tween.
|
||||
|
||||
`code` `code-animation` `particles` `gpu` `webgl` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-particle-assemble.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-particle-assemble.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-particle-assemble
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 8s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-particle-assemble.html` | `compositions/code-particle-assemble.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-particle-assemble" data-composition-src="compositions/code-particle-assemble.html" data-start="0" data-duration="8" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Scroll To Line"
|
||||
description: "The camera scrolls a long file to bring a target line to center and spotlights it — for walking through real modules."
|
||||
---
|
||||
|
||||
# Code Scroll To Line
|
||||
|
||||
The camera scrolls a long file to bring a target line to center and spotlights it — for walking through real modules.
|
||||
|
||||
`code` `code-animation` `scroll` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-scroll.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-scroll.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-scroll
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 6s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-scroll.html` | `compositions/code-scroll.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-scroll" data-composition-src="compositions/code-scroll.html" data-start="0" data-duration="6" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Shader Dissolve"
|
||||
description: "The code compiles into existence: a GPU fragment shader resolves it out of seeded noise with a chromatic dissolve front and edge glow, then holds crisp."
|
||||
---
|
||||
|
||||
# Code Shader Dissolve
|
||||
|
||||
The code compiles into existence: a GPU fragment shader resolves it out of seeded noise with a chromatic dissolve front and edge glow, then holds crisp.
|
||||
|
||||
`code` `code-animation` `shader` `webgl` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-shader-dissolve.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-shader-dissolve.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-shader-dissolve
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 7s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-shader-dissolve.html` | `compositions/code-shader-dissolve.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-shader-dissolve" data-composition-src="compositions/code-shader-dissolve.html" data-start="0" data-duration="7" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Apple Terminal Basic"
|
||||
description: "Apple Terminal Basic profile with white background and black text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Basic
|
||||
|
||||
macOS Terminal.app window in the built-in Basic profile — clean white background with black monospace text and a solid black cursor. Per-character typing animation with output reveal.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-basic.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-basic.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-basic
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-basic.html` | `compositions/code-snippet-apple-terminal-basic.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-basic"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-basic.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Basic profile — white background, black text, solid cursor
|
||||
- macOS window chrome with traffic light buttons (close, minimize, fullscreen) and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Clear Dark"
|
||||
description: "Apple Terminal Clear Dark profile with semi-transparent dark background and white text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Clear Dark
|
||||
|
||||
macOS Terminal.app window in the built-in Clear Dark profile — translucent black background with white text and a grey cursor. Per-character typing animation with output reveal.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-dark.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-dark.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-clear-dark
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-clear-dark.html` | `compositions/code-snippet-apple-terminal-clear-dark.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-clear-dark"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-clear-dark.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Clear Dark profile — semi-transparent black background with white text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Apple Terminal Clear Light"
|
||||
description: "Apple Terminal Clear Light profile with semi-transparent white background and black text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Clear Light
|
||||
|
||||
macOS Terminal.app window in the built-in Clear Light profile — translucent white background with black text and a grey cursor. Per-character typing animation with output reveal.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-light.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-light.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-clear-light
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-clear-light.html` | `compositions/code-snippet-apple-terminal-clear-light.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-clear-light"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-clear-light.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Clear Light profile — semi-transparent white background with black text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Apple Terminal Grass"
|
||||
description: "Apple Terminal Grass profile with black background and bright green text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Grass
|
||||
|
||||
macOS Terminal.app window in the built-in Grass profile — pitch-black background with pure green text and a matching cursor. Classic terminal aesthetic with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-grass.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-grass.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-grass
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-grass.html` | `compositions/code-snippet-apple-terminal-grass.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-grass"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-grass.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Grass profile — black background with #00C100 green text
|
||||
- macOS window chrome with green-accented title bar and traffic light buttons
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Homebrew"
|
||||
description: "Apple Terminal Homebrew profile with black background, bright green text and lime cursor, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Homebrew
|
||||
|
||||
macOS Terminal.app window in the built-in Homebrew profile — black background with vivid green text and a lime `#48F800` cursor. One of the most beloved classic terminal looks.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-homebrew.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-homebrew.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-homebrew
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-homebrew.html` | `compositions/code-snippet-apple-terminal-homebrew.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-homebrew"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-homebrew.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Homebrew profile — black background with #00CF00 text and #48F800 cursor
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Apple Terminal Man Page"
|
||||
description: "Apple Terminal Man Page profile with pale yellow background and black text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Man Page
|
||||
|
||||
macOS Terminal.app window in the built-in Man Page profile — pale yellow `#FEF49C` background with black text. Evoking classic Unix manual pages, with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-man-page.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-man-page.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-man-page
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-man-page.html` | `compositions/code-snippet-apple-terminal-man-page.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-man-page"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-man-page.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Man Page profile — pale yellow background with black text
|
||||
- Shows a realistic man page output structure with sections and indented content
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Novel"
|
||||
description: "Apple Terminal Novel profile with warm parchment background and dark brown text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Novel
|
||||
|
||||
macOS Terminal.app window in the built-in Novel profile — warm parchment `#DFC18A` background with deep brown text. A distinctive earthy look, with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-novel.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-novel.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-novel
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-novel.html` | `compositions/code-snippet-apple-terminal-novel.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-novel"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-novel.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Novel profile — warm parchment background with #3E2900 dark brown text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Ocean"
|
||||
description: "Apple Terminal Ocean profile with deep blue background and white text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Ocean
|
||||
|
||||
macOS Terminal.app window in the built-in Ocean profile — vivid `#224FBE` blue background with crisp white text. Bold and distinctive, with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-ocean.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-ocean.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-ocean
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-ocean.html` | `compositions/code-snippet-apple-terminal-ocean.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-ocean"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-ocean.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Ocean profile — #224FBE blue background with white text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Pro"
|
||||
description: "Apple Terminal Pro profile with black background, grey text and lime green cursor, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Pro
|
||||
|
||||
macOS Terminal.app window in the built-in Pro profile — pure black background with grey `#BBBBBB` text and a distinctive `#88FF67` lime cursor. Hacker aesthetic with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-pro.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-pro.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-pro
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-pro.html` | `compositions/code-snippet-apple-terminal-pro.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-pro"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-pro.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Pro profile — black background, #BBBBBB grey text, #88FF67 lime cursor
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Red Sands"
|
||||
description: "Apple Terminal Red Sands profile with deep red background and sandy text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Red Sands
|
||||
|
||||
macOS Terminal.app window in the built-in Red Sands profile — deep crimson `#7B140E` background with warm sandy `#FFE1B9` text. A bold, dramatic look with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-red-sands.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-red-sands.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-red-sands
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-red-sands.html` | `compositions/code-snippet-apple-terminal-red-sands.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-red-sands"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-red-sands.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Red Sands profile — #7B140E red background with #FFE1B9 sandy text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Silver Aerogel"
|
||||
description: "Apple Terminal Silver Aerogel profile with dark grey background and white text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Silver Aerogel
|
||||
|
||||
macOS Terminal.app window in the built-in Silver Aerogel profile — dark grey `#3D3D3D` background with clean white text. A professional neutral look with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-silver-aerogel.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-silver-aerogel.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-silver-aerogel
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-silver-aerogel.html` | `compositions/code-snippet-apple-terminal-silver-aerogel.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-silver-aerogel"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-silver-aerogel.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Silver Aerogel profile — #3D3D3D dark grey background with white text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "Apple Terminal Solid Colors"
|
||||
description: "Apple Terminal Solid Colors profile with deep purple background and white text, per-character typing animation."
|
||||
---
|
||||
|
||||
# Apple Terminal Solid Colors
|
||||
|
||||
macOS Terminal.app window in the built-in Solid Colors profile — vivid deep purple `#4C0099` background with white text. Eye-catching and vibrant, with per-character typing animation.
|
||||
|
||||
`code` `developer` `showcase` `terminal` `apple`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-solid-colors.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-solid-colors.png" autoPlay muted loop playsInline />
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-apple-terminal-solid-colors
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all Apple Terminal themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add apple-terminal
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-apple-terminal-solid-colors.html` | `compositions/code-snippet-apple-terminal-solid-colors.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-apple-terminal-solid-colors"
|
||||
data-composition-src="compositions/code-snippet-apple-terminal-solid-colors.html"
|
||||
data-start="0"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Faithful recreation of macOS Terminal.app Solid Colors profile — #4C0099 deep purple background with white text
|
||||
- macOS window chrome with traffic light buttons and centered title bar
|
||||
- Per-character GSAP typing animation — command types out character by character
|
||||
- Output lines reveal sequentially after command executes
|
||||
- Cursor blinks three times at the end then holds steady
|
||||
- Self-contained HTML — no external assets, only GSAP CDN
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Dark 2026"
|
||||
description: "The newest VS Code dark theme with refined token scopes and updated palette."
|
||||
---
|
||||
|
||||
# Dark 2026
|
||||
|
||||
VS Code workbench with per-character typing animation in the Dark 2026 theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-2026.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-2026.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-dark-2026
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-dark-2026.html` | `compositions/code-snippet-dark-2026.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-dark-2026"
|
||||
data-composition-src="compositions/code-snippet-dark-2026.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Dark Modern"
|
||||
description: "The default dark theme — clean and contemporary with comfortable contrast."
|
||||
---
|
||||
|
||||
# Dark Modern
|
||||
|
||||
VS Code workbench with per-character typing animation in the Dark Modern theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-modern.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-modern.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-dark-modern
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-dark-modern.html` | `compositions/code-snippet-dark-modern.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-dark-modern"
|
||||
data-composition-src="compositions/code-snippet-dark-modern.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Dark+"
|
||||
description: "Classic dark theme with enhanced syntax highlighting for popular languages."
|
||||
---
|
||||
|
||||
# Dark+
|
||||
|
||||
VS Code workbench with per-character typing animation in the Dark+ theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-plus.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-dark-plus.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-dark-plus
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-dark-plus.html` | `compositions/code-snippet-dark-plus.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-dark-plus"
|
||||
data-composition-src="compositions/code-snippet-dark-plus.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Snippet Flight"
|
||||
description: "Discrete code snippets fly in from the side and assemble into a stacked program, staggered. Block-level FLIP."
|
||||
---
|
||||
|
||||
# Code Snippet Flight
|
||||
|
||||
Discrete code snippets fly in from the side and assemble into a stacked program, staggered. Block-level FLIP.
|
||||
|
||||
`code` `code-animation` `flight` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-flight.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-flight.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-flight
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 6s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-flight.html` | `compositions/code-snippet-flight.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-snippet-flight" data-composition-src="compositions/code-snippet-flight.html" data-start="0" data-duration="6" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "High Contrast Light"
|
||||
description: "Maximum contrast light theme for accessibility."
|
||||
---
|
||||
|
||||
# High Contrast Light
|
||||
|
||||
VS Code workbench with per-character typing animation in the High Contrast Light theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-high-contrast-light.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-high-contrast-light.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-high-contrast-light
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-high-contrast-light.html` | `compositions/code-snippet-high-contrast-light.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-high-contrast-light"
|
||||
data-composition-src="compositions/code-snippet-high-contrast-light.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "High Contrast"
|
||||
description: "Maximum contrast dark theme for accessibility."
|
||||
---
|
||||
|
||||
# High Contrast
|
||||
|
||||
VS Code workbench with per-character typing animation in the High Contrast theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-high-contrast.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-high-contrast.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-high-contrast
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-high-contrast.html` | `compositions/code-snippet-high-contrast.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-high-contrast"
|
||||
data-composition-src="compositions/code-snippet-high-contrast.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Light 2026"
|
||||
description: "The newest VS Code light theme with refined token scopes and updated palette."
|
||||
---
|
||||
|
||||
# Light 2026
|
||||
|
||||
VS Code workbench with per-character typing animation in the Light 2026 theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-2026.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-2026.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-light-2026
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-light-2026.html` | `compositions/code-snippet-light-2026.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-light-2026"
|
||||
data-composition-src="compositions/code-snippet-light-2026.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Light Modern"
|
||||
description: "The default light theme — a fresh, modern take on the classic VS light experience."
|
||||
---
|
||||
|
||||
# Light Modern
|
||||
|
||||
VS Code workbench with per-character typing animation in the Light Modern theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-modern.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-modern.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-light-modern
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-light-modern.html` | `compositions/code-snippet-light-modern.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-light-modern"
|
||||
data-composition-src="compositions/code-snippet-light-modern.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Light+"
|
||||
description: "Classic light theme with enhanced syntax highlighting for popular languages."
|
||||
---
|
||||
|
||||
# Light+
|
||||
|
||||
VS Code workbench with per-character typing animation in the Light+ theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-plus.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-light-plus.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-light-plus
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-light-plus.html` | `compositions/code-snippet-light-plus.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-light-plus"
|
||||
data-composition-src="compositions/code-snippet-light-plus.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Monokai"
|
||||
description: "The iconic warm-toned dark theme beloved by developers worldwide."
|
||||
---
|
||||
|
||||
# Monokai
|
||||
|
||||
VS Code workbench with per-character typing animation in the Monokai theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-monokai.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-monokai.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-monokai
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-monokai.html` | `compositions/code-snippet-monokai.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-monokai"
|
||||
data-composition-src="compositions/code-snippet-monokai.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Solarized Light"
|
||||
description: "Ethan Schoonover's precision-engineered light color scheme."
|
||||
---
|
||||
|
||||
# Solarized Light
|
||||
|
||||
VS Code workbench with per-character typing animation in the Solarized Light theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-solarized-light.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-solarized-light.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-solarized-light
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-solarized-light.html` | `compositions/code-snippet-solarized-light.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-solarized-light"
|
||||
data-composition-src="compositions/code-snippet-solarized-light.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Visual Studio Dark"
|
||||
description: "The traditional Visual Studio dark color scheme."
|
||||
---
|
||||
|
||||
# Visual Studio Dark
|
||||
|
||||
VS Code workbench with per-character typing animation in the Visual Studio Dark theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-visual-studio-dark.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-visual-studio-dark.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-visual-studio-dark
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-visual-studio-dark.html` | `compositions/code-snippet-visual-studio-dark.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-visual-studio-dark"
|
||||
data-composition-src="compositions/code-snippet-visual-studio-dark.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "Visual Studio Light"
|
||||
description: "The traditional Visual Studio light color scheme."
|
||||
---
|
||||
|
||||
# Visual Studio Light
|
||||
|
||||
VS Code workbench with per-character typing animation in the Visual Studio Light theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.
|
||||
|
||||
`code` `developer` `showcase` `vscode`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-visual-studio-light.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-visual-studio-light.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-snippet-visual-studio-light
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
Install all code snippet themes at once:
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code
|
||||
```
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 11s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-snippet-visual-studio-light.html` | `compositions/code-snippet-visual-studio-light.html` | hyperframes:composition |
|
||||
| `background.jpeg` | `assets/background.jpeg` | hyperframes:asset |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="code-snippet-visual-studio-light"
|
||||
data-composition-src="compositions/code-snippet-visual-studio-light.html"
|
||||
data-start="0"
|
||||
data-duration="11"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Full VS Code workbench recreation — activity bar, sidebar, explorer tree, editor tabs, breadcrumbs, terminal panel, status bar
|
||||
- Per-character typing animation with cursor tracking and active line highlight
|
||||
- Colors sourced from official `microsoft/vscode` built-in theme JSON
|
||||
- 3D perspective tilt at the end of the typing sequence
|
||||
- Terminal panel with mock test output
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Code Typing"
|
||||
description: "Token-streamed typing reveal with a caret that tracks the frontier — deterministic, no CSS animation."
|
||||
---
|
||||
|
||||
# Code Typing
|
||||
|
||||
Token-streamed typing reveal with a caret that tracks the frontier — deterministic, no CSS animation.
|
||||
|
||||
`code` `code-animation` `typing` `developer`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-typing.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-typing.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add code-typing
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 5s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `code-typing.html` | `compositions/code-typing.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="code-typing" data-composition-src="compositions/code-typing.html" data-start="0" data-duration="5" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Cross Warp Morph"
|
||||
description: "Shader transition with cross-warped morphing"
|
||||
---
|
||||
|
||||
# Cross Warp Morph
|
||||
|
||||
Shader transition with cross-warped morphing
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/cross-warp-morph.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/cross-warp-morph.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add cross-warp-morph
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `cross-warp-morph.html` | `compositions/cross-warp-morph.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="cross-warp-morph" data-composition-src="compositions/cross-warp-morph.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Data Chart"
|
||||
description: "Animated bar + line chart with staggered reveal, NYT-style typography, and value labels"
|
||||
---
|
||||
|
||||
# Data Chart
|
||||
|
||||
Animated bar + line chart with staggered reveal, NYT-style typography, and value labels
|
||||
|
||||
`data` `chart` `statistics`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="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" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add data-chart
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 15s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `data-chart.html` | `compositions/data-chart.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="data-chart" data-composition-src="compositions/data-chart.html" data-start="0" data-duration="15" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Domain Warp Dissolve"
|
||||
description: "Shader transition with fractal noise domain warping"
|
||||
---
|
||||
|
||||
# Domain Warp Dissolve
|
||||
|
||||
Shader transition with fractal noise domain warping
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/domain-warp-dissolve.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/domain-warp-dissolve.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add domain-warp-dissolve
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `domain-warp-dissolve.html` | `compositions/domain-warp-dissolve.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="domain-warp-dissolve" data-composition-src="compositions/domain-warp-dissolve.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Flash Through White"
|
||||
description: "Shader transition with white flash crossfade"
|
||||
---
|
||||
|
||||
# Flash Through White
|
||||
|
||||
Shader transition with white flash crossfade
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flash-through-white.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flash-through-white.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add flash-through-white
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `flash-through-white.html` | `compositions/flash-through-white.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="flash-through-white" data-composition-src="compositions/flash-through-white.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Flowchart Vertical"
|
||||
description: "Portrait animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction"
|
||||
---
|
||||
|
||||
# Flowchart Vertical
|
||||
|
||||
Portrait animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction
|
||||
|
||||
`diagram` `flowchart` `interactive` `portrait`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flowchart-vertical.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flowchart-vertical.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add flowchart-vertical
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1440×2560 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `flowchart-vertical.html` | `compositions/flowchart-vertical.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="flowchart-vertical" data-composition-src="compositions/flowchart-vertical.html" data-start="0" data-duration="12" data-track-index="1" data-width="1440" data-height="2560"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Flowchart"
|
||||
description: "Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction"
|
||||
---
|
||||
|
||||
# Flowchart
|
||||
|
||||
Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction
|
||||
|
||||
`diagram` `flowchart` `interactive`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flowchart.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/flowchart.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add flowchart
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `flowchart.html` | `compositions/flowchart.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="flowchart" data-composition-src="compositions/flowchart.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Glitch"
|
||||
description: "Shader transition with digital glitch artifacts"
|
||||
---
|
||||
|
||||
# Glitch
|
||||
|
||||
Shader transition with digital glitch artifacts
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/glitch.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/glitch.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add glitch
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `glitch.html` | `compositions/glitch.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="glitch" data-composition-src="compositions/glitch.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Gravitational Lens"
|
||||
description: "Shader transition with gravitational lensing distortion"
|
||||
---
|
||||
|
||||
# Gravitational Lens
|
||||
|
||||
Shader transition with gravitational lensing distortion
|
||||
|
||||
`transition` `shader`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/gravitational-lens.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/gravitational-lens.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add gravitational-lens
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 4s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `gravitational-lens.html` | `compositions/gravitational-lens.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="gravitational-lens" data-composition-src="compositions/gravitational-lens.html" data-start="0" data-duration="4" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user