initial code (#2)

* feat: initial code port from hyperframes-internal

Port all OSS-ready packages from the internal monorepo:
- @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime
- @hyperframes/cli — CLI for creating, previewing, and rendering compositions
- @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg)
- @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg)
- @hyperframes/ui-player — browser-based video player component
- @hyperframes/studio — composition editor (React frontend + Hono backend)

Includes regression test suite with Docker-based test harness.

All HeyGen-internal references, deployment infrastructure, and
proprietary assets have been removed. Package names migrated
from @app/* to @hyperframes/*.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: scrub internal codenames and stale references from OSS port

- Replace static.heygen.ai runtime URLs in test fixtures
- Remove internal CDN publish script (publish-hyperframe-runtime.ts)
- Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime
  with neutral names (studio, hyperframe-runtime, __hyperframeRuntime)
- Fix stale Vault API / localhost references in docs
- Remove broken deprecated_studio link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove remaining internal codenames and stale references

- Delete stale producer README.md and PIPELINE.md (referenced nonexistent files)
- Replace "Cerberus" codename with "HyperFrames" in test design reviews
- Replace magic-edit postMessage identifiers with hf-preview/hf-parent
- Rename debug-magic-edit-timeline.ts to debug-timeline.ts
- Replace "Motion Cut" with "HyperFrames" in Timeline comments
- Fix studio/CLI references to nonexistent archive package
  (use local data/projects/ dir, stub render proxy)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-03-21 22:43:56 -07:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 10621e7903
commit 9f8e5ba5a1
401 changed files with 54545 additions and 2 deletions
@@ -0,0 +1,114 @@
<template id="captions-template">
<div data-composition-id="captions" data-width="1080" data-height="1920" data-duration="10.24">
<div id="captions-container"></div>
<style>
[data-composition-id="captions"] {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
background-color: transparent;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-transform: uppercase;
overflow: hidden;
}
[data-composition-id="captions"] .caption-group {
position: absolute;
top: 1528px;
left: 50%;
transform: translateX(-50%);
width: 900px;
background-color: #FFFFFF;
color: #000000;
padding: 60px;
border-top: 8px solid #CC0000;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
opacity: 0;
box-sizing: border-box;
}
[data-composition-id="captions"] .word {
font-weight: 700;
font-size: 72px;
letter-spacing: -0.02em;
margin: 0 10px;
display: inline-block;
}
</style>
<script>
(function() {
const TRANSCRIPT = [
{ text: 'Hola,', start: 1.22, end: 1.879 },
{ text: 'esto', start: 1.919, end: 2.119 },
{ text: 'es', start: 2.139, end: 2.199 },
{ text: 'una', start: 2.24, end: 2.46 },
{ text: 'prueba.', start: 2.46, end: 4.239 },
{ text: 'Yo', start: 4.279, end: 4.619 },
{ text: 'quiero', start: 4.679, end: 4.979 },
{ text: 'definitivamente', start: 5.0, end: 6.539 },
{ text: 'poder', start: 6.559, end: 6.879 },
{ text: 'grabar', start: 6.899, end: 7.279 },
{ text: 'contenido,', start: 7.299, end: 8.099 },
{ text: 'pero', start: 8.119, end: 8.3 },
{ text: 'ser', start: 8.399, end: 8.519 },
{ text: 'yo', start: 8.6, end: 8.74 },
{ text: 'misma', start: 8.76, end: 9.14 },
{ text: 'también', start: 9.159, end: 10.26 }
];
const container = document.getElementById('captions-container');
const tl = gsap.timeline({ paused: true });
const chunks = [];
let currentChunk = [];
TRANSCRIPT.forEach((word, index) => {
currentChunk.push(word);
if (currentChunk.length >= 3 || index === TRANSCRIPT.length - 1) {
chunks.push([...currentChunk]);
currentChunk = [];
}
});
chunks.forEach((chunk, i) => {
const group = document.createElement('div');
group.className = 'caption-group';
group.id = `group-${i}`;
chunk.forEach((wordData) => {
const span = document.createElement('span');
span.className = 'word';
span.textContent = wordData.text;
group.appendChild(span);
});
container.appendChild(group);
const startTime = chunk[0].start;
const endTime = chunk[chunk.length - 1].end;
tl.fromTo(
group,
{ opacity: 0, y: 20 },
{ opacity: 1, y: 0, duration: 0.3, ease: "power2.out" },
startTime
);
tl.to(
group,
{ opacity: 0, y: -10, duration: 0.2, ease: "power2.in" },
endTime
);
});
window.__timelines["captions"] = tl;
})();
</script>
</div>
</template>
@@ -0,0 +1,172 @@
<template id="overlays-template">
<div data-composition-id="overlays" data-width="1080" data-height="1920" data-duration="10.24">
<div id="graphic-1" class="vignelli-container">
<div class="white-box">
<div class="text-black">PRUEBA</div>
</div>
</div>
<div id="graphic-2" class="vignelli-container">
<div class="white-box">
<div class="text-black">GRABAR<br>CONTENIDO</div>
</div>
</div>
<div id="graphic-3" class="vignelli-full">
<div class="charcoal-bg"></div>
<div class="full-content">
<div class="text-white">SER YO<br>MISMA</div>
</div>
</div>
<style>
[data-composition-id="overlays"] {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
overflow: hidden;
}
.vignelli-container {
position: absolute;
width: 100%;
display: flex;
flex-direction: column;
align-items: flex-start;
padding-left: 100px;
opacity: 0;
pointer-events: none;
}
.white-box {
background-color: #FFFFFF;
padding: 40px 60px;
border-left: 30px solid #CC0000;
position: relative;
}
.text-black {
color: #1A1A1A;
font-size: 100px;
font-weight: 900;
line-height: 0.9;
text-transform: uppercase;
}
#graphic-1 {
top: 200px;
}
#graphic-1 .text-black {
font-size: 140px;
}
#graphic-2 {
top: 1150px;
}
.vignelli-full {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
padding-left: 100px;
pointer-events: none;
}
.charcoal-bg {
position: absolute;
top: 0;
left: 100%;
width: 100%;
height: 100%;
background-color: #1A1A1A;
}
.full-content {
position: relative;
z-index: 2;
opacity: 0;
text-align: left;
border-left: 30px solid #CC0000;
padding-left: 60px;
}
.full-content .text-white {
color: #FFFFFF;
font-size: 180px;
font-weight: 900;
line-height: 0.85;
text-transform: uppercase;
}
</style>
<script>
(function() {
const tl = gsap.timeline({ paused: true });
const G1_IN = 1.22;
const G1_OUT = 4.23;
const G2_IN = 4.67;
const G2_OUT = 8.09;
const G3_IN = 8.3;
const G3_OUT = 10.24;
tl.fromTo(
'#graphic-1',
{ opacity: 0, x: -100 },
{ opacity: 1, x: 0, duration: 0.8, ease: "power3.out" },
G1_IN
);
tl.to(
'#graphic-1',
{ opacity: 0, x: 100, duration: 0.4, ease: "power3.in" },
G1_OUT - 0.4
);
tl.fromTo(
'#graphic-2',
{ opacity: 0, x: -100 },
{ opacity: 1, x: 0, duration: 0.8, ease: "power3.out" },
G2_IN
);
tl.to(
'#graphic-2',
{ opacity: 0, x: 100, duration: 0.4, ease: "power3.in" },
G2_OUT - 0.4
);
tl.to(
'.charcoal-bg',
{ left: 0, duration: 0.8, ease: "power3.inOut" },
G3_IN
);
tl.fromTo(
'.full-content',
{ opacity: 0, x: -50 },
{ opacity: 1, x: 0, duration: 0.8, ease: "back.out(1.2)" },
G3_IN + 0.4
);
tl.to(
'#graphic-3',
{ opacity: 0, duration: 0.24 },
G3_OUT - 0.24
);
window.__timelines = window.__timelines || {};
window.__timelines["overlays"] = tl;
})();
</script>
</div>
</template>
@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vignelli Style Video</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script src=""></script>
<style>
body {
margin: 0;
padding: 0;
background: #FFFFFF;
overflow: hidden;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
#main-composition {
position: relative;
width: 1080px;
height: 1920px;
background: #FFFFFF;
}
#a-roll-wrapper {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
overflow: hidden;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
}
[data-composition-id="overlays"] {
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
[data-composition-id="captions"] {
position: absolute;
top: 0;
left: 0;
z-index: 3;
}
</style>
</head>
<body>
<div id="main-composition" data-composition-id="main-comp" data-width="1080" data-height="1920" data-duration="10.24">
<div id="a-roll-wrapper">
<video id="a-roll" src="https://gen-os-static.s3.us-east-2.amazonaws.com/astral_assets/uploaded_assets/f140a7f9_c8ae0ae2698f4a6895110bb9cbaadd74.mp4" data-start="0" data-duration="10.24" data-track-index="0">
</video>
</div>
<div id="overlays-comp" data-composition-src="compositions/overlays.html" data-composition-id="overlays" data-start="0" data-duration="10.24" data-track-index="2" data-width="1080" data-height="1920">
</div>
<div id="captions-comp" data-composition-src="compositions/captions.html" data-composition-id="captions" data-start="0" data-duration="10.24" data-track-index="3" data-width="1080" data-height="1920">
</div>
</div>
<script>
const tl = gsap.timeline({ paused: true });
window.__timelines = window.__timelines || {};
window.__timelines["main-comp"] = tl;
</script>
</body>
</html>