{“content”:”---\nname: hyperframes-video\ndescription: TypeScript video composition framework (heygen-com/hyperframes) — init, lint, render workflow\n---\n# hyperframes-video\n\nTypeScript video composition framework (heygen-com/hyperframes) — renders HTML+CSS+GSAP animations to video.\n\nRender only works on PC (Windows/macOS with Chrome + FFmpeg). Termux can author but not render.\n\n## Project Structure\n\n\nD:\\hyperframes_test\\my-project\\ ← project root (run npx hyperframes here)\n├── index.html ← MUST exist at root (lint finds it at root)\n├── src\\\n│ └── index.html ← your working file (SCP here, then copy to root)\n├── meta.json\n└── output\\\n └── output.mp4\n\n\nCritical: After SCP-ing to src/, copy to root: Copy-Item 'src\\index.html' '.'\n\n## Required HTML Composition Structure\n\nEvery HTML file MUST have these on <body>:\n\nhtml\n<body\n id=\"app\"\n data-composition-id=\"main\"\n data-width=\"1920\"\n data-height=\"1080\"\n data-start=\"0\"\n data-duration=\"55\"\n>\n\n\nLINT WILL FAIL without all of: data-composition-id, data-width, data-height.\n\n## GSAP Timeline Setup\n\nhtml\n<script>\n window.__timelines = window.__timelines || {};\n // bg layer — static or minimal animation\n window.__timelines['bg'] = gsap.timeline({ paused: true });\n // main timeline — all content animations\n const tl = gsap.timeline({ paused: true });\n window.__timelines.main = tl;\n\n // Set initial states for animated elements (run before any tl.to())\n gsap.set('.badge, .sub-headline, .meta', { opacity: 0, y: 20 });\n gsap.set('.headline .word', { opacity: 0, x: 40, clipPath: 'inset(0 100% 0 0)' });\n gsap.set('#headline', { opacity: 1 }); // container must be visible for word animations\n</script>\n\n\nCommon lint errors and fixes:\n\n| Error | Fix |\n|-------|-----|\n| root_missing_composition_id | Add data-composition-id=\"main\" to <body> |\n| root_missing_dimensions | Add data-width and data-height to <body> |\n| timeline_registry_missing_init | Add window.__timelines = window.__timelines \\|\\| {}; before assignments |\n| timeline_id_mismatch | Use window.__timelines.main = tl matching data-composition-id=\"main\" |\n| root_missing_composition_id [bg-layer] | The div with id=\"bg-layer\" is treated as a composition. Either remove its id, OR add full composition attrs to it: data-composition-id=\"bg\" data-width=\"1920\" data-height=\"1080\" data-start=\"0\" data-duration=\"55\" |\n\n## Remote PC Workflow (SSH from Termux)\n\nPC Tailscale IP: 100.83.112.84 (verify with ping first if changed).\n\nbash\n# 1. Create project dirs on PC\nssh [email protected] \"powershell -NoProfile -Command \\\n \\\"New-Item -ItemType Directory -Force -Path 'D:\\\\hyperframes_test\\\\my-project\\\\src','D:\\\\hyperframes_test\\\\my-project\\\\output' | Out-Null; Write-Host 'OK'\\\"\"\n\n# 2. SCP HTML to PC src/\nscp -o StrictHostKeyChecking=no local/index.html [email protected]:\"D:/hyperframes_test/my-project/src/index.html\"\n\n# 3. Copy to root (lint requires index.html at project root)\nssh [email protected] \"powershell -NoProfile -Command \\\n \\\"Copy-Item 'D:\\\\hyperframes_test\\\\my-project\\\\src\\\\index.html' 'D:\\\\hyperframes_test\\\\my-project\\\\'; Write-Host 'Copied'\\\"\"\n\n# 4. Lint\nssh [email protected] \"powershell -NoProfile -Command \\\n \\\"Set-Location 'D:\\\\hyperframes_test'; npx hyperframes lint --project 'D:\\\\hyperframes_test\\\\my-project'; Write-Host 'EXIT:' \\$LASTEXITCODE\\\"\"\n\n# 5. Render (foreground, ~3min for 55s video at 30fps on 4 cores)\nssh [email protected] \"powershell -NoProfile -Command \\\n \\\"Set-Location 'D:\\\\hyperframes_test'; npx hyperframes render --project 'D:\\\\hyperframes_test\\\\my-project' --output 'D:\\\\hyperframes_test\\\\my-project\\\\output\\\\output.mp4'; Write-Host 'EXIT:' \\$LASTEXITCODE\\\"\"\n\n# 6. SCP output back\nscp -o StrictHostKeyChecking=no [email protected]:\"D:/hyperframes_test/my-project/output/output.mp4\" ~/Download/output.mp4\n\n\nPerformance: 55s video at 30fps = 1650 frames. On a modern PC with 4 cores ~3 min render. Add notify_on_complete=true for long renders so SSH doesn’t timeout.\n\n## Professional News Broadcast Design System\n\nUse this color/typography system for premium broadcast-quality videos:\n\ncss\n:root {\n --bg-primary: #0a0e1a; /* Deep navy */\n --bg-secondary: #111827; /* Slate */\n --accent-gold: #c9a84c; /* Gold accent */\n --accent-gold2: #e8c96a; /* Gold highlight */\n --accent-cyan: #00d4ff; /* Cyan highlight */\n --text-primary: #ffffff;\n --text-muted: rgba(255,255,255,0.5);\n --text-dim: rgba(255,255,255,0.3);\n}\n\n\nFont: Montserrat (Google Fonts) — weights 300/400/600/700/900.\nDimensions: 1920×1080, 30fps, 55s total (4 news segments × ~12s each + 4s intro + 3s outro).\n\nSegment layout patterns:\n- AI/Tech: Badge + headline (word-by-word clip-path reveal) + sub + meta + side visual\n- World: Left icon + stat row + body + highlighted headline words in gold\n- Malaysia: Topbar with flag + LIVE badge + data cards (flex row of stat cards)\n- Interior: 40% visual panel + 60% text column with tags\n\nAnimation timings per segment (~12s each):\n\n0.0s — segment fades in\n0.2s — badge/label slides in\n0.5s — headline words reveal one-by-one (0.15s stagger)\n1.8s — sub headline/body fades up\n2.5s — meta/tags/cards animate in\n10.5s — segment fades out\n\n\nNews ticker: Fixed at bottom, gold bar with scrolling headline text.\n\n## GSAP Composition Template\n\nhtml\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <title>My Video</title>\n <link href=\"https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;600;700;900&display=swap\" rel=\"stylesheet\" />\n <script src=\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js\"></script>\n <style>\n body { background: #0a0e1a; font-family: 'Montserrat', sans-serif; color: #fff; overflow: hidden; width: 1920px; height: 1080px; }\n .layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }\n </style>\n</head>\n<body id=\"app\" data-composition-id=\"main\" data-width=\"1920\" data-height=\"1080\" data-start=\"0\" data-duration=\"55\">\n <div id=\"bg-layer\" class=\"layer\" data-composition-id=\"bg\" data-width=\"1920\" data-height=\"1080\" data-start=\"0\" data-duration=\"55\"></div>\n <div id=\"content-layer\" class=\"layer\"></div>\n <script>\n window.__timelines = window.__timelines || {};\n window.__timelines['bg'] = gsap.timeline({ paused: true });\n const tl = gsap.timeline({ paused: true });\n window.__timelines.main = tl;\n\n // Set initial states\n gsap.set('#some-element', { opacity: 0 });\n // Animate in at 1s\n tl.to('#some-element', { opacity: 1, duration: 0.5 }, 1.0);\n </script>\n</body>\n</html>\n\n\n## Limitations\n\n- Termux cannot render (no Chrome/Puppeteer)\n- External fonts require internet on render PC\n- All animations: GSAP with paused: true timelines only\n- No Date.now(), no unseeded Math.random() in render code\n”}