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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:58:35 +08:00
commit 85453da49f
4031 changed files with 710987 additions and 0 deletions
+947
View File
@@ -0,0 +1,947 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>app-showcase</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #0a0a0f;
}
</style>
</head>
<body>
<div
data-composition-id="app-showcase"
data-width="1920"
data-height="1080"
data-start="0"
data-duration="5.5"
>
<!-- Background -->
<div class="s3-bg" id="s3Bg"></div>
<div class="s3-bg-glow" id="s3BgGlow"></div>
<!-- Stage wrapper for ambient scale -->
<div class="s3-stage" id="s3Stage">
<!-- ═══════════════════════════════════════
LEFT PHONE — Lifestyle / Motivational
═══════════════════════════════════════ -->
<div class="s3-phone s3-phone-left" id="s3PhoneLeft">
<div class="s3-bezel">
<div class="s3-notch"></div>
<div class="s3-screen s3-screen-left">
<!-- Abstract exercise shapes -->
<div class="left-shapes">
<svg viewBox="0 0 304 400" xmlns="http://www.w3.org/2000/svg" fill="none">
<!-- Abstract running figure — geometric -->
<circle cx="152" cy="80" r="28" fill="#271f15" opacity="0.15" />
<line
x1="152"
y1="108"
x2="152"
y2="200"
stroke="#271f15"
stroke-width="6"
stroke-linecap="round"
opacity="0.15"
/>
<line
x1="152"
y1="145"
x2="115"
y2="175"
stroke="#271f15"
stroke-width="6"
stroke-linecap="round"
opacity="0.15"
/>
<line
x1="152"
y1="145"
x2="195"
y2="165"
stroke="#271f15"
stroke-width="6"
stroke-linecap="round"
opacity="0.15"
/>
<line
x1="152"
y1="200"
x2="120"
y2="260"
stroke="#271f15"
stroke-width="6"
stroke-linecap="round"
opacity="0.15"
/>
<line
x1="152"
y1="200"
x2="190"
y2="255"
stroke="#271f15"
stroke-width="6"
stroke-linecap="round"
opacity="0.15"
/>
<!-- Decorative arcs -->
<path
d="M60 300 Q152 240 244 300"
stroke="#e4fa72"
stroke-width="3"
fill="none"
opacity="0.5"
/>
<path
d="M40 330 Q152 260 264 330"
stroke="#e4fa72"
stroke-width="2"
fill="none"
opacity="0.3"
/>
</svg>
</div>
<div class="left-bottom">
<div class="left-tagline" id="s3Tagline">Unleash Full Potential</div>
<div class="left-cta">START NOW</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════
CENTER PHONE — Dashboard (Hero)
═══════════════════════════════════════ -->
<div class="s3-phone s3-phone-center" id="s3PhoneCenter">
<div class="s3-bezel">
<div class="s3-notch"></div>
<div class="s3-screen s3-screen-center">
<!-- Header -->
<div class="center-header">
<div class="center-avatar">JM</div>
<div class="center-user-info">
<div class="center-name">James Medrano</div>
<div class="center-subtitle">Premium Member</div>
</div>
<div class="center-bell">
<svg viewBox="0 0 20 20" width="20" height="20" fill="none">
<path
d="M10 2a5 5 0 00-5 5v3l-1.5 2.5h13L15 10V7a5 5 0 00-5-5z"
stroke="#7c857c"
stroke-width="1.4"
stroke-linejoin="round"
/>
<path
d="M8 16.5a2 2 0 004 0"
stroke="#7c857c"
stroke-width="1.4"
stroke-linecap="round"
/>
<circle cx="14" cy="5" r="3" fill="#e4fa72" />
</svg>
</div>
</div>
<!-- Weekly Goal -->
<div class="center-goal">
<div class="goal-label">Weekly Goal</div>
<div class="goal-ring-wrap">
<svg class="goal-ring" viewBox="0 0 140 140">
<circle
class="ring-track"
cx="70"
cy="70"
r="52"
fill="none"
stroke="#333"
stroke-width="10"
/>
<circle
class="ring-fill"
id="s3Ring"
cx="70"
cy="70"
r="52"
fill="none"
stroke="#e4fa72"
stroke-width="10"
stroke-linecap="round"
transform="rotate(-90 70 70)"
/>
</svg>
<div class="goal-count">
<span class="goal-num">2</span>
<span class="goal-sep">/</span>
<span class="goal-den">3</span>
</div>
</div>
<div class="goal-days">
<span class="day done">M</span>
<span class="day done">T</span>
<span class="day">W</span>
<span class="day">T</span>
<span class="day">F</span>
<span class="day">S</span>
<span class="day">S</span>
</div>
</div>
<!-- Your Progress -->
<div class="center-progress">
<div class="progress-header">
<span class="progress-title">Your Progress</span>
<span class="progress-link">See all</span>
</div>
<div class="progress-bars">
<div class="bar-row">
<div class="bar-icon">
<svg viewBox="0 0 16 16" width="14" height="14" fill="none">
<path
d="M8 2l1.5 3H13l-2.5 2 1 3L8 8.5 4.5 10l1-3L3 5h3.5z"
fill="#e4fa72"
/>
</svg>
</div>
<div class="bar-info">
<span class="bar-name">Running</span>
<span class="bar-val">5.2 km</span>
</div>
<div class="bar-track"><div class="bar-value bar-v1" id="s3Bar1"></div></div>
</div>
<div class="bar-row">
<div class="bar-icon">
<svg viewBox="0 0 16 16" width="14" height="14" fill="none">
<circle cx="8" cy="8" r="5" stroke="#e4fa72" stroke-width="2" />
</svg>
</div>
<div class="bar-info">
<span class="bar-name">Cycling</span>
<span class="bar-val">12.8 km</span>
</div>
<div class="bar-track"><div class="bar-value bar-v2" id="s3Bar2"></div></div>
</div>
<div class="bar-row">
<div class="bar-icon">
<svg viewBox="0 0 16 16" width="14" height="14" fill="none">
<rect
x="3"
y="6"
width="10"
height="6"
rx="1"
stroke="#e4fa72"
stroke-width="1.5"
/>
<path d="M6 6V4a2 2 0 014 0v2" stroke="#e4fa72" stroke-width="1.5" />
</svg>
</div>
<div class="bar-info">
<span class="bar-name">Strength</span>
<span class="bar-val">45 min</span>
</div>
<div class="bar-track"><div class="bar-value bar-v3" id="s3Bar3"></div></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════
RIGHT PHONE — Calories Data
═══════════════════════════════════════ -->
<div class="s3-phone s3-phone-right" id="s3PhoneRight">
<div class="s3-bezel">
<div class="s3-notch"></div>
<div class="s3-screen s3-screen-right">
<div class="right-header">
<div class="right-title">Burned Calories</div>
<div class="right-value">740 <span class="right-unit">kcal</span></div>
</div>
<div class="right-graph-wrap">
<svg class="right-graph" viewBox="0 0 260 130" xmlns="http://www.w3.org/2000/svg">
<!-- Grid lines -->
<line
x1="10"
y1="25"
x2="250"
y2="25"
stroke="#d9e0bc"
stroke-width="0.5"
opacity="0.5"
/>
<line
x1="10"
y1="55"
x2="250"
y2="55"
stroke="#d9e0bc"
stroke-width="0.5"
opacity="0.5"
/>
<line
x1="10"
y1="85"
x2="250"
y2="85"
stroke="#d9e0bc"
stroke-width="0.5"
opacity="0.5"
/>
<line
x1="10"
y1="115"
x2="250"
y2="115"
stroke="#d9e0bc"
stroke-width="0.5"
opacity="0.5"
/>
<!-- Area fill -->
<path
class="graph-area"
id="s3GraphArea"
d="M10,105 L50,80 90,90 130,45 170,60 210,25 250,35 250,115 10,115 Z"
fill="#e4fa72"
opacity="0.15"
/>
<!-- Line -->
<polyline
class="graph-line"
id="s3GraphLine"
points="10,105 50,80 90,90 130,45 170,60 210,25 250,35"
fill="none"
stroke="#e4fa72"
stroke-width="2.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<!-- Dots -->
<circle class="graph-dot" cx="10" cy="105" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="50" cy="80" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="90" cy="90" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="130" cy="45" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="170" cy="60" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="210" cy="25" r="3.5" fill="#e4fa72" />
<circle class="graph-dot" cx="250" cy="35" r="3.5" fill="#e4fa72" />
</svg>
<div class="right-labels">
<span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span
><span>Sat</span><span>Sun</span>
</div>
</div>
<div class="right-stats">
<div class="stat-pill">
<span class="stat-dot" style="background: #e4fa72"></span>
<span class="stat-label">Active</span>
<span class="stat-num">540</span>
</div>
<div class="stat-pill">
<span class="stat-dot" style="background: #7c857c"></span>
<span class="stat-label">Rest</span>
<span class="stat-num">200</span>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap");
[data-composition-id="app-showcase"] {
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "DM Sans", sans-serif;
color: #271f15;
}
/* ── Background ── */
[data-composition-id="app-showcase"] .s3-bg {
position: absolute;
inset: 0;
background: linear-gradient(160deg, #f1f2ec 0%, #e8ecda 40%, #f1f2ec 100%);
}
[data-composition-id="app-showcase"] .s3-bg-glow {
position: absolute;
width: 900px;
height: 900px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: radial-gradient(circle, rgba(228, 250, 114, 0.18) 0%, transparent 70%);
border-radius: 50%;
}
/* ── Stage ── */
[data-composition-id="app-showcase"] .s3-stage {
position: absolute;
inset: 0;
transform-origin: center center;
}
/* ── Phones ── */
[data-composition-id="app-showcase"] .s3-phone {
position: absolute;
width: 320px;
height: 650px;
top: 215px;
left: 800px;
}
[data-composition-id="app-showcase"] .s3-phone-center {
z-index: 30;
}
[data-composition-id="app-showcase"] .s3-phone-left {
z-index: 20;
}
[data-composition-id="app-showcase"] .s3-phone-right {
z-index: 20;
}
/* ── Bezel ── */
[data-composition-id="app-showcase"] .s3-bezel {
width: 100%;
height: 100%;
border-radius: 42px;
background: #271f15;
padding: 8px;
box-shadow:
0 24px 64px rgba(39, 31, 21, 0.35),
0 4px 16px rgba(39, 31, 21, 0.15);
position: relative;
overflow: hidden;
}
[data-composition-id="app-showcase"] .s3-notch {
position: absolute;
top: 8px;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 26px;
background: #271f15;
border-radius: 0 0 18px 18px;
z-index: 5;
}
/* ── Screens ── */
[data-composition-id="app-showcase"] .s3-screen {
width: 100%;
height: 100%;
border-radius: 36px;
overflow: hidden;
position: relative;
}
/* Left screen */
[data-composition-id="app-showcase"] .s3-screen-left {
background: linear-gradient(160deg, #d9e0bc 0%, #c8d4a0 50%, #b8c78a 100%);
display: flex;
flex-direction: column;
justify-content: flex-end;
}
[data-composition-id="app-showcase"] .left-shapes {
position: absolute;
top: 40px;
left: 0;
width: 100%;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
}
[data-composition-id="app-showcase"] .left-shapes svg {
width: 200px;
height: 280px;
}
[data-composition-id="app-showcase"] .left-bottom {
padding: 0 28px 40px;
position: relative;
z-index: 2;
}
[data-composition-id="app-showcase"] .left-tagline {
font-size: 28px;
font-weight: 700;
color: #271f15;
line-height: 1.15;
margin-bottom: 16px;
letter-spacing: -0.02em;
}
[data-composition-id="app-showcase"] .left-cta {
display: inline-block;
background: #271f15;
color: #e4fa72;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.08em;
padding: 10px 28px;
border-radius: 24px;
}
/* Center screen */
[data-composition-id="app-showcase"] .s3-screen-center {
background: #1a1a1a;
padding: 42px 22px 22px;
display: flex;
flex-direction: column;
gap: 18px;
}
[data-composition-id="app-showcase"] .center-header {
display: flex;
align-items: center;
gap: 10px;
}
[data-composition-id="app-showcase"] .center-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #e4fa72, #d9e0bc);
display: flex;
align-items: center;
justify-content: center;
font-size: 15px;
font-weight: 700;
color: #271f15;
flex-shrink: 0;
}
[data-composition-id="app-showcase"] .center-user-info {
flex: 1;
}
[data-composition-id="app-showcase"] .center-name {
font-size: 18px;
font-weight: 700;
color: #f1f2ec;
line-height: 1.2;
}
[data-composition-id="app-showcase"] .center-subtitle {
font-size: 12px;
font-weight: 400;
color: #7c857c;
margin-top: 1px;
}
[data-composition-id="app-showcase"] .center-bell {
flex-shrink: 0;
}
/* Weekly Goal */
[data-composition-id="app-showcase"] .center-goal {
background: #242424;
border-radius: 20px;
padding: 18px 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
[data-composition-id="app-showcase"] .goal-label {
font-size: 15px;
font-weight: 500;
color: #7c857c;
align-self: flex-start;
}
[data-composition-id="app-showcase"] .goal-ring-wrap {
position: relative;
width: 130px;
height: 130px;
}
[data-composition-id="app-showcase"] .goal-ring {
width: 100%;
height: 100%;
}
[data-composition-id="app-showcase"] .ring-track {
opacity: 0.3;
}
[data-composition-id="app-showcase"] .goal-count {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 2px;
}
[data-composition-id="app-showcase"] .goal-num {
font-size: 36px;
font-weight: 700;
color: #e4fa72;
}
[data-composition-id="app-showcase"] .goal-sep {
font-size: 24px;
font-weight: 400;
color: #7c857c;
margin: 0 2px;
}
[data-composition-id="app-showcase"] .goal-den {
font-size: 24px;
font-weight: 400;
color: #7c857c;
}
[data-composition-id="app-showcase"] .goal-days {
display: flex;
gap: 8px;
}
[data-composition-id="app-showcase"] .day {
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 500;
color: #7c857c;
background: #1a1a1a;
}
[data-composition-id="app-showcase"] .day.done {
background: #e4fa72;
color: #271f15;
font-weight: 700;
}
/* Progress section */
[data-composition-id="app-showcase"] .center-progress {
flex: 1;
display: flex;
flex-direction: column;
gap: 12px;
}
[data-composition-id="app-showcase"] .progress-header {
display: flex;
justify-content: space-between;
align-items: center;
}
[data-composition-id="app-showcase"] .progress-title {
font-size: 15px;
font-weight: 500;
color: #f1f2ec;
}
[data-composition-id="app-showcase"] .progress-link {
font-size: 12px;
font-weight: 400;
color: #e4fa72;
}
[data-composition-id="app-showcase"] .progress-bars {
display: flex;
flex-direction: column;
gap: 12px;
}
[data-composition-id="app-showcase"] .bar-row {
display: flex;
align-items: center;
gap: 10px;
}
[data-composition-id="app-showcase"] .bar-icon {
width: 28px;
height: 28px;
border-radius: 8px;
background: #2a2a2a;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
[data-composition-id="app-showcase"] .bar-info {
width: 70px;
flex-shrink: 0;
}
[data-composition-id="app-showcase"] .bar-name {
display: block;
font-size: 12px;
font-weight: 500;
color: #f1f2ec;
line-height: 1.2;
}
[data-composition-id="app-showcase"] .bar-val {
display: block;
font-size: 10px;
font-weight: 400;
color: #7c857c;
}
[data-composition-id="app-showcase"] .bar-track {
flex: 1;
height: 8px;
background: #2a2a2a;
border-radius: 4px;
overflow: hidden;
}
[data-composition-id="app-showcase"] .bar-value {
height: 100%;
border-radius: 4px;
background: #e4fa72;
width: 0%;
}
/* Right screen */
[data-composition-id="app-showcase"] .s3-screen-right {
background: #f1f2ec;
padding: 42px 20px 24px;
display: flex;
flex-direction: column;
gap: 14px;
}
[data-composition-id="app-showcase"] .right-header {
display: flex;
flex-direction: column;
gap: 4px;
}
[data-composition-id="app-showcase"] .right-title {
font-size: 14px;
font-weight: 500;
color: #7c857c;
}
[data-composition-id="app-showcase"] .right-value {
font-size: 40px;
font-weight: 700;
color: #271f15;
line-height: 1;
letter-spacing: -0.03em;
}
[data-composition-id="app-showcase"] .right-unit {
font-size: 20px;
font-weight: 400;
color: #7c857c;
}
[data-composition-id="app-showcase"] .right-graph-wrap {
flex: 1;
display: flex;
flex-direction: column;
gap: 6px;
}
[data-composition-id="app-showcase"] .right-graph {
width: 100%;
flex: 1;
}
[data-composition-id="app-showcase"] .right-labels {
display: flex;
justify-content: space-between;
padding: 0 6px;
font-size: 10px;
font-weight: 400;
color: #7c857c;
}
[data-composition-id="app-showcase"] .right-stats {
display: flex;
gap: 12px;
}
[data-composition-id="app-showcase"] .stat-pill {
display: flex;
align-items: center;
gap: 6px;
background: #e8ecda;
border-radius: 20px;
padding: 8px 14px;
}
[data-composition-id="app-showcase"] .stat-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
[data-composition-id="app-showcase"] .stat-label {
font-size: 12px;
font-weight: 400;
color: #7c857c;
}
[data-composition-id="app-showcase"] .stat-num {
font-size: 13px;
font-weight: 700;
color: #271f15;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
(function () {
var S = '[data-composition-id="app-showcase"] ';
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
// ── SVG setup ──
var graphLine = document.querySelector(S + "#s3GraphLine");
var graphLen = graphLine.getTotalLength();
gsap.set(graphLine, { strokeDasharray: graphLen, strokeDashoffset: graphLen });
var graphArea = document.querySelector(S + "#s3GraphArea");
gsap.set(graphArea, { opacity: 0 });
var graphDots = document.querySelectorAll(S + ".graph-dot");
gsap.set(graphDots, { opacity: 0, scale: 0 });
var CIRC = 2 * 3.14159265 * 52;
gsap.set(S + "#s3Ring", { strokeDasharray: CIRC, strokeDashoffset: CIRC });
// ── Initial states ──
gsap.set(S + ".s3-bg", { opacity: 0 });
gsap.set(S + ".s3-bg-glow", { opacity: 0 });
// Center phone: starts scaled down + hidden
gsap.set(S + "#s3PhoneCenter", { opacity: 0, scale: 0.85 });
// Side phones: start stacked behind center (same position), hidden
gsap.set(S + "#s3PhoneLeft", { opacity: 0, x: 0, rotation: 0 });
gsap.set(S + "#s3PhoneRight", { opacity: 0, x: 0, rotation: 0 });
gsap.set(S + ".bar-value", { width: "0%" });
gsap.set(S + "#s3Tagline", { opacity: 0, y: 20 });
gsap.set(S + ".left-cta", { opacity: 0, y: 12 });
// ════════════════════════════════════
// BUILD PHASE (02s)
// ════════════════════════════════════
// Background
tl.to(S + ".s3-bg", { opacity: 1, duration: 0.8, ease: "power1.out" }, 0);
tl.to(S + ".s3-bg-glow", { opacity: 1, duration: 1.2, ease: "power1.out" }, 0.2);
// Center phone — scales up first
tl.to(
S + "#s3PhoneCenter",
{
scale: 1,
opacity: 1,
duration: 0.7,
ease: "back.out(1.4)",
},
0.2,
);
// Side phones: opacity matches center (0.7s, back.out), fan starts at 0.1
tl.to(S + "#s3PhoneLeft", { opacity: 1, duration: 0.7, ease: "back.out(1.4)" }, 0.3);
tl.to(
S + "#s3PhoneLeft",
{
x: -340,
rotation: -12,
duration: 1.2,
ease: "expo.out",
},
0.3,
);
tl.to(S + "#s3PhoneRight", { opacity: 1, duration: 0.7, ease: "back.out(1.4)" }, 0.4);
tl.to(
S + "#s3PhoneRight",
{
x: 340,
rotation: 12,
duration: 1.2,
ease: "expo.out",
},
0.4,
);
// ════════════════════════════════════
// BREATHE PHASE (24s)
// ════════════════════════════════════
// Progress ring fills to 2/3
tl.to(
S + "#s3Ring",
{
strokeDashoffset: CIRC * (1 - 2 / 3),
duration: 1.2,
ease: "circ.out",
},
1.8,
);
// Activity bars stagger in
tl.to(S + "#s3Bar1", { width: "75%", duration: 0.8, ease: "power3.out" }, 2.1);
tl.to(S + "#s3Bar2", { width: "50%", duration: 0.8, ease: "power3.out" }, 2.3);
tl.to(S + "#s3Bar3", { width: "90%", duration: 0.8, ease: "power3.out" }, 2.5);
// Graph line draws on
tl.to(
graphLine,
{
strokeDashoffset: 0,
duration: 1.4,
ease: "sine.inOut",
},
2.0,
);
// Graph area fades in
tl.to(graphArea, { opacity: 0.15, duration: 0.8, ease: "power1.out" }, 2.6);
// Graph dots pop in
tl.to(
graphDots,
{
opacity: 1,
scale: 1,
duration: 0.3,
ease: "back.out(2)",
stagger: { each: 0.06, ease: "power2.in" },
},
3.0,
);
// Tagline and CTA on left phone
tl.to(
S + "#s3Tagline",
{
opacity: 1,
y: 0,
duration: 0.6,
ease: "power2.out",
},
2.2,
);
tl.to(
S + ".left-cta",
{
opacity: 1,
y: 0,
duration: 0.5,
ease: "power2.out",
},
2.5,
);
// Ambient slow scale push
tl.to(
S + "#s3Stage",
{
scale: 1.02,
duration: 3.5,
ease: "sine.inOut",
},
2.0,
);
// ════════════════════════════════════
// RESOLVE PHASE (45.5s)
// ════════════════════════════════════
// Subtle glow pulse on lime accent elements
tl.to(S + ".ring-fill", { opacity: 0.65, duration: 0.6, ease: "sine.inOut" }, 4.0);
tl.to(S + ".ring-fill", { opacity: 1, duration: 0.6, ease: "sine.inOut" }, 4.6);
tl.to(S + ".bar-value", { opacity: 0.7, duration: 0.6, ease: "sine.inOut" }, 4.1);
tl.to(S + ".bar-value", { opacity: 1, duration: 0.6, ease: "sine.inOut" }, 4.7);
tl.to(graphLine, { opacity: 0.65, duration: 0.6, ease: "sine.inOut" }, 4.05);
tl.to(graphLine, { opacity: 1, duration: 0.6, ease: "sine.inOut" }, 4.65);
window.__timelines["app-showcase"] = tl;
})();
</script>
</div>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "app-showcase",
"type": "hyperframes:block",
"title": "App Showcase",
"description": "Fitness app product showcase with three floating smartphone screens",
"tags": ["showcase", "app", "3d"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 5.5,
"files": [
{
"path": "app-showcase.html",
"target": "compositions/app-showcase.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+308
View File
@@ -0,0 +1,308 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<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: #fdfefe;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #fdfefe;
color: #111315;
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
.green-flash {
position: absolute;
inset: 0;
z-index: 1;
background: #30d158;
opacity: 0;
}
.stage-content {
position: relative;
z-index: 5;
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
padding: 120px 160px;
}
.amount-wrap {
position: relative;
display: flex;
align-items: center;
justify-content: center;
min-width: 1080px;
min-height: 260px;
}
.amount {
position: relative;
color: #111315;
font-size: 190px;
font-weight: 900;
line-height: 0.9;
letter-spacing: 0;
font-variant-numeric: tabular-nums;
text-align: center;
white-space: nowrap;
text-shadow:
0 3px 0 rgba(255, 255, 255, 0.58),
0 18px 36px rgba(17, 19, 21, 0.14),
0 42px 92px rgba(17, 19, 21, 0.1);
will-change: transform, color, opacity, text-shadow;
}
.money-burst {
position: absolute;
inset: 0;
z-index: 8;
pointer-events: none;
}
.money-icon {
position: absolute;
left: 50%;
top: 50%;
display: grid;
place-items: center;
opacity: 0;
filter: drop-shadow(0 20px 24px rgba(7, 84, 31, 0.2));
will-change: transform, opacity, filter;
}
.money-icon.bill {
width: 96px;
height: 52px;
border-radius: 10px;
background: #30d158;
box-shadow:
inset 0 0 0 3px rgba(7, 84, 31, 0.2),
inset 0 -10px 18px rgba(7, 84, 31, 0.1),
0 16px 26px rgba(7, 84, 31, 0.2),
0 34px 64px rgba(7, 84, 31, 0.16);
}
.money-icon.bill::before {
position: absolute;
inset: 9px 16px;
border: 2px solid rgba(7, 84, 31, 0.28);
border-radius: 999px;
content: "";
}
.money-icon.coin {
width: 64px;
height: 64px;
border-radius: 50%;
background: radial-gradient(circle at 34% 30%, #fff7a6 0%, #ffd54f 40%, #d9a514 100%);
box-shadow:
inset 0 0 0 4px rgba(111, 76, 0, 0.12),
inset 0 -8px 14px rgba(111, 76, 0, 0.1),
0 16px 30px rgba(111, 76, 0, 0.18),
0 34px 58px rgba(111, 76, 0, 0.12);
}
.money-icon .mark {
position: relative;
z-index: 1;
color: #07541f;
font-size: 30px;
font-weight: 900;
line-height: 1;
}
.money-icon.coin .mark {
color: #6f4c00;
font-size: 28px;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="apple-money-count"
data-root="true"
data-start="0"
data-duration="5"
data-width="1920"
data-height="1080"
>
<div id="greenFlash" class="green-flash"></div>
<div class="stage-content">
<div class="amount-wrap">
<div id="amount" class="amount">$0</div>
</div>
</div>
<div id="moneyBurst" class="money-burst" data-layout-allow-overflow></div>
<audio
id="sfxTrack"
data-start="0"
data-duration="5"
data-track-index="9"
src="assets/sfx-production.wav"
data-volume="0.92"
></audio>
</div>
<script>
window.__timelines = window.__timelines || {};
const amount = document.querySelector("#amount");
const moneyBurst = document.querySelector("#moneyBurst");
const countState = { value: 0 };
function formatMoney(value) {
const bounded = Math.max(0, Math.min(10000, value));
const rounded = Math.round(bounded);
return "$" + rounded.toLocaleString("en-US");
}
function renderAmount(value) {
amount.textContent = formatMoney(value);
}
const moneyIcons = [];
const moneySpecs = [];
for (let i = 0; i < 62; i += 1) {
const icon = document.createElement("div");
const isCoin = i % 3 === 0;
icon.className = "money-icon " + (isCoin ? "coin" : "bill");
icon.innerHTML = '<span class="mark">$</span>';
moneyBurst.appendChild(icon);
moneyIcons.push(icon);
const angle = i * 2.399963229728653;
const ring = i % 5;
const radiusX = 260 + ring * 145 + (i % 7) * 12;
const radiusY = 160 + ring * 78 + (i % 6) * 12;
const offsetX = (i % 4) * 24 - 36;
const offsetY = (i % 5) * 18 - 36;
const x = Math.max(-865, Math.min(865, Math.cos(angle) * radiusX + offsetX));
const y = Math.max(-465, Math.min(465, Math.sin(angle * 1.13) * radiusY + offsetY));
moneySpecs.push({
x,
y,
delay: (i % 8) * 0.025,
duration: 0.74 + (i % 5) * 0.045,
fadeDelay: (i % 5) * 0.05,
rotation: ((i * 43) % 160) - 80,
scale: isCoin ? 0.72 + (i % 4) * 0.08 : 0.68 + (i % 5) * 0.07,
});
}
renderAmount(0);
const tl = gsap.timeline({
paused: true,
defaults: { ease: "power3.out" },
});
gsap.set(moneyIcons, {
x: 0,
y: 0,
xPercent: -50,
yPercent: -50,
opacity: 0,
scale: 0.18,
transformOrigin: "50% 50%",
});
tl.from(
"#amount",
{
y: 26,
opacity: 0,
scale: 0.985,
duration: 0.45,
ease: "power2.out",
},
0,
);
tl.to(
countState,
{
value: 10000,
duration: 3.16,
ease: "none",
onUpdate: () => renderAmount(countState.value),
onComplete: () => renderAmount(10000),
},
0,
);
tl.to(
"#amount",
{
color: "#30d158",
textShadow:
"0 3px 0 rgba(255,255,255,0.52), 0 18px 40px rgba(48,209,88,0.3), 0 46px 96px rgba(7,84,31,0.2)",
duration: 0.18,
},
3.16,
);
tl.to("#amount", { scale: 1.06, duration: 0.16, ease: "back.out(2.2)" }, 3.16);
tl.to("#amount", { scale: 1, duration: 0.23, ease: "power2.out" }, 3.33);
tl.to("#greenFlash", { opacity: 0.34, duration: 0.08, ease: "none" }, 3.16);
tl.to("#greenFlash", { opacity: 0.22, duration: 0.76, ease: "none" }, 3.24);
tl.to("#greenFlash", { opacity: 0, duration: 0.16, ease: "power2.out" }, 4);
moneyIcons.forEach((icon, i) => {
const spec = moneySpecs[i];
tl.to(
icon,
{
x: spec.x,
y: spec.y,
rotation: spec.rotation,
scale: spec.scale,
opacity: 1,
duration: spec.duration,
ease: "power4.out",
},
3.28 + spec.delay,
);
tl.to(
icon,
{
y: spec.y + (spec.y < 0 ? -58 : 58),
scale: spec.scale * 0.54,
opacity: 0,
duration: 0.38,
ease: "power2.in",
},
4.18 + spec.fadeDelay,
);
});
tl.to("#amount", { opacity: 0, scale: 0.985, duration: 0.28, ease: "power2.in" }, 4.36);
window.__timelines["apple-money-count"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,32 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "apple-money-count",
"type": "hyperframes:block",
"title": "Apple Money Count",
"description": "Apple-style finance counter that counts from $0 to $10,000, flashes green, and bursts money icons with sound.",
"tags": ["showcase", "finance", "kinetic", "youtube", "sfx"],
"author": "Stronkter",
"authorUrl": "https://x.com/Stronkter",
"sourcePrompt": "📷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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 5,
"files": [
{
"path": "apple-money-count.html",
"target": "compositions/apple-money-count.html",
"type": "hyperframes:composition"
},
{
"path": "assets/sfx-production.wav",
"target": "assets/sfx-production.wav",
"type": "hyperframes:asset"
}
],
"preview": {
"video": "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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,36 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "blue-sweater-intro-video",
"type": "hyperframes:block",
"title": "Blue Sweater Intro Video",
"description": "Warm AI creator intro sequence that resolves into an X follow card for @_blue_sweater_.",
"tags": ["showcase", "ai", "creator", "sfx"],
"author": "Joe Sai",
"authorUrl": "https://x.com/_blue_sweater_",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "blue-sweater-intro-video.html",
"target": "compositions/blue-sweater-intro-video.html",
"type": "hyperframes:composition"
},
{
"path": "assets/joe-sai-avatar.png",
"target": "assets/joe-sai-avatar.png",
"type": "hyperframes:asset"
},
{
"path": "assets/sfx/integrated-melodic-tech-mix.wav",
"target": "assets/sfx/integrated-melodic-tech-mix.wav",
"type": "hyperframes:asset"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,366 @@
<!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>
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<style>
[data-composition-id="main"] {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
background: #22223b;
}
/* Blueprint grid */
.bp-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
}
/* Layout */
.bp-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1200px;
display: flex;
align-items: center;
justify-content: center;
}
.bp-right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 720px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px 60px 60px 40px;
}
.bp-divider {
position: absolute;
left: 1200px;
top: 60px;
bottom: 60px;
width: 1px;
background: #7678ed;
opacity: 0.15;
}
.bp-number {
font-family: "Space Mono", monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.4em;
text-transform: uppercase;
position: absolute;
top: 40px;
left: 60px;
color: #7678ed;
}
/* Right panel typography */
.bp-name {
font-family: "Bebas Neue", sans-serif;
font-size: 38px;
letter-spacing: 0.08em;
margin-bottom: 20px;
color: #7678ed;
}
.bp-plabel {
font-family: "Space Mono", monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
color: #7678ed;
opacity: 0.5;
}
.bp-prompt {
font-family: "JetBrains Mono", monospace;
font-size: 20px;
line-height: 1.6;
padding: 16px 20px;
border-radius: 6px;
margin-bottom: 20px;
color: #7678ed;
background: rgba(118, 120, 237, 0.06);
border: 1px solid rgba(118, 120, 237, 0.12);
}
.bp-desc {
font-family: "Lato", sans-serif;
font-size: 17px;
line-height: 1.6;
color: #9a8c98;
opacity: 0.55;
}
/* GL scenes (hidden, just for texture capture) */
.scene {
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.scene-label {
font-family: "Bebas Neue", sans-serif;
font-size: 140px;
letter-spacing: 0.06em;
opacity: 0.12;
}
</style>
<div class="bp-grid"></div>
<div class="bp-divider"></div>
<div class="bp-number">08 / 14</div>
<!-- GL demo scenes (captured as textures, then hidden) -->
<div id="s1" class="scene" style="background: #22223b">
<div class="scene-label" style="color: #7678ed">SCENE A</div>
</div>
<div id="s2" class="scene" style="background: #7678ed; opacity: 0">
<div class="scene-label" style="color: #22223b">SCENE B</div>
</div>
<!-- GL canvas (left panel only) -->
<canvas
id="gl-canvas"
width="1200"
height="1080"
style="
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
z-index: 10;
pointer-events: none;
display: none;
"
>
</canvas>
<!-- Right panel metadata -->
<div class="bp-right">
<div class="bp-name">Chromatic Radial Split</div>
<div class="bp-plabel">Prompt</div>
<div class="bp-prompt">"use chromatic radial split shader transition"</div>
<div class="bp-desc">
RGB channels separate and converge radially. From-scene splits outward, to-scene converges
inward.
</div>
</div>
<div
id="driver"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
window.__timelines = window.__timelines || {};
var glCanvas = document.getElementById("gl-canvas");
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
if (!gl) {
console.warn("WebGL not available");
window.__timelines["main"] = gsap.timeline({ paused: true });
} else {
gl.viewport(0, 0, 1200, 1080);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
var sceneTextures = {};
function captureScene(sceneId) {
var scene = document.getElementById(sceneId);
var origOpacity = scene.style.opacity;
var origZ = scene.style.zIndex;
scene.style.opacity = "1";
scene.style.zIndex = "999";
scene.offsetHeight;
var c = document.createElement("canvas");
c.width = 1200;
c.height = 1080;
var ctx = c.getContext("2d");
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
ctx.fillRect(0, 0, 1200, 1080);
var sr = scene.getBoundingClientRect();
var els = scene.querySelectorAll("*");
for (var i = 0; i < els.length; i++) {
var el = els[i],
cs = window.getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden") continue;
var r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) continue;
var x = r.left - sr.left,
y = r.top - sr.top,
w = r.width,
h = r.height;
ctx.save();
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
var bg = cs.backgroundColor;
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
ctx.fillStyle = bg;
ctx.fillRect(x, y, w, h);
}
var hasChildEls = el.querySelector("div,span,img,video");
var text = "";
for (var j = 0; j < el.childNodes.length; j++)
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
text = text.trim();
if (text && !hasChildEls) {
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
ctx.fillStyle = cs.color;
if (cs.letterSpacing && cs.letterSpacing !== "normal")
ctx.letterSpacing = cs.letterSpacing;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, x + w / 2, y + h / 2);
}
ctx.restore();
}
scene.style.opacity = origOpacity;
scene.style.zIndex = origZ;
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
sceneTextures[sceneId] = tex;
}
var vertSrc =
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
var quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
gl.STATIC_DRAW,
);
function compileShader(src, type) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
console.error("Shader:", gl.getShaderInfoLog(s));
return s;
}
function mkProg(fragSrc) {
var p = gl.createProgram();
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
console.error("Link:", gl.getProgramInfoLog(p));
return p;
}
var H =
"precision mediump float;" +
"varying vec2 v_uv;" +
"uniform sampler2D u_from, u_to;" +
"uniform float u_progress;" +
"uniform vec2 u_resolution;\n";
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
var progTrans = mkProg(
H +
"void main(){vec2 c=v_uv-.5;float fromShift=u_progress*.06;float fr=texture2D(u_from,clamp(v_uv+c*fromShift,0.,1.)).r;float fg=texture2D(u_from,v_uv).g;float fb=texture2D(u_from,clamp(v_uv-c*fromShift,0.,1.)).b;vec3 fromSplit=vec3(fr,fg,fb);float toShift=(1.-u_progress)*.06;float tr=texture2D(u_to,clamp(v_uv-c*toShift,0.,1.)).r;float tg=texture2D(u_to,v_uv).g;float tb=texture2D(u_to,clamp(v_uv+c*toShift,0.,1.)).b;vec3 toSplit=vec3(tr,tg,tb);gl_FragColor=vec4(mix(fromSplit,toSplit,u_progress),1.);}",
);
function renderShader(prog, texFrom, texTo, progress) {
gl.useProgram(prog);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texFrom);
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texTo);
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
var pos = gl.getAttribLocation(prog, "a_pos");
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function easeInOut(p) {
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
}
captureScene("s1");
captureScene("s2");
glCanvas.style.display = "block";
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
document.querySelectorAll(".scene").forEach(function (s) {
s.style.opacity = "0";
});
var tl = gsap.timeline({
paused: true,
onUpdate: function () {
var t = tl.time();
if (t >= 1.0 && t < 3.0) {
renderShader(
progTrans,
sceneTextures["s1"],
sceneTextures["s2"],
easeInOut((t - 1.0) / 2.0),
);
} else if (t >= 3.0) {
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
} else {
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
}
},
});
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
window.__timelines["main"] = tl;
} // end if (gl)
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "chromatic-radial-split",
"type": "hyperframes:block",
"title": "Chromatic Radial Split",
"description": "Shader transition with chromatic aberration radial split",
"tags": ["transition", "shader"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "chromatic-radial-split.html",
"target": "compositions/chromatic-radial-split.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+366
View File
@@ -0,0 +1,366 @@
<!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>
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<style>
[data-composition-id="main"] {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
background: #3d348b;
}
/* Blueprint grid */
.bp-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
}
/* Layout */
.bp-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1200px;
display: flex;
align-items: center;
justify-content: center;
}
.bp-right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 720px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px 60px 60px 40px;
}
.bp-divider {
position: absolute;
left: 1200px;
top: 60px;
bottom: 60px;
width: 1px;
background: #f7b801;
opacity: 0.15;
}
.bp-number {
font-family: "Space Mono", monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.4em;
text-transform: uppercase;
position: absolute;
top: 40px;
left: 60px;
color: #f7b801;
}
/* Right panel typography */
.bp-name {
font-family: "Bebas Neue", sans-serif;
font-size: 38px;
letter-spacing: 0.08em;
margin-bottom: 20px;
color: #f7b801;
}
.bp-plabel {
font-family: "Space Mono", monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
color: #f7b801;
opacity: 0.5;
}
.bp-prompt {
font-family: "JetBrains Mono", monospace;
font-size: 20px;
line-height: 1.6;
padding: 16px 20px;
border-radius: 6px;
margin-bottom: 20px;
color: #f7b801;
background: rgba(247, 184, 1, 0.06);
border: 1px solid rgba(247, 184, 1, 0.12);
}
.bp-desc {
font-family: "Lato", sans-serif;
font-size: 17px;
line-height: 1.6;
color: #a0a0c0;
opacity: 0.55;
}
/* GL scenes (hidden, just for texture capture) */
.scene {
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.scene-label {
font-family: "Bebas Neue", sans-serif;
font-size: 140px;
letter-spacing: 0.06em;
opacity: 0.12;
}
</style>
<div class="bp-grid"></div>
<div class="bp-divider"></div>
<div class="bp-number">07 / 14</div>
<!-- GL demo scenes (captured as textures, then hidden) -->
<div id="s1" class="scene" style="background: #3d348b">
<div class="scene-label" style="color: #f7b801">SCENE A</div>
</div>
<div id="s2" class="scene" style="background: #f7b801; opacity: 0">
<div class="scene-label" style="color: #3d348b">SCENE B</div>
</div>
<!-- GL canvas (left panel only) -->
<canvas
id="gl-canvas"
width="1200"
height="1080"
style="
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
z-index: 10;
pointer-events: none;
display: none;
"
>
</canvas>
<!-- Right panel metadata -->
<div class="bp-right">
<div class="bp-name">Cinematic Zoom</div>
<div class="bp-plabel">Prompt</div>
<div class="bp-prompt">"use cinematic zoom shader transition"</div>
<div class="bp-desc">
Both scenes zoom-blur with per-channel radial offset. From zooms outward, to zooms inward
from tight.
</div>
</div>
<div
id="driver"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
window.__timelines = window.__timelines || {};
var glCanvas = document.getElementById("gl-canvas");
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
if (!gl) {
console.warn("WebGL not available");
window.__timelines["main"] = gsap.timeline({ paused: true });
} else {
gl.viewport(0, 0, 1200, 1080);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
var sceneTextures = {};
function captureScene(sceneId) {
var scene = document.getElementById(sceneId);
var origOpacity = scene.style.opacity;
var origZ = scene.style.zIndex;
scene.style.opacity = "1";
scene.style.zIndex = "999";
scene.offsetHeight;
var c = document.createElement("canvas");
c.width = 1200;
c.height = 1080;
var ctx = c.getContext("2d");
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
ctx.fillRect(0, 0, 1200, 1080);
var sr = scene.getBoundingClientRect();
var els = scene.querySelectorAll("*");
for (var i = 0; i < els.length; i++) {
var el = els[i],
cs = window.getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden") continue;
var r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) continue;
var x = r.left - sr.left,
y = r.top - sr.top,
w = r.width,
h = r.height;
ctx.save();
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
var bg = cs.backgroundColor;
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
ctx.fillStyle = bg;
ctx.fillRect(x, y, w, h);
}
var hasChildEls = el.querySelector("div,span,img,video");
var text = "";
for (var j = 0; j < el.childNodes.length; j++)
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
text = text.trim();
if (text && !hasChildEls) {
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
ctx.fillStyle = cs.color;
if (cs.letterSpacing && cs.letterSpacing !== "normal")
ctx.letterSpacing = cs.letterSpacing;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, x + w / 2, y + h / 2);
}
ctx.restore();
}
scene.style.opacity = origOpacity;
scene.style.zIndex = origZ;
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
sceneTextures[sceneId] = tex;
}
var vertSrc =
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
var quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
gl.STATIC_DRAW,
);
function compileShader(src, type) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
console.error("Shader:", gl.getShaderInfoLog(s));
return s;
}
function mkProg(fragSrc) {
var p = gl.createProgram();
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
console.error("Link:", gl.getProgramInfoLog(p));
return p;
}
var H =
"precision mediump float;" +
"varying vec2 v_uv;" +
"uniform sampler2D u_from, u_to;" +
"uniform float u_progress;" +
"uniform vec2 u_resolution;\n";
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
var progTrans = mkProg(
H +
"void main(){vec2 d=v_uv-vec2(.5);float fromS=u_progress*.08;float toS=(1.-u_progress)*.06;float fr=0.,fg=0.,fb=0.;for(int i=0;i<12;i++){float f=float(i)/12.;fr+=texture2D(u_from,v_uv-d*(fromS*1.06)*f).r;fg+=texture2D(u_from,v_uv-d*fromS*f).g;fb+=texture2D(u_from,v_uv-d*(fromS*.94)*f).b;}vec3 fromBl=vec3(fr,fg,fb)/12.;float tr=0.,tg=0.,tb=0.;for(int i=0;i<12;i++){float f=float(i)/12.;tr+=texture2D(u_to,v_uv+d*(toS*1.06)*f).r;tg+=texture2D(u_to,v_uv+d*toS*f).g;tb+=texture2D(u_to,v_uv+d*(toS*.94)*f).b;}vec3 toBl=vec3(tr,tg,tb)/12.;gl_FragColor=vec4(mix(fromBl,toBl,u_progress),1.);}",
);
function renderShader(prog, texFrom, texTo, progress) {
gl.useProgram(prog);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texFrom);
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texTo);
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
var pos = gl.getAttribLocation(prog, "a_pos");
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function easeInOut(p) {
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
}
captureScene("s1");
captureScene("s2");
glCanvas.style.display = "block";
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
document.querySelectorAll(".scene").forEach(function (s) {
s.style.opacity = "0";
});
var tl = gsap.timeline({
paused: true,
onUpdate: function () {
var t = tl.time();
if (t >= 1.0 && t < 3.0) {
renderShader(
progTrans,
sceneTextures["s1"],
sceneTextures["s2"],
easeInOut((t - 1.0) / 2.0),
);
} else if (t >= 3.0) {
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
} else {
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
}
},
});
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
window.__timelines["main"] = tl;
} // end if (gl)
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "cinematic-zoom",
"type": "hyperframes:block",
"title": "Cinematic Zoom",
"description": "Shader transition with dramatic zoom blur",
"tags": ["transition", "shader"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "cinematic-zoom.html",
"target": "compositions/cinematic-zoom.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+613
View File
@@ -0,0 +1,613 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code 3D Extrude</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.147.0/build/three.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
background: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
}
#gl {
position: absolute;
inset: 0;
width: 1920px;
height: 1080px;
display: block;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-3d-extrude"
data-start="0"
data-duration="8"
data-width="1920"
data-height="1080"
>
<canvas id="gl" width="1920" height="1080"></canvas>
</div>
<script>
window.__TOKENS = {
feature: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: 'async function loadConfig(path) {\n const raw = await readFile(path, "utf8")\n const config = JSON.parse(raw)\n return validate(config)\n}',
tokens: [
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-0",
content: "async",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-2",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-4",
content: "loadConfig",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-5",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-6",
content: "path",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-7",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-9",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-10",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-11",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-12",
content: "raw",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-13",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-14",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-15",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-16",
content: "await",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-17",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-18",
content: "readFile",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-19",
content: "(path,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-20",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-21",
content: '"utf8"',
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-22",
content: ")",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-23",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-24",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-25",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-26",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-27",
content: "config",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-28",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-29",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-30",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-31",
content: "JSON",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-32",
content: ".",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-33",
content: "parse",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-34",
content: "(raw)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-35",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-36",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-37",
content: "return",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-38",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-39",
content: "validate",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-40",
content: "(config)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-41",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-42",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-43",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = {
id: "code-3d-extrude",
effect: "extrude",
seq: "feature",
duration: 8,
seed: 7,
};
</script>
<script>
// hf-code-anim-gl.js — WebGL code-animation engine for the "crazy" Code Animations blocks.
//
// Bridges the baked Shiki tokens (window.__TOKENS) into Three.js: the tokens are drawn once
// to an offscreen 2D canvas (a CanvasTexture), which then drives a lit 3D slab, a dissolve
// shader, or a GPU particle system. Determinism per the project contract:
// - render only via tl.eventCallback("onUpdate", …) + one initial render() — never rAF
// - all randomness from a seeded mulberry32 — never Math.random / Date.now
// - canvas drawn once after document.fonts.ready (final glyph metrics)
// - paused GSAP timeline registered on window.__timelines[id]; HF seeks it per frame
//
// Each block sets window.__BLOCK = { id, effect, seq, duration, seed } and includes this engine.
(function () {
"use strict";
var T = window.__TOKENS || {};
// ---- seeded PRNG (no Math.random) -----------------------------------------
function mulberry32(a) {
return function () {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
var t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// ---- split a token state into lines of {content,color} --------------------
function splitLines(state) {
var lines = [[]];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push([]);
continue;
}
lines[lines.length - 1].push(t);
}
while (lines.length && lines[lines.length - 1].length === 0) lines.pop();
return lines;
}
// ---- THE BRIDGE: draw baked tokens to an offscreen 2D canvas ---------------
// Returns { canvas, W, H, lines, lineH, padY, fontPx } so effects can sample it.
function drawCodeToCanvas(state, opts) {
opts = opts || {};
var fontPx = opts.fontPx || 36;
var lineH = opts.lineH || 54;
var padX = opts.padX || 70;
var padY = opts.padY || 60;
var weight = opts.weight || 500;
var font = weight + " " + fontPx + 'px "JetBrains Mono", monospace';
var lines = splitLines(state);
var measure = document.createElement("canvas").getContext("2d");
measure.font = font;
var maxW = 0;
for (var i = 0; i < lines.length; i++) {
var w = 0;
for (var j = 0; j < lines[i].length; j++)
w += measure.measureText(lines[i][j].content).width;
if (w > maxW) maxW = w;
}
var W = Math.max(2, Math.ceil(maxW + padX * 2));
var H = Math.max(2, Math.ceil(lines.length * lineH + padY * 2));
var canvas = document.createElement("canvas");
canvas.width = W;
canvas.height = H;
var ctx = canvas.getContext("2d");
if (opts.transparent) {
ctx.clearRect(0, 0, W, H);
} else {
ctx.fillStyle = opts.bg || "#0b0f17";
ctx.fillRect(0, 0, W, H);
}
ctx.textBaseline = "top";
ctx.font = font;
for (var li = 0; li < lines.length; li++) {
var x = padX;
var y = padY + li * lineH;
for (var k = 0; k < lines[li].length; k++) {
var tok = lines[li][k];
ctx.fillStyle = tok.color;
ctx.fillText(tok.content, x, y);
x += ctx.measureText(tok.content).width;
}
}
return {
canvas: canvas,
W: W,
H: H,
lines: lines.length,
lineH: lineH,
padY: padY,
fontPx: fontPx,
};
}
function fxExtrude(THREE, scene, camera, renderer, state, st, tl, dur) {
scene.background = new THREE.Color(0x05070b);
var code = drawCodeToCanvas(state, {
fontPx: 38,
lineH: 56,
padX: 80,
padY: 70,
weight: 600,
});
var tex = new THREE.CanvasTexture(code.canvas);
tex.minFilter = THREE.LinearFilter;
tex.magFilter = THREE.LinearFilter;
tex.generateMipmaps = false;
var aspect = code.W / code.H;
var slabH = 6.2;
var slabW = slabH * aspect;
var depth = 0.5;
// beveled slab: rounded extruded rectangle
var hw = slabW / 2;
var hh = slabH / 2;
var r = 0.18;
var shape = new THREE.Shape();
shape.moveTo(-hw + r, -hh);
shape.lineTo(hw - r, -hh);
shape.quadraticCurveTo(hw, -hh, hw, -hh + r);
shape.lineTo(hw, hh - r);
shape.quadraticCurveTo(hw, hh, hw - r, hh);
shape.lineTo(-hw + r, hh);
shape.quadraticCurveTo(-hw, hh, -hw, hh - r);
shape.lineTo(-hw, -hh + r);
shape.quadraticCurveTo(-hw, -hh, -hw + r, -hh);
var geo = new THREE.ExtrudeGeometry(shape, {
depth: depth,
bevelEnabled: true,
bevelThickness: 0.12,
bevelSize: 0.1,
bevelSegments: 3,
steps: 1,
});
geo.center();
// UVs from ExtrudeGeometry don't map the texture nicely to the face; remap front-face UVs from XY bounds.
geo.computeBoundingBox();
var bb = geo.boundingBox;
var sizeX = bb.max.x - bb.min.x;
var sizeY = bb.max.y - bb.min.y;
var pos = geo.attributes.position;
var uv = geo.attributes.uv;
for (var vi = 0; vi < pos.count; vi++) {
uv.setXY(vi, (pos.getX(vi) - bb.min.x) / sizeX, (pos.getY(vi) - bb.min.y) / sizeY);
}
uv.needsUpdate = true;
// Face is an unlit "screen" — shows the exact vivid Shiki colors (no PBR/emissive wash).
// The 3D read comes from the lit, beveled EDGES + perspective, like a glowing monitor.
var faceMat = new THREE.MeshBasicMaterial({ map: tex });
var edgeMat = new THREE.MeshStandardMaterial({
color: 0x141d2b,
roughness: 0.3,
metalness: 0.4,
});
// ExtrudeGeometry groups: 0 = front+back faces, 1 = sides. Front shows the code.
var slab = new THREE.Mesh(geo, [faceMat, edgeMat]);
scene.add(slab);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
var key = new THREE.DirectionalLight(0xbcd4ff, 1.25);
key.position.set(5, 7, 9);
scene.add(key);
var rim = new THREE.DirectionalLight(0x4fffa0, 0.45);
rim.position.set(-7, -3, 5);
scene.add(rim);
camera.position.set(0, 0, 10);
// fit camera distance so the WHOLE slab fits (width-limited for wide code), ~78% fill
var vfov = (camera.fov * Math.PI) / 180;
var screenAspect = 1920 / 1080;
var fitH = slabH / 2 / Math.tan(vfov / 2) / 0.78;
var fitW = slabW / 2 / (Math.tan(vfov / 2) * screenAspect) / 0.78;
var fitZ = Math.max(fitH, fitW);
st.rotY = -1.0;
st.rotX = 0.4;
st.camZ = fitZ + 6;
tl.to(st, { rotY: 0, rotX: 0, camZ: fitZ, duration: dur * 0.6, ease: "power3.out" }, 0);
// gentle breathing drift at rest (subtle — stays readable)
tl.to(
st,
{ rotY: 0.06, rotX: -0.02, duration: dur * 0.4, ease: "sine.inOut" },
dur * 0.6,
);
return function () {
slab.rotation.y = st.rotY;
slab.rotation.x = st.rotX;
camera.position.z = st.camZ;
camera.lookAt(0, 0, 0);
// boot loop's render() issues the single renderer.render() — don't double-render here
};
}
// ---- dispatch + boot ------------------------------------------------------
function buildEffect(THREE, scene, camera, renderer, spec, st, tl) {
var state = T[spec.seq].states[0];
var dur = spec.duration;
if (spec.effect === "extrude")
return fxExtrude(THREE, scene, camera, renderer, state, st, tl, dur);
return function () {};
}
// Free GPU resources (renderer, geometries, materials, textures) on page teardown.
// One-shot renders exit per job so nothing leaks there; this guards long-lived
// Studio/player sessions that reload. Fires only on unload — never during capture.
function disposeGL(renderer, scene) {
scene.traverse(function (o) {
if (o.geometry && o.geometry.dispose) o.geometry.dispose();
var mats = o.material ? (Array.isArray(o.material) ? o.material : [o.material]) : [];
mats.forEach(function (m) {
if (m.map && m.map.dispose) m.map.dispose();
if (
m.uniforms &&
m.uniforms.uTex &&
m.uniforms.uTex.value &&
m.uniforms.uTex.value.dispose
) {
m.uniforms.uTex.value.dispose();
}
if (m.dispose) m.dispose();
});
});
if (renderer.dispose) renderer.dispose();
}
function go() {
var spec = window.__BLOCK;
var root = document.getElementById("root");
var glcanvas = document.getElementById("gl");
var W = 1920;
var H = 1080;
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
window.__timelines[spec.id] = tl; // register synchronously
var THREE = window.THREE;
var renderer = new THREE.WebGLRenderer({
canvas: glcanvas,
antialias: true,
alpha: false,
preserveDrawingBuffer: true,
});
renderer.setPixelRatio(1);
renderer.setSize(W, H, false);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, W / H, 0.1, 200);
var st = {};
document.fonts.ready.then(function () {
var renderFn = buildEffect(THREE, scene, camera, renderer, spec, st, tl);
function render() {
renderFn();
renderer.render(scene, camera);
}
tl.eventCallback("onUpdate", render);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
render(); // paint frame 0
window.addEventListener("beforeunload", function () {
disposeGL(renderer, scene);
});
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-3d-extrude",
"type": "hyperframes:block",
"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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 8,
"tags": ["code", "code-animation", "3d", "webgl", "developer"],
"files": [
{
"path": "code-3d-extrude.html",
"target": "compositions/code-3d-extrude.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+816
View File
@@ -0,0 +1,816 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Diff</title>
<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: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
font-family: "JetBrains Mono", monospace;
color: #e6edf3;
}
.bg-field {
position: absolute;
inset: 0;
background: radial-gradient(1200px 700px at 50% 18%, #0e1726 0%, #070b12 55%, #05070b 100%);
}
.bg-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(88, 166, 255, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(88, 166, 255, 0.05) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(1100px 620px at 50% 42%, #000 0%, transparent 78%);
}
.bg-glow {
position: absolute;
width: 900px;
height: 900px;
border-radius: 50%;
filter: blur(120px);
opacity: 0.5;
}
.bg-glow.a {
background: #1f6feb55;
left: -180px;
top: -200px;
}
.bg-glow.b {
background: #2ea04355;
right: -200px;
bottom: -260px;
}
.editor {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 1380px;
height: 800px;
background: #0b0f17;
border: 1px solid #1d2733;
border-radius: 16px;
box-shadow:
0 40px 120px rgba(0, 0, 0, 0.6),
0 2px 0 rgba(255, 255, 255, 0.03) inset;
overflow: hidden;
display: flex;
flex-direction: column;
}
.titlebar {
height: 56px;
flex: 0 0 56px;
display: flex;
align-items: center;
gap: 16px;
padding: 0 22px;
background: linear-gradient(#11161f, #0c111a);
border-bottom: 1px solid #1b2430;
}
.dots {
display: flex;
gap: 10px;
}
.dot {
width: 14px;
height: 14px;
border-radius: 50%;
}
.dot.r {
background: #ff5f57;
}
.dot.y {
background: #febc2e;
}
.dot.g {
background: #28c840;
}
.filename {
font-size: 19px;
color: #8b98a9;
letter-spacing: 0.2px;
}
.filename .accent {
color: #d6e2f0;
}
.code-surface {
position: relative;
flex: 1 1 auto;
overflow: hidden;
}
.scene {
position: absolute;
inset: 0;
opacity: 0;
will-change: opacity;
}
.code {
position: absolute;
top: 38px;
left: 0;
right: 0;
padding: 0 44px 0 104px;
font-size: 30px;
line-height: 46px;
font-variant-ligatures: none;
tab-size: 2;
}
.gutter {
position: absolute;
top: 38px;
left: 0;
width: 84px;
padding-right: 18px;
font-size: 30px;
line-height: 46px;
text-align: right;
color: #828c9b;
user-select: none;
}
.ln {
display: block;
height: 46px;
}
.line {
display: block;
min-height: 46px;
white-space: pre;
position: relative;
z-index: 1;
}
.tok {
display: inline-block;
white-space: pre;
will-change: transform, opacity;
}
.caret {
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 32px;
margin-top: 6px;
background: #58a6ff;
border-radius: 1px;
z-index: 3;
}
.hl-box {
position: absolute;
background: rgba(88, 166, 255, 0.16);
border-left: 3px solid #58a6ff;
border-radius: 6px;
z-index: 0;
overflow: hidden;
}
.diff-line {
display: block;
min-height: 0;
line-height: 46px;
white-space: pre;
position: relative;
overflow: hidden;
padding-left: 14px;
}
.diff-sign {
display: inline-block;
width: 22px;
color: #41506220;
}
.diff-del {
background: rgba(248, 81, 73, 0.12);
box-shadow: inset 3px 0 #f85149;
}
.diff-add {
background: rgba(63, 185, 80, 0.12);
box-shadow: inset 3px 0 #3fb950;
}
.diff-del .diff-sign {
color: #f85149;
}
.diff-add .diff-sign {
color: #3fb950;
}
.flight-block {
position: absolute;
white-space: pre;
font-size: 27px;
line-height: 40px;
padding: 11px 22px;
border-radius: 11px;
background: #0f1722;
border: 1px solid #233044;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
will-change: transform, opacity;
}
.flight-target {
position: absolute;
border: 1.5px dashed #2a3a4f;
border-radius: 14px;
opacity: 0;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-diff"
data-start="0"
data-duration="6"
data-width="1920"
data-height="1080"
>
<div class="bg-field" data-layout-ignore></div>
<div class="bg-grid" data-layout-ignore></div>
<div class="bg-glow a" data-layout-ignore></div>
<div class="bg-glow b" data-layout-ignore></div>
<div class="editor" id="editor" data-layout-ignore>
<div class="titlebar">
<div class="dots">
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
</div>
<span class="filename"><span class="accent">greet.js</span> — Code Diff</span>
</div>
<div class="code-surface" id="surface"></div>
</div>
</div>
<script>
window.__TOKENS = {
diff: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: 'function greet(name) {\n console.log("hi " + name)\n}',
tokens: [
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-0",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-2",
content: "greet",
color: "#B392F0",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-3",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-4",
content: "name",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-5",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-6",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-7",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-8",
content: "console.",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-9",
content: "log",
color: "#B392F0",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-10",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-11",
content: '"hi "',
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-12",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-13",
content: "+",
color: "#F97583",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-14",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-15",
content: "name)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-16",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-17",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-18",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
{
code: 'function greet(name, lang) {\n const msg = translate("hi", lang)\n console.log(`${msg} ${name}`)\n}',
tokens: [
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-0",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-2",
content: "greet",
color: "#B392F0",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-3",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-4",
content: "name",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-5",
content: ",",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-6",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-7",
content: "lang",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-5",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-6",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-7",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-11",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-12",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-13",
content: "msg",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-14",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-15",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-16",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-17",
content: "translate",
color: "#B392F0",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-10",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-19",
content: '"hi"',
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-20",
content: ", lang)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-21",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-22",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-23",
content: "console.",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-9",
content: "log",
color: "#B392F0",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-25",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-26",
content: "`${",
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-27",
content: "msg",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-28",
content: "} ${",
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-29",
content: "name",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-30",
content: "}`",
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-31",
content: ")",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-16",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "97wperY-uI8_OA5W5UX94Q5keKEoIobaKXQ6V8Tcd5I-17",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "w2rmoAdPXgC70S4pDXgHIIwz8Jqq0QKYf1B6jvTMUJ8-34",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = { id: "code-diff", effect: "diff", seq: "diff", duration: 6 };
</script>
<script>
// hf-code-anim.js — self-contained code-animation engine for HyperFrames registry blocks.
//
// Reuses Shiki Magic Move's baked output (window.__TOKENS, baked at author time) and
// drives the animation as a PAUSED GSAP timeline the HyperFrames engine seeks per frame —
// NOT CSS transitions (those break under non-sequential frame seeking). FLIP measurement
// runs once inside document.fonts.ready (glyph metrics must be final). Each block sets
// window.__BLOCK = { id, effect, seq, line?, duration } and includes this engine; the
// engine builds one scene that fills the composition and registers window.__timelines[id].
(function () {
"use strict";
var T = window.__TOKENS || {};
function lineDiv() {
var d = document.createElement("div");
d.className = "line";
return d;
}
// Render a code state's keyed tokens into codeEl as lines of inline-block .tok spans.
function renderState(codeEl, state) {
codeEl.textContent = "";
var keyToEl = new Map();
var line = lineDiv();
codeEl.appendChild(line);
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
line = lineDiv();
codeEl.appendChild(line);
continue;
}
var span = document.createElement("span");
span.className = "tok";
span.textContent = t.content;
span.style.color = t.color;
if (t.fontStyle & 1) span.style.fontStyle = "italic";
if (t.fontStyle & 2) span.style.fontWeight = "700";
line.appendChild(span);
keyToEl.set(t.key, span);
}
var last = codeEl.lastChild;
if (last && last.className === "line" && last.children.length === 0)
codeEl.removeChild(last);
return keyToEl;
}
function rectsOf(keyToEl) {
var m = new Map();
keyToEl.forEach(function (el, k) {
var r = el.getBoundingClientRect();
m.set(k, { left: r.left, top: r.top });
});
return m;
}
function makeScene(surface, withGutter) {
var scene = document.createElement("div");
scene.className = "scene";
if (withGutter) {
var g = document.createElement("div");
g.className = "gutter";
scene.appendChild(g);
}
var code = document.createElement("div");
code.className = "code";
scene.appendChild(code);
surface.appendChild(scene);
return { scene: scene, code: code, gutter: scene.querySelector(".gutter") };
}
function fillGutter(g, n) {
var html = "";
for (var i = 1; i <= n; i++) html += '<span class="ln">' + i + "</span>";
g.innerHTML = html;
}
function splitLines(state) {
var lines = [{ text: "", tokens: [] }];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push({ text: "", tokens: [] });
continue;
}
var cur = lines[lines.length - 1];
cur.tokens.push(t);
cur.text += t.content;
}
if (lines.length && lines[lines.length - 1].tokens.length === 0) lines.pop();
return lines;
}
function lineDiff(a, b) {
var n = a.length;
var m = b.length;
var dp = [];
for (var i = 0; i <= n; i++) dp.push(new Array(m + 1).fill(0));
for (var i = n - 1; i >= 0; i--) {
for (var j = m - 1; j >= 0; j--) {
dp[i][j] =
a[i].text === b[j].text
? dp[i + 1][j + 1] + 1
: Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
var ops = [];
var i = 0;
var j = 0;
while (i < n && j < m) {
if (a[i].text === b[j].text) {
ops.push({ type: "same", line: b[j] });
i++;
j++;
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
ops.push({ type: "del", line: a[i] });
i++;
} else {
ops.push({ type: "add", line: b[j] });
j++;
}
}
while (i < n) ops.push({ type: "del", line: a[i++] });
while (j < m) ops.push({ type: "add", line: b[j++] });
return ops;
}
// ---- single-scene effect builders (fade in, play, hold to end) -------------
var FADE = 0.45;
function diff(tl, surface, states, start) {
var DEL = 0.55;
var ADD = 0.6;
var ops = lineDiff(splitLines(states[0]), splitLines(states[1]));
var parts = makeScene(surface, false);
var code = parts.code;
var delEls = [];
var addEls = [];
ops.forEach(function (op) {
var ln = document.createElement("div");
ln.className =
"diff-line" +
(op.type === "del" ? " diff-del" : op.type === "add" ? " diff-add" : "");
var sign = document.createElement("span");
sign.className = "diff-sign";
sign.textContent = op.type === "del" ? "- " : op.type === "add" ? "+ " : " ";
ln.appendChild(sign);
op.line.tokens.forEach(function (t) {
var s = document.createElement("span");
s.className = "tok";
s.textContent = t.content;
s.style.color = t.color;
ln.appendChild(s);
});
code.appendChild(ln);
if (op.type === "del") delEls.push(ln);
if (op.type === "add") addEls.push(ln);
});
tl.set(parts.scene, { opacity: 0 }, 0);
tl.to(parts.scene, { opacity: 1, duration: FADE, ease: "power1.out" }, start);
var atDel = start + FADE + 0.3;
delEls.forEach(function (el, k) {
tl.fromTo(
el,
{ height: 46, opacity: 1 },
{ height: 0, opacity: 0, duration: DEL, ease: "power2.inOut" },
atDel + k * 0.08,
);
});
var atAdd = atDel + DEL + 0.15;
addEls.forEach(function (el, k) {
tl.set(el, { height: 0, opacity: 0 }, 0);
tl.fromTo(
el,
{ height: 0, opacity: 0 },
{ height: 46, opacity: 1, duration: ADD, ease: "power2.out" },
atAdd + k * 0.12,
);
});
}
function buildEffect(tl, surface, spec) {
var start = 0.45;
var seq = T[spec.seq];
if (spec.effect === "diff") diff(tl, surface, seq.states, start);
}
function go() {
var spec = window.__BLOCK;
var surface = document.getElementById("surface");
var root = document.getElementById("root");
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
// Build inside fonts.ready (glyph metrics must be final), then register.
// Register ONLY after the timeline is fully built: the runtime's
// sub-composition readiness gate treats "key present" as "ready" and
// nests the child once. An empty timeline registered before this build
// would be nested empty and never re-nested → blank render when used as
// a sub-composition. See the contract in engine frameCapture.ts.
document.fonts.ready.then(function () {
tl.from("#editor", { opacity: 0, scale: 0.985, duration: 0.5, ease: "power2.out" }, 0);
buildEffect(tl, surface, spec);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
window.__timelines["code-diff"] = tl; // register AFTER setup completes
if (typeof window.__hfForceTimelineRebind === "function") {
window.__hfForceTimelineRebind(); // re-nest now that we are populated
}
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-diff",
"type": "hyperframes:block",
"title": "Code Diff",
"description": "An edit shown as a colored diff — removed lines collapse in red, added lines expand in green.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 6,
"tags": ["code", "code-animation", "diff", "developer"],
"files": [
{
"path": "code-diff.html",
"target": "compositions/code-diff.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+745
View File
@@ -0,0 +1,745 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Highlight Sweep</title>
<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: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
font-family: "JetBrains Mono", monospace;
color: #e6edf3;
}
.bg-field {
position: absolute;
inset: 0;
background: radial-gradient(1200px 700px at 50% 18%, #0e1726 0%, #070b12 55%, #05070b 100%);
}
.bg-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(88, 166, 255, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(88, 166, 255, 0.05) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(1100px 620px at 50% 42%, #000 0%, transparent 78%);
}
.bg-glow {
position: absolute;
width: 900px;
height: 900px;
border-radius: 50%;
filter: blur(120px);
opacity: 0.5;
}
.bg-glow.a {
background: #1f6feb55;
left: -180px;
top: -200px;
}
.bg-glow.b {
background: #2ea04355;
right: -200px;
bottom: -260px;
}
.editor {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 1380px;
height: 800px;
background: #0b0f17;
border: 1px solid #1d2733;
border-radius: 16px;
box-shadow:
0 40px 120px rgba(0, 0, 0, 0.6),
0 2px 0 rgba(255, 255, 255, 0.03) inset;
overflow: hidden;
display: flex;
flex-direction: column;
}
.titlebar {
height: 56px;
flex: 0 0 56px;
display: flex;
align-items: center;
gap: 16px;
padding: 0 22px;
background: linear-gradient(#11161f, #0c111a);
border-bottom: 1px solid #1b2430;
}
.dots {
display: flex;
gap: 10px;
}
.dot {
width: 14px;
height: 14px;
border-radius: 50%;
}
.dot.r {
background: #ff5f57;
}
.dot.y {
background: #febc2e;
}
.dot.g {
background: #28c840;
}
.filename {
font-size: 19px;
color: #8b98a9;
letter-spacing: 0.2px;
}
.filename .accent {
color: #d6e2f0;
}
.code-surface {
position: relative;
flex: 1 1 auto;
overflow: hidden;
}
.scene {
position: absolute;
inset: 0;
opacity: 0;
will-change: opacity;
}
.code {
position: absolute;
top: 38px;
left: 0;
right: 0;
padding: 0 44px 0 104px;
font-size: 30px;
line-height: 46px;
font-variant-ligatures: none;
tab-size: 2;
}
.gutter {
position: absolute;
top: 38px;
left: 0;
width: 84px;
padding-right: 18px;
font-size: 30px;
line-height: 46px;
text-align: right;
color: #828c9b;
user-select: none;
}
.ln {
display: block;
height: 46px;
}
.line {
display: block;
min-height: 46px;
white-space: pre;
position: relative;
z-index: 1;
}
.tok {
display: inline-block;
white-space: pre;
will-change: transform, opacity;
}
.caret {
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 32px;
margin-top: 6px;
background: #58a6ff;
border-radius: 1px;
z-index: 3;
}
.hl-box {
position: absolute;
background: rgba(88, 166, 255, 0.16);
border-left: 3px solid #58a6ff;
border-radius: 6px;
z-index: 0;
overflow: hidden;
}
.diff-line {
display: block;
min-height: 0;
line-height: 46px;
white-space: pre;
position: relative;
overflow: hidden;
padding-left: 14px;
}
.diff-sign {
display: inline-block;
width: 22px;
color: #41506220;
}
.diff-del {
background: rgba(248, 81, 73, 0.12);
box-shadow: inset 3px 0 #f85149;
}
.diff-add {
background: rgba(63, 185, 80, 0.12);
box-shadow: inset 3px 0 #3fb950;
}
.diff-del .diff-sign {
color: #f85149;
}
.diff-add .diff-sign {
color: #3fb950;
}
.flight-block {
position: absolute;
white-space: pre;
font-size: 27px;
line-height: 40px;
padding: 11px 22px;
border-radius: 11px;
background: #0f1722;
border: 1px solid #233044;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
will-change: transform, opacity;
}
.flight-target {
position: absolute;
border: 1.5px dashed #2a3a4f;
border-radius: 14px;
opacity: 0;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-highlight"
data-start="0"
data-duration="5"
data-width="1920"
data-height="1080"
>
<div class="bg-field" data-layout-ignore></div>
<div class="bg-grid" data-layout-ignore></div>
<div class="bg-glow a" data-layout-ignore></div>
<div class="bg-glow b" data-layout-ignore></div>
<div class="editor" id="editor" data-layout-ignore>
<div class="titlebar">
<div class="dots">
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
</div>
<span class="filename"
><span class="accent">loadConfig.js</span> — Code Highlight Sweep</span
>
</div>
<div class="code-surface" id="surface"></div>
</div>
</div>
<script>
window.__TOKENS = {
feature: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: 'async function loadConfig(path) {\n const raw = await readFile(path, "utf8")\n const config = JSON.parse(raw)\n return validate(config)\n}',
tokens: [
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-0",
content: "async",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-2",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-4",
content: "loadConfig",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-5",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-6",
content: "path",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-7",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-9",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-10",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-11",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-12",
content: "raw",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-13",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-14",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-15",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-16",
content: "await",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-17",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-18",
content: "readFile",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-19",
content: "(path,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-20",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-21",
content: '"utf8"',
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-22",
content: ")",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-23",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-24",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-25",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-26",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-27",
content: "config",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-28",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-29",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-30",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-31",
content: "JSON",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-32",
content: ".",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-33",
content: "parse",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-34",
content: "(raw)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-35",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-36",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-37",
content: "return",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-38",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-39",
content: "validate",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-40",
content: "(config)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-41",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-42",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-43",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = {
id: "code-highlight",
effect: "highlight",
seq: "feature",
line: 1,
duration: 5,
};
</script>
<script>
// hf-code-anim.js — self-contained code-animation engine for HyperFrames registry blocks.
//
// Reuses Shiki Magic Move's baked output (window.__TOKENS, baked at author time) and
// drives the animation as a PAUSED GSAP timeline the HyperFrames engine seeks per frame —
// NOT CSS transitions (those break under non-sequential frame seeking). FLIP measurement
// runs once inside document.fonts.ready (glyph metrics must be final). Each block sets
// window.__BLOCK = { id, effect, seq, line?, duration } and includes this engine; the
// engine builds one scene that fills the composition and registers window.__timelines[id].
(function () {
"use strict";
var T = window.__TOKENS || {};
function lineDiv() {
var d = document.createElement("div");
d.className = "line";
return d;
}
// Render a code state's keyed tokens into codeEl as lines of inline-block .tok spans.
function renderState(codeEl, state) {
codeEl.textContent = "";
var keyToEl = new Map();
var line = lineDiv();
codeEl.appendChild(line);
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
line = lineDiv();
codeEl.appendChild(line);
continue;
}
var span = document.createElement("span");
span.className = "tok";
span.textContent = t.content;
span.style.color = t.color;
if (t.fontStyle & 1) span.style.fontStyle = "italic";
if (t.fontStyle & 2) span.style.fontWeight = "700";
line.appendChild(span);
keyToEl.set(t.key, span);
}
var last = codeEl.lastChild;
if (last && last.className === "line" && last.children.length === 0)
codeEl.removeChild(last);
return keyToEl;
}
function rectsOf(keyToEl) {
var m = new Map();
keyToEl.forEach(function (el, k) {
var r = el.getBoundingClientRect();
m.set(k, { left: r.left, top: r.top });
});
return m;
}
function makeScene(surface, withGutter) {
var scene = document.createElement("div");
scene.className = "scene";
if (withGutter) {
var g = document.createElement("div");
g.className = "gutter";
scene.appendChild(g);
}
var code = document.createElement("div");
code.className = "code";
scene.appendChild(code);
surface.appendChild(scene);
return { scene: scene, code: code, gutter: scene.querySelector(".gutter") };
}
function fillGutter(g, n) {
var html = "";
for (var i = 1; i <= n; i++) html += '<span class="ln">' + i + "</span>";
g.innerHTML = html;
}
function splitLines(state) {
var lines = [{ text: "", tokens: [] }];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push({ text: "", tokens: [] });
continue;
}
var cur = lines[lines.length - 1];
cur.tokens.push(t);
cur.text += t.content;
}
if (lines.length && lines[lines.length - 1].tokens.length === 0) lines.pop();
return lines;
}
function lineDiff(a, b) {
var n = a.length;
var m = b.length;
var dp = [];
for (var i = 0; i <= n; i++) dp.push(new Array(m + 1).fill(0));
for (var i = n - 1; i >= 0; i--) {
for (var j = m - 1; j >= 0; j--) {
dp[i][j] =
a[i].text === b[j].text
? dp[i + 1][j + 1] + 1
: Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
var ops = [];
var i = 0;
var j = 0;
while (i < n && j < m) {
if (a[i].text === b[j].text) {
ops.push({ type: "same", line: b[j] });
i++;
j++;
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
ops.push({ type: "del", line: a[i] });
i++;
} else {
ops.push({ type: "add", line: b[j] });
j++;
}
}
while (i < n) ops.push({ type: "del", line: a[i++] });
while (j < m) ops.push({ type: "add", line: b[j++] });
return ops;
}
// ---- single-scene effect builders (fade in, play, hold to end) -------------
var FADE = 0.45;
function highlight(tl, surface, state, start, targetIdx) {
var SWEEP = 0.9;
var parts = makeScene(surface, true);
var code = parts.code;
renderState(code, state);
var lines = code.querySelectorAll(".line");
fillGutter(parts.gutter, lines.length);
var base = code.getBoundingClientRect();
var idx = Math.max(0, Math.min(lines.length - 1, targetIdx));
var lr = lines[idx].getBoundingClientRect();
var box = document.createElement("div");
box.className = "hl-box";
box.style.left = lr.left - base.left - 8 + "px";
box.style.top = lr.top - base.top - 1 + "px";
box.style.height = lr.height + 2 + "px";
code.insertBefore(box, code.firstChild);
tl.set(parts.scene, { opacity: 0 }, 0);
tl.to(parts.scene, { opacity: 1, duration: FADE, ease: "power1.out" }, start);
var at = start + FADE + 0.2;
tl.fromTo(
box,
{ width: 0, opacity: 0 },
{ width: lr.width + 18, opacity: 1, duration: SWEEP, ease: "power2.inOut" },
at,
);
for (var i = 0; i < lines.length; i++) {
if (i === idx) continue;
tl.fromTo(
lines[i],
{ opacity: 1 },
{ opacity: 0.45, duration: SWEEP, ease: "power2.inOut" },
at,
);
}
}
function buildEffect(tl, surface, spec) {
var start = 0.45;
var seq = T[spec.seq];
if (spec.effect === "highlight")
highlight(tl, surface, seq.states[0], start, spec.line || 0);
}
function go() {
var spec = window.__BLOCK;
var surface = document.getElementById("surface");
var root = document.getElementById("root");
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
// Build inside fonts.ready (glyph metrics must be final), then register.
// Register ONLY after the timeline is fully built: the runtime's
// sub-composition readiness gate treats "key present" as "ready" and
// nests the child once. An empty timeline registered before this build
// would be nested empty and never re-nested → blank render when used as
// a sub-composition. See the contract in engine frameCapture.ts.
document.fonts.ready.then(function () {
tl.from("#editor", { opacity: 0, scale: 0.985, duration: 0.5, ease: "power2.out" }, 0);
buildEffect(tl, surface, spec);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
window.__timelines["code-highlight"] = tl; // register AFTER setup completes
if (typeof window.__hfForceTimelineRebind === "function") {
window.__hfForceTimelineRebind(); // re-nest now that we are populated
}
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-highlight",
"type": "hyperframes:block",
"title": "Code Highlight Sweep",
"description": "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 5,
"tags": ["code", "code-animation", "highlight", "developer"],
"files": [
{
"path": "code-highlight.html",
"target": "compositions/code-highlight.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-morph",
"type": "hyperframes:block",
"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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 7,
"tags": ["code", "code-animation", "morph", "refactor", "developer"],
"files": [
{
"path": "code-morph.html",
"target": "compositions/code-morph.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,479 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Particle Assemble</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.147.0/build/three.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
background: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
}
#gl {
position: absolute;
inset: 0;
width: 1920px;
height: 1080px;
display: block;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-particle-assemble"
data-start="0"
data-duration="8"
data-width="1920"
data-height="1080"
>
<canvas id="gl" width="1920" height="1080"></canvas>
</div>
<script>
window.__TOKENS = {
assemble: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: "const app = pipe(\n parse,\n optimize,\n emit,\n)",
tokens: [
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-0",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-2",
content: "app",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-4",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-5",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-6",
content: "pipe",
color: "#B392F0",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-7",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-9",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-10",
content: "parse,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-11",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-12",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-13",
content: "optimize,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-14",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-15",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-16",
content: "emit,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-17",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-18",
content: ")",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "AFffx9qQBGKnMZ-vDjoaRwC68xQloGJNUSICY1myCK4-19",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = {
id: "code-particle-assemble",
effect: "particles",
seq: "assemble",
duration: 8,
seed: 23,
};
</script>
<script>
// hf-code-anim-gl.js — WebGL code-animation engine for the "crazy" Code Animations blocks.
//
// Bridges the baked Shiki tokens (window.__TOKENS) into Three.js: the tokens are drawn once
// to an offscreen 2D canvas (a CanvasTexture), which then drives a lit 3D slab, a dissolve
// shader, or a GPU particle system. Determinism per the project contract:
// - render only via tl.eventCallback("onUpdate", …) + one initial render() — never rAF
// - all randomness from a seeded mulberry32 — never Math.random / Date.now
// - canvas drawn once after document.fonts.ready (final glyph metrics)
// - paused GSAP timeline registered on window.__timelines[id]; HF seeks it per frame
//
// Each block sets window.__BLOCK = { id, effect, seq, duration, seed } and includes this engine.
(function () {
"use strict";
var T = window.__TOKENS || {};
// ---- seeded PRNG (no Math.random) -----------------------------------------
function mulberry32(a) {
return function () {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
var t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// ---- split a token state into lines of {content,color} --------------------
function splitLines(state) {
var lines = [[]];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push([]);
continue;
}
lines[lines.length - 1].push(t);
}
while (lines.length && lines[lines.length - 1].length === 0) lines.pop();
return lines;
}
// ---- THE BRIDGE: draw baked tokens to an offscreen 2D canvas ---------------
// Returns { canvas, W, H, lines, lineH, padY, fontPx } so effects can sample it.
function drawCodeToCanvas(state, opts) {
opts = opts || {};
var fontPx = opts.fontPx || 36;
var lineH = opts.lineH || 54;
var padX = opts.padX || 70;
var padY = opts.padY || 60;
var weight = opts.weight || 500;
var font = weight + " " + fontPx + 'px "JetBrains Mono", monospace';
var lines = splitLines(state);
var measure = document.createElement("canvas").getContext("2d");
measure.font = font;
var maxW = 0;
for (var i = 0; i < lines.length; i++) {
var w = 0;
for (var j = 0; j < lines[i].length; j++)
w += measure.measureText(lines[i][j].content).width;
if (w > maxW) maxW = w;
}
var W = Math.max(2, Math.ceil(maxW + padX * 2));
var H = Math.max(2, Math.ceil(lines.length * lineH + padY * 2));
var canvas = document.createElement("canvas");
canvas.width = W;
canvas.height = H;
var ctx = canvas.getContext("2d");
if (opts.transparent) {
ctx.clearRect(0, 0, W, H);
} else {
ctx.fillStyle = opts.bg || "#0b0f17";
ctx.fillRect(0, 0, W, H);
}
ctx.textBaseline = "top";
ctx.font = font;
for (var li = 0; li < lines.length; li++) {
var x = padX;
var y = padY + li * lineH;
for (var k = 0; k < lines[li].length; k++) {
var tok = lines[li][k];
ctx.fillStyle = tok.color;
ctx.fillText(tok.content, x, y);
x += ctx.measureText(tok.content).width;
}
}
return {
canvas: canvas,
W: W,
H: H,
lines: lines.length,
lineH: lineH,
padY: padY,
fontPx: fontPx,
};
}
function fxParticles(THREE, scene, camera, renderer, state, st, tl, dur, seed) {
scene.background = new THREE.Color(0x05070b);
var code = drawCodeToCanvas(state, {
fontPx: 46,
lineH: 70,
padX: 70,
padY: 64,
weight: 700,
});
var cw = code.W;
var ch = code.H;
var data = code.canvas.getContext("2d").getImageData(0, 0, cw, ch).data;
var rng = mulberry32(((seed || 1) * 2654435761) >>> 0);
var worldW = 13.0;
var worldH = worldW * (ch / cw);
// sample glyph pixels (brighter than the dark bg) on a fixed grid
var step = 2;
var tx = [];
var col = [];
for (var y = 0; y < ch; y += step) {
for (var x = 0; x < cw; x += step) {
var idx = (y * cw + x) * 4;
var r = data[idx];
var g = data[idx + 1];
var b = data[idx + 2];
if (r + g + b < 120) continue; // skip background
tx.push((x / cw - 0.5) * worldW, -(y / ch - 0.5) * worldH, 0);
col.push(r / 255, g / 255, b / 255);
}
}
var n = tx.length / 3;
var positions = new Float32Array(n * 3);
var aOrigin = new Float32Array(n * 3);
var aTarget = new Float32Array(tx);
var aColor = new Float32Array(col);
var aDelay = new Float32Array(n);
for (var i = 0; i < n; i++) {
var sx = (rng() * 2 - 1) * worldW * 1.15;
var sy = (rng() * 2 - 1) * worldH * 1.7;
var sz = (rng() * 2 - 1) * 9.0 - 2.0;
aOrigin[i * 3] = sx;
aOrigin[i * 3 + 1] = sy;
aOrigin[i * 3 + 2] = sz;
positions[i * 3] = sx;
positions[i * 3 + 1] = sy;
positions[i * 3 + 2] = sz;
aDelay[i] = rng();
}
var geo = new THREE.BufferGeometry();
geo.setAttribute("position", new THREE.BufferAttribute(positions, 3));
geo.setAttribute("aOrigin", new THREE.BufferAttribute(aOrigin, 3));
geo.setAttribute("aTarget", new THREE.BufferAttribute(aTarget, 3));
geo.setAttribute("aColor", new THREE.BufferAttribute(aColor, 3));
geo.setAttribute("aDelay", new THREE.BufferAttribute(aDelay, 1));
var uniforms = { uProgress: { value: 0 }, uSize: { value: 3.4 } };
var mat = new THREE.ShaderMaterial({
uniforms: uniforms,
transparent: true,
depthTest: false,
depthWrite: false,
blending: THREE.NormalBlending,
vertexShader: [
"attribute vec3 aOrigin; attribute vec3 aTarget; attribute vec3 aColor; attribute float aDelay;",
"uniform float uProgress; uniform float uSize;",
"varying vec3 vColor; varying float vP;",
"void main(){",
" float span = 0.62;",
" float p = clamp((uProgress - aDelay*(1.0-span)) / span, 0.0, 1.0);",
" p = p*p*(3.0-2.0*p);",
" vec3 pos = mix(aOrigin, aTarget, p);",
" vec4 mv = modelViewMatrix * vec4(pos, 1.0);",
" gl_Position = projectionMatrix * mv;",
" gl_PointSize = uSize * (60.0 / -mv.z) * (0.45 + 0.55*p);",
" vColor = aColor; vP = p;",
"}",
].join("\n"),
fragmentShader: [
"precision highp float;",
"varying vec3 vColor; varying float vP;",
"void main(){",
" vec2 d = gl_PointCoord - 0.5;",
" float r2 = dot(d, d);",
" if (r2 > 0.25) discard;",
" float a = smoothstep(0.25, 0.02, r2);",
// brighter & whiter in flight, resolves to true color as it lands
" vec3 c = mix(vColor + vec3(0.32)*(1.0-vP), vColor, vP);",
" gl_FragColor = vec4(c, a * (0.7 + 0.3*vP));",
"}",
].join("\n"),
});
var pts = new THREE.Points(geo, mat);
scene.add(pts);
camera.position.set(0, 0, 10);
var vfov = (camera.fov * Math.PI) / 180;
var sa = 1920 / 1080;
var fitH = worldH / 2 / Math.tan(vfov / 2) / 0.78;
var fitW = worldW / 2 / (Math.tan(vfov / 2) * sa) / 0.78;
camera.position.z = Math.max(fitH, fitW);
camera.lookAt(0, 0, 0);
tl.to(uniforms.uProgress, { value: 1.0, duration: dur * 0.72, ease: "power2.out" }, 0);
// uProgress is tweened by GSAP; the boot loop's render() draws once per frame.
return function () {};
}
// ---- dispatch + boot ------------------------------------------------------
function buildEffect(THREE, scene, camera, renderer, spec, st, tl) {
var state = T[spec.seq].states[0];
var dur = spec.duration;
if (spec.effect === "particles")
return fxParticles(THREE, scene, camera, renderer, state, st, tl, dur, spec.seed);
return function () {};
}
// Free GPU resources (renderer, geometries, materials, textures) on page teardown.
// One-shot renders exit per job so nothing leaks there; this guards long-lived
// Studio/player sessions that reload. Fires only on unload — never during capture.
function disposeGL(renderer, scene) {
scene.traverse(function (o) {
if (o.geometry && o.geometry.dispose) o.geometry.dispose();
var mats = o.material ? (Array.isArray(o.material) ? o.material : [o.material]) : [];
mats.forEach(function (m) {
if (m.map && m.map.dispose) m.map.dispose();
if (
m.uniforms &&
m.uniforms.uTex &&
m.uniforms.uTex.value &&
m.uniforms.uTex.value.dispose
) {
m.uniforms.uTex.value.dispose();
}
if (m.dispose) m.dispose();
});
});
if (renderer.dispose) renderer.dispose();
}
function go() {
var spec = window.__BLOCK;
var root = document.getElementById("root");
var glcanvas = document.getElementById("gl");
var W = 1920;
var H = 1080;
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
window.__timelines[spec.id] = tl; // register synchronously
var THREE = window.THREE;
var renderer = new THREE.WebGLRenderer({
canvas: glcanvas,
antialias: true,
alpha: false,
preserveDrawingBuffer: true,
});
renderer.setPixelRatio(1);
renderer.setSize(W, H, false);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, W / H, 0.1, 200);
var st = {};
document.fonts.ready.then(function () {
var renderFn = buildEffect(THREE, scene, camera, renderer, spec, st, tl);
function render() {
renderFn();
renderer.render(scene, camera);
}
tl.eventCallback("onUpdate", render);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
render(); // paint frame 0
window.addEventListener("beforeunload", function () {
disposeGL(renderer, scene);
});
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-particle-assemble",
"type": "hyperframes:block",
"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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 8,
"tags": ["code", "code-animation", "particles", "gpu", "webgl", "developer"],
"files": [
{
"path": "code-particle-assemble.html",
"target": "compositions/code-particle-assemble.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-scroll",
"type": "hyperframes:block",
"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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 6,
"tags": ["code", "code-animation", "scroll", "developer"],
"files": [
{
"path": "code-scroll.html",
"target": "compositions/code-scroll.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,535 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Shader Dissolve</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.147.0/build/three.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
background: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
}
#gl {
position: absolute;
inset: 0;
width: 1920px;
height: 1080px;
display: block;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-shader-dissolve"
data-start="0"
data-duration="7"
data-width="1920"
data-height="1080"
>
<canvas id="gl" width="1920" height="1080"></canvas>
</div>
<script>
window.__TOKENS = {
compile: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: "function compile(src) {\n const ast = parse(src)\n const ir = optimize(ast)\n return emit(ir)\n}",
tokens: [
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-0",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-2",
content: "compile",
color: "#B392F0",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-3",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-4",
content: "src",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-5",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-6",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-7",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-8",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-9",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-10",
content: "ast",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-11",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-12",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-13",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-14",
content: "parse",
color: "#B392F0",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-15",
content: "(src)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-16",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-17",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-18",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-19",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-20",
content: "ir",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-21",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-22",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-23",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-24",
content: "optimize",
color: "#B392F0",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-25",
content: "(ast)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-26",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-27",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-28",
content: "return",
color: "#F97583",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-29",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-30",
content: "emit",
color: "#B392F0",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-31",
content: "(ir)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-32",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-33",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "zGtBjd8ajYlOewpKFJD53Oc7W94UowxIfV0186O1l8A-34",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = {
id: "code-shader-dissolve",
effect: "dissolve",
seq: "compile",
duration: 7,
seed: 11,
};
</script>
<script>
// hf-code-anim-gl.js — WebGL code-animation engine for the "crazy" Code Animations blocks.
//
// Bridges the baked Shiki tokens (window.__TOKENS) into Three.js: the tokens are drawn once
// to an offscreen 2D canvas (a CanvasTexture), which then drives a lit 3D slab, a dissolve
// shader, or a GPU particle system. Determinism per the project contract:
// - render only via tl.eventCallback("onUpdate", …) + one initial render() — never rAF
// - all randomness from a seeded mulberry32 — never Math.random / Date.now
// - canvas drawn once after document.fonts.ready (final glyph metrics)
// - paused GSAP timeline registered on window.__timelines[id]; HF seeks it per frame
//
// Each block sets window.__BLOCK = { id, effect, seq, duration, seed } and includes this engine.
(function () {
"use strict";
var T = window.__TOKENS || {};
// ---- seeded PRNG (no Math.random) -----------------------------------------
function mulberry32(a) {
return function () {
a |= 0;
a = (a + 0x6d2b79f5) | 0;
var t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// ---- split a token state into lines of {content,color} --------------------
function splitLines(state) {
var lines = [[]];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push([]);
continue;
}
lines[lines.length - 1].push(t);
}
while (lines.length && lines[lines.length - 1].length === 0) lines.pop();
return lines;
}
// ---- THE BRIDGE: draw baked tokens to an offscreen 2D canvas ---------------
// Returns { canvas, W, H, lines, lineH, padY, fontPx } so effects can sample it.
function drawCodeToCanvas(state, opts) {
opts = opts || {};
var fontPx = opts.fontPx || 36;
var lineH = opts.lineH || 54;
var padX = opts.padX || 70;
var padY = opts.padY || 60;
var weight = opts.weight || 500;
var font = weight + " " + fontPx + 'px "JetBrains Mono", monospace';
var lines = splitLines(state);
var measure = document.createElement("canvas").getContext("2d");
measure.font = font;
var maxW = 0;
for (var i = 0; i < lines.length; i++) {
var w = 0;
for (var j = 0; j < lines[i].length; j++)
w += measure.measureText(lines[i][j].content).width;
if (w > maxW) maxW = w;
}
var W = Math.max(2, Math.ceil(maxW + padX * 2));
var H = Math.max(2, Math.ceil(lines.length * lineH + padY * 2));
var canvas = document.createElement("canvas");
canvas.width = W;
canvas.height = H;
var ctx = canvas.getContext("2d");
if (opts.transparent) {
ctx.clearRect(0, 0, W, H);
} else {
ctx.fillStyle = opts.bg || "#0b0f17";
ctx.fillRect(0, 0, W, H);
}
ctx.textBaseline = "top";
ctx.font = font;
for (var li = 0; li < lines.length; li++) {
var x = padX;
var y = padY + li * lineH;
for (var k = 0; k < lines[li].length; k++) {
var tok = lines[li][k];
ctx.fillStyle = tok.color;
ctx.fillText(tok.content, x, y);
x += ctx.measureText(tok.content).width;
}
}
return {
canvas: canvas,
W: W,
H: H,
lines: lines.length,
lineH: lineH,
padY: padY,
fontPx: fontPx,
};
}
function fxDissolve(THREE, scene, camera, renderer, state, st, tl, dur, seed) {
scene.background = new THREE.Color(0x05070b);
var code = drawCodeToCanvas(state, {
fontPx: 40,
lineH: 60,
padX: 90,
padY: 80,
weight: 600,
});
var tex = new THREE.CanvasTexture(code.canvas);
tex.minFilter = THREE.LinearFilter;
tex.magFilter = THREE.LinearFilter;
tex.generateMipmaps = false;
var aspect = code.W / code.H;
var planeH = 6.6;
var planeW = planeH * aspect;
var uniforms = {
uTex: { value: tex },
uProgress: { value: 0 },
uSeed: { value: (seed || 1) * 13.37 },
};
var mat = new THREE.ShaderMaterial({
uniforms: uniforms,
transparent: true,
vertexShader: [
"varying vec2 vUv;",
"void main(){ vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); }",
].join("\n"),
fragmentShader: [
"precision highp float;",
"uniform sampler2D uTex;",
"uniform float uProgress;",
"uniform float uSeed;",
"varying vec2 vUv;",
"float hash(vec2 p){ p=fract(p*vec2(123.34,456.21)); p+=dot(p,p+45.32); return fract(p.x*p.y); }",
"float noise(vec2 p){ vec2 i=floor(p),f=fract(p); float a=hash(i),b=hash(i+vec2(1.,0.)),c=hash(i+vec2(0.,1.)),d=hash(i+vec2(1.,1.)); vec2 u=f*f*(3.-2.*f); return mix(mix(a,b,u.x),mix(c,d,u.x),u.y); }",
"void main(){",
" vec2 uv = vUv;",
// multi-octave seeded noise field
" float n = noise(uv*16.0+uSeed)*0.6 + noise(uv*48.0+uSeed*1.7)*0.3 + noise(uv*120.0+uSeed*2.3)*0.1;",
" float edge = 0.12;",
" float reveal = smoothstep(n-edge, n+edge, uProgress);", // 0 hidden -> 1 shown
// chromatic fringe strongest at the dissolving edge
" float band = reveal*(1.0-reveal)*4.0;",
" float off = band*0.010;",
" float r = texture2D(uTex, uv+vec2(off,0.0)).r;",
" float g = texture2D(uTex, uv).g;",
" float b = texture2D(uTex, uv-vec2(off,0.0)).b;",
" vec3 codeCol = vec3(r,g,b);",
// additive cyan edge glow along the dissolve front
" vec3 glow = vec3(0.30,0.72,1.0) * band * 0.9;",
" vec3 outc = codeCol*reveal + glow;",
" float a = max(reveal, band*0.8);",
" gl_FragColor = vec4(outc, a);",
"}",
].join("\n"),
});
var plane = new THREE.Mesh(new THREE.PlaneGeometry(planeW, planeH), mat);
scene.add(plane);
camera.position.set(0, 0, 10);
var vfov = (camera.fov * Math.PI) / 180;
var screenAspect = 1920 / 1080;
var fitH = planeH / 2 / Math.tan(vfov / 2) / 0.82;
var fitW = planeW / 2 / (Math.tan(vfov / 2) * screenAspect) / 0.82;
camera.position.z = Math.max(fitH, fitW);
camera.lookAt(0, 0, 0);
// compile in, then hold crisp. Overshoot to 1.15 so even max-noise pixels
// (n up to ~1.0, edge 0.12) fully resolve — no leftover specks at rest.
tl.to(uniforms.uProgress, { value: 1.15, duration: dur * 0.62, ease: "power1.inOut" }, 0);
// uProgress is tweened by GSAP; the boot loop's render() draws once per frame.
return function () {};
}
// ---- dispatch + boot ------------------------------------------------------
function buildEffect(THREE, scene, camera, renderer, spec, st, tl) {
var state = T[spec.seq].states[0];
var dur = spec.duration;
if (spec.effect === "dissolve")
return fxDissolve(THREE, scene, camera, renderer, state, st, tl, dur, spec.seed);
return function () {};
}
// Free GPU resources (renderer, geometries, materials, textures) on page teardown.
// One-shot renders exit per job so nothing leaks there; this guards long-lived
// Studio/player sessions that reload. Fires only on unload — never during capture.
function disposeGL(renderer, scene) {
scene.traverse(function (o) {
if (o.geometry && o.geometry.dispose) o.geometry.dispose();
var mats = o.material ? (Array.isArray(o.material) ? o.material : [o.material]) : [];
mats.forEach(function (m) {
if (m.map && m.map.dispose) m.map.dispose();
if (
m.uniforms &&
m.uniforms.uTex &&
m.uniforms.uTex.value &&
m.uniforms.uTex.value.dispose
) {
m.uniforms.uTex.value.dispose();
}
if (m.dispose) m.dispose();
});
});
if (renderer.dispose) renderer.dispose();
}
function go() {
var spec = window.__BLOCK;
var root = document.getElementById("root");
var glcanvas = document.getElementById("gl");
var W = 1920;
var H = 1080;
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
window.__timelines[spec.id] = tl; // register synchronously
var THREE = window.THREE;
var renderer = new THREE.WebGLRenderer({
canvas: glcanvas,
antialias: true,
alpha: false,
preserveDrawingBuffer: true,
});
renderer.setPixelRatio(1);
renderer.setSize(W, H, false);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, W / H, 0.1, 200);
var st = {};
document.fonts.ready.then(function () {
var renderFn = buildEffect(THREE, scene, camera, renderer, spec, st, tl);
function render() {
renderFn();
renderer.render(scene, camera);
}
tl.eventCallback("onUpdate", render);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
render(); // paint frame 0
window.addEventListener("beforeunload", function () {
disposeGL(renderer, scene);
});
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-shader-dissolve",
"type": "hyperframes:block",
"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.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 7,
"tags": ["code", "code-animation", "shader", "webgl", "developer"],
"files": [
{
"path": "code-shader-dissolve.html",
"target": "compositions/code-shader-dissolve.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,249 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Basic</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #ececec;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #e8e8e8 0%, #d8d8d8 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.25),
0 10px 30px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #ececec;
display: flex;
align-items: center;
padding: 0 14px;
gap: 0;
flex-shrink: 0;
border-bottom: 1px solid #d0d0d0;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #333333;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #ffffff;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #000000;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #000000;
}
.output-line.bold {
font-weight: bold;
color: #000000;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #000000;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #000000;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #000000;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-basic"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line">Last login: Mon Jun 2 09:14:22 on ttys001</span>
<span class="output-line">total 48</span>
<span class="output-line bold">drwxr-xr-x 8 user staff 256 Jun 2 09:10 .</span>
<span class="output-line">drwxr-xr-x 42 user staff 1344 Jun 1 18:22 ..</span>
<span class="output-line">-rw-r--r-- 1 user staff 872 May 30 14:05 README.md</span>
<span class="output-line bold">drwxr-xr-x 5 user staff 160 Jun 2 09:10 dist</span>
<span class="output-line bold"
>drwxr-xr-x 12 user staff 384 Jun 2 09:10 node_modules</span
>
<span class="output-line">-rw-r--r-- 1 user staff 1204 Jun 2 09:08 package.json</span>
<span class="output-line bold">drwxr-xr-x 6 user staff 192 Jun 2 09:10 src</span>
<span class="output-line">-rw-r--r-- 1 user staff 348 May 29 11:42 tsconfig.json</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "ls -la";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
// Phase 1 (00.5s): hold on empty prompt
tl.set(typedEl, { text: "" }, 0);
// Phase 2 (0.52s): type command char by char
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
// Phase 3 (2.2s): hide cursor, show first output line (login message)
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
// Phase 4 (2.5s): clear command, show ls output line by line
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return; // already shown
tl.set(line, { opacity: 1 }, 2.8 + i * 0.08);
});
// Phase 5 (4s): new prompt with blinking cursor
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.0);
// Phase 6 (4.210s): blink cursor 3 times then stop
const blinkTimes = [4.2, 4.6, 5.0, 5.4, 5.8, 6.2];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.6);
window.__timelines["code-snippet-apple-terminal-basic"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-basic",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Basic",
"description": "Apple Terminal Basic profile: white background, black text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-basic.html",
"target": "compositions/code-snippet-apple-terminal-basic.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,244 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Clear Dark</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #1a1a1a;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #1a1a1a 0%, #111111 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.7),
0 10px 30px rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: rgba(0, 0, 0, 0.7);
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #ffffff;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #ffffff;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.dim {
color: rgba(255, 255, 255, 0.6);
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #888888;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #ffffff;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #888888;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-clear-dark"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys002</span>
<span class="output-line">Scanning dependencies...</span>
<span class="output-line">Found 3 vulnerabilities (1 moderate, 2 low)</span>
<span class="output-line dim"> package: lodash@4.17.20</span>
<span class="output-line dim"> severity: moderate</span>
<span class="output-line dim"> fix: lodash@4.17.21</span>
<span class="output-line dim"> package: minimist@1.2.5</span>
<span class="output-line dim"> severity: low</span>
<span class="output-line dim"> fix: minimist@1.2.6</span>
<span class="output-line bold">Run `npm audit fix` to fix them.</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "npm audit";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-clear-dark"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-clear-dark",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Clear Dark",
"description": "Apple Terminal Clear Dark profile: semi-transparent dark background, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-clear-dark.html",
"target": "compositions/code-snippet-apple-terminal-clear-dark.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,244 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Clear Light</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.18),
0 10px 30px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: rgba(255, 255, 255, 0.4);
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
position: relative;
backdrop-filter: blur(10px);
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #333333;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: rgba(255, 255, 255, 0.7);
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #000000;
backdrop-filter: blur(8px);
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #000000;
}
.output-line.bold {
font-weight: bold;
}
.output-line.muted {
color: #666666;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #888888;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #000000;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #888888;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-clear-light"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line muted">Last login: Mon Jun 2 09:14:22 on ttys003</span>
<span class="output-line bold">git log --oneline -8</span>
<span class="output-line">a3f2c19 fix: correct off-by-one in pagination</span>
<span class="output-line">b7e8d04 feat: add dark mode toggle</span>
<span class="output-line">c1a9f55 refactor: extract auth helpers</span>
<span class="output-line">d4e2b31 test: add unit tests for parser</span>
<span class="output-line">e6c8a72 docs: update API reference</span>
<span class="output-line">f9b1d44 chore: bump dependencies</span>
<span class="output-line">2a7e890 feat: implement search endpoint</span>
<span class="output-line">3c5f012 init: project bootstrap</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac myproject % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "git log --oneline -8";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.09);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac myproject % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.0);
const blinkTimes = [4.2, 4.6, 5.0, 5.4, 5.8, 6.2];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.6);
window.__timelines["code-snippet-apple-terminal-clear-light"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-clear-light",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Clear Light",
"description": "Apple Terminal Clear Light profile: semi-transparent light background, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-clear-light.html",
"target": "compositions/code-snippet-apple-terminal-clear-light.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,243 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Grass</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000000;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #0a1a0a 0%, #000000 70%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 193, 0, 0.15),
0 10px 30px rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #1c1c1c;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #00c100;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #00c100;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #000000;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #00c100;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #00c100;
}
.output-line.bold {
font-weight: bold;
color: #00c100;
}
.output-line.dim {
color: #006600;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #00c100;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #00c100;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #00c100;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-grass"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys004</span>
<span class="output-line">Running test suite...</span>
<span class="output-line dim"> ✓ should initialize with defaults (2ms)</span>
<span class="output-line dim"> ✓ should parse config correctly (4ms)</span>
<span class="output-line dim"> ✓ should handle empty input (1ms)</span>
<span class="output-line dim"> ✓ should reject invalid tokens (3ms)</span>
<span class="output-line dim"> ✓ should emit events on change (5ms)</span>
<span class="output-line dim"> ✓ should clean up on destroy (2ms)</span>
<span class="output-line bold"> 6 passing (18ms)</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "npm test";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.12);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.0);
const blinkTimes = [4.2, 4.6, 5.0, 5.4, 5.8, 6.2];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.6);
window.__timelines["code-snippet-apple-terminal-grass"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-grass",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Grass",
"description": "Apple Terminal Grass profile: black background with green text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-grass.html",
"target": "compositions/code-snippet-apple-terminal-grass.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,248 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Homebrew</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000000;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #0d1a0d 0%, #000000 70%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 207, 0, 0.18),
0 10px 30px rgba(0, 0, 0, 0.85);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #1c1c1c;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #006900;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #00cf00;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #000000;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #00cf00;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #00cf00;
}
.output-line.bold {
font-weight: bold;
color: #00de00;
}
.output-line.dim {
color: #006600;
}
.output-line.bright {
color: #48f800;
font-weight: bold;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #48f800;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #00cf00;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #48f800;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-homebrew"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys005</span>
<span class="output-line">==> Updating Homebrew...</span>
<span class="output-line dim">Already up-to-date.</span>
<span class="output-line">==> Outdated formulae</span>
<span class="output-line">node 20.11.0 -> 22.3.0</span>
<span class="output-line">python 3.11.6 -> 3.12.4</span>
<span class="output-line">git 2.43.0 -> 2.45.2</span>
<span class="output-line">ffmpeg 6.1.1 -> 7.0.0</span>
<span class="output-line bright">==> Run `brew upgrade` to update 4 formulae.</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "brew outdated";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-homebrew"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-homebrew",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Homebrew",
"description": "Apple Terminal Homebrew profile: black background with bright green text and lime cursor, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-homebrew.html",
"target": "compositions/code-snippet-apple-terminal-homebrew.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,248 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Man Page</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #ede87a 0%, #ddd566 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.2),
0 10px 30px rgba(0, 0, 0, 0.12);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #f0e680;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #c8be40;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #333333;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #fef49c;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #000000;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #000000;
}
.output-line.bold {
font-weight: bold;
}
.output-line.indent {
padding-left: 24px;
color: #222222;
}
.output-line.section {
font-weight: bold;
margin-top: 2px;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #000000;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #000000;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #000000;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-man-page"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">man — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line section">CURL(1) General Commands Manual CURL(1)</span>
<span class="output-line"></span>
<span class="output-line section">NAME</span>
<span class="output-line indent">curl -- transfer a URL</span>
<span class="output-line"></span>
<span class="output-line section">SYNOPSIS</span>
<span class="output-line indent">curl [options / URLs]</span>
<span class="output-line"></span>
<span class="output-line section">DESCRIPTION</span>
<span class="output-line indent"
>curl is a tool for transferring data from or to a server using URLs.</span
>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "man curl";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.add(() => {
typedEl.textContent = "";
}, 2.4);
outputLines.forEach((line, i) => {
tl.set(line, { opacity: 1 }, 2.5 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.0);
const blinkTimes = [4.2, 4.6, 5.0, 5.4, 5.8, 6.2];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.6);
window.__timelines["code-snippet-apple-terminal-man-page"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-man-page",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Man Page",
"description": "Apple Terminal Man Page profile: pale yellow background with black text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-man-page.html",
"target": "compositions/code-snippet-apple-terminal-man-page.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,244 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Novel</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #c9a86c 0%, #b8955a 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(62, 41, 0, 0.3),
0 10px 30px rgba(0, 0, 0, 0.15);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #c9a86c;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #a88040;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #3e2900;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 600;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #dfc18a;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #3e2900;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #3e2900;
}
.output-line.bold {
font-weight: bold;
color: #3e2900;
}
.output-line.muted {
color: #7a5a20;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #3e2900;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #3e2900;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #3e2900;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-novel"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line muted">Last login: Mon Jun 2 09:14:22 on ttys006</span>
<span class="output-line muted">Python 3.12.4 (main, Jun 6 2024, 18:26:44)</span>
<span class="output-line muted"
>Type "help", "copyright", "credits" or "license" for more information.</span
>
<span class="output-line bold">>>> import hyperframes</span>
<span class="output-line bold">>>> hf = hyperframes.Composition("intro.html")</span>
<span class="output-line">>>> hf.duration</span>
<span class="output-line">12.0</span>
<span class="output-line">>>> hf.dimensions</span>
<span class="output-line">Dimensions(width=1920, height=1080)</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "python3";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-novel"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-novel",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Novel",
"description": "Apple Terminal Novel profile: warm parchment background with dark brown text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-novel.html",
"target": "compositions/code-snippet-apple-terminal-novel.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,253 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Ocean</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #1a3f9e;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #224fbe 0%, #0e2878 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.6),
0 10px 30px rgba(34, 79, 190, 0.3);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #1a3f9e;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #224fbe;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #ffffff;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #ffffff;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.dim {
color: rgba(255, 255, 255, 0.65);
}
.output-line.success {
color: #7fffb3;
font-weight: bold;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: rgba(255, 255, 255, 0.8);
font-weight: bold;
user-select: none;
}
.typed-command {
color: #ffffff;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #ffffff;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-ocean"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys007</span>
<span class="output-line bold">docker ps</span>
<span class="output-line dim">CONTAINER ID IMAGE COMMAND CREATED</span>
<span class="output-line"
>a1b2c3d4e5f6 nginx:latest "/docker-entrypoint.…" 2 hours ago</span
>
<span class="output-line"
>b2c3d4e5f6a7 postgres:15 "docker-entrypoint.s…" 2 hours ago</span
>
<span class="output-line"
>c3d4e5f6a7b8 redis:alpine "docker-entrypoint.s…" 2 hours ago</span
>
<span class="output-line success">3 containers running</span>
<span class="output-line dim">Use 'docker logs CONTAINER' to view output</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "docker ps";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-ocean"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-ocean",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Ocean",
"description": "Apple Terminal Ocean profile: deep blue background with white text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-ocean.html",
"target": "compositions/code-snippet-apple-terminal-ocean.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,247 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Pro</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000000;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #141414 0%, #000000 70%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(136, 255, 103, 0.08),
0 10px 30px rgba(0, 0, 0, 0.9);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #1c1c1c;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #333333;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #bbbbbb;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #000000;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #bbbbbb;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #bbbbbb;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.accent {
color: #88ff67;
font-weight: bold;
}
.output-line.dim {
color: #666666;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #88ff67;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #bbbbbb;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #88ff67;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-pro"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys008</span>
<span class="output-line dim">Building production bundle...</span>
<span class="output-line"> vite v5.3.1 building for production...</span>
<span class="output-line"> ✓ 142 modules transformed.</span>
<span class="output-line"> dist/index.html 0.48 kB</span>
<span class="output-line"> dist/assets/index-Cv3rN.js 284.12 kB</span>
<span class="output-line"> dist/assets/index-Du4mP.css 42.08 kB</span>
<span class="output-line accent"> ✓ built in 2.31s</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac myapp % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "npm run build";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac myapp % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-pro"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-pro",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Pro",
"description": "Apple Terminal Pro profile: black background with grey text and lime green cursor, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-pro.html",
"target": "compositions/code-snippet-apple-terminal-pro.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,244 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Red Sands</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #7b140e;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #8a1a12 0%, #4a0a06 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.7),
0 10px 30px rgba(123, 20, 14, 0.4);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #5e0f0a;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #8b2018;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #ffe1b9;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #7b140e;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #ffe1b9;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #ffe1b9;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.dim {
color: #c4916a;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #ffe1b9;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #ffe1b9;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #ffffff;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-red-sands"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys009</span>
<span class="output-line">Fetching https://api.example.com/status</span>
<span class="output-line dim"> HTTP/2 200</span>
<span class="output-line dim"> content-type: application/json</span>
<span class="output-line dim"> x-request-id: a3f9c21e-04b2-4d78</span>
<span class="output-line">{</span>
<span class="output-line"> "status": "healthy",</span>
<span class="output-line"> "version": "2.4.1",</span>
<span class="output-line bold"> "uptime": "14d 6h 32m"</span>
<span class="output-line">}</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "curl -s api.example.com/status | jq";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.4);
const blinkTimes = [4.6, 5.0, 5.4, 5.8, 6.2, 6.6];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 7.0);
window.__timelines["code-snippet-apple-terminal-red-sands"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-red-sands",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Red Sands",
"description": "Apple Terminal Red Sands profile: deep red background with sandy text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-red-sands.html",
"target": "compositions/code-snippet-apple-terminal-red-sands.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,250 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Silver Aerogel</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #2a2a2a;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #3a3a3a 0%, #1c1c1c 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.6),
0 10px 30px rgba(232, 232, 232, 0.05);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #2a2a2a;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #444444;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #3d3d3d;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #ffffff;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #ffffff;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.dim {
color: #aaaaaa;
}
.output-line.success {
color: #7fffb3;
}
.output-line.warn {
color: #ffd700;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #e8e8e8;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #ffffff;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #e8e8e8;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-silver-aerogel"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys010</span>
<span class="output-line">Checking system resources...</span>
<span class="output-line">Filesystem Size Used Avail Use%</span>
<span class="output-line">/dev/disk3s1s1 460G 142G 302G 32%</span>
<span class="output-line dim">/dev/disk3s6 460G 5.0G 302G 2%</span>
<span class="output-line">/dev/disk3s2 460G 11G 302G 4%</span>
<span class="output-line warn">Memory: 14.2 GB / 16.0 GB used (89%)</span>
<span class="output-line success">CPU: 8-core, 12% load average</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "df -h && vm_stat";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-silver-aerogel"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-silver-aerogel",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Silver Aerogel",
"description": "Apple Terminal Silver Aerogel profile: dark grey background with white text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-silver-aerogel.html",
"target": "compositions/code-snippet-apple-terminal-silver-aerogel.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,247 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Apple Terminal Solid Colors</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #4c0099;
font-family: "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}
#scene {
width: 1920px;
height: 1080px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, #5a00b3 0%, #2e0060 100%);
}
.terminal-window {
width: 1400px;
height: 700px;
border-radius: 10px;
overflow: hidden;
box-shadow:
0 30px 80px rgba(0, 0, 0, 0.7),
0 10px 30px rgba(76, 0, 153, 0.4);
display: flex;
flex-direction: column;
}
.titlebar {
height: 38px;
background: #3a0077;
display: flex;
align-items: center;
padding: 0 14px;
flex-shrink: 0;
border-bottom: 1px solid #6600bb;
position: relative;
}
.traffic-lights {
display: flex;
gap: 8px;
align-items: center;
}
.traffic-lights span {
width: 13px;
height: 13px;
border-radius: 50%;
display: inline-block;
}
.traffic-lights .close {
background: #ff5f57;
border: 1px solid #e0443e;
}
.traffic-lights .minimize {
background: #ffbd2e;
border: 1px solid #dfa123;
}
.traffic-lights .fullscreen {
background: #28c840;
border: 1px solid #1aab29;
}
.window-title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
font-weight: 500;
letter-spacing: -0.1px;
}
.terminal-canvas {
flex: 1;
background: #4c0099;
padding: 18px 20px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #ffffff;
}
.output-lines {
margin-bottom: 4px;
}
.output-line {
display: block;
white-space: pre;
opacity: 0;
color: #ffffff;
}
.output-line.bold {
font-weight: bold;
color: #ffffff;
}
.output-line.dim {
color: rgba(255, 255, 255, 0.55);
}
.output-line.accent {
color: #cc99ff;
font-weight: bold;
}
.input-line {
display: flex;
align-items: center;
white-space: pre;
}
.prompt {
color: #cc99ff;
font-weight: bold;
user-select: none;
}
.typed-command {
color: #ffffff;
}
.cursor-block {
display: inline-block;
width: 9px;
height: 16px;
background: #ffffff;
vertical-align: text-bottom;
margin-left: 1px;
}
</style>
</head>
<body>
<div
id="scene"
data-composition-id="code-snippet-apple-terminal-solid-colors"
data-width="1920"
data-height="1080"
>
<div class="terminal-window">
<div class="titlebar">
<div class="traffic-lights">
<span class="close"></span>
<span class="minimize"></span>
<span class="fullscreen"></span>
</div>
<span class="window-title">bash — 80×24</span>
</div>
<div class="terminal-canvas">
<div class="output-lines">
<span class="output-line dim">Last login: Mon Jun 2 09:14:22 on ttys011</span>
<span class="output-line">Initializing HyperFrames project...</span>
<span class="output-line dim"> Creating project structure</span>
<span class="output-line dim"> Copying template files</span>
<span class="output-line dim"> Installing dependencies</span>
<span class="output-line"> added 142 packages in 3.4s</span>
<span class="output-line accent"> ✓ Project ready at ./my-video</span>
<span class="output-line bold"> Run: cd my-video && npx hyperframes preview</span>
</div>
<div class="input-line">
<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span
><span class="cursor-block"></span>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<script>
window.__timelines = window.__timelines || {};
const command = "npx hyperframes init my-video";
const typedEl = document.querySelector(".typed-command");
const cursorEl = document.querySelector(".cursor-block");
const outputLines = document.querySelectorAll(".output-line");
const tl = gsap.timeline({ paused: true });
tl.set(typedEl, { text: "" }, 0);
const charDuration = 1.5 / command.length;
command.split("").forEach((char, i) => {
tl.add(
() => {
typedEl.textContent = command.slice(0, i + 1);
},
0.5 + i * charDuration,
);
});
tl.set(cursorEl, { opacity: 0 }, 2.2);
tl.set(outputLines[0], { opacity: 1 }, 2.3);
tl.add(() => {
typedEl.textContent = "";
}, 2.5);
outputLines.forEach((line, i) => {
if (i === 0) return;
tl.set(line, { opacity: 1 }, 2.8 + i * 0.1);
});
tl.add(() => {
const inputLine = document.querySelector(".input-line");
const newPrompt = document.createElement("div");
newPrompt.className = "input-line";
newPrompt.innerHTML =
'<span class="prompt">user@Mac ~ % </span><span class="typed-command"></span><span class="cursor-block" id="final-cursor"></span>';
inputLine.style.display = "none";
inputLine.parentNode.appendChild(newPrompt);
}, 4.2);
const blinkTimes = [4.4, 4.8, 5.2, 5.6, 6.0, 6.4];
blinkTimes.forEach((t, i) => {
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = i % 2 === 0 ? "0" : "1";
}, t);
});
tl.add(() => {
const fc = document.getElementById("final-cursor");
if (fc) fc.style.opacity = "1";
}, 6.8);
window.__timelines["code-snippet-apple-terminal-solid-colors"] = tl;
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-apple-terminal-solid-colors",
"type": "hyperframes:block",
"title": "Code Snippet - Apple Terminal Solid Colors",
"description": "Apple Terminal Solid Colors profile: deep purple background with white text, per-character typing animation of a shell session.",
"tags": ["code", "developer", "showcase", "terminal", "apple", "apple-terminal"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 12,
"files": [
{
"path": "code-snippet-apple-terminal-solid-colors.html",
"target": "compositions/code-snippet-apple-terminal-solid-colors.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-dark-2026",
"type": "hyperframes:block",
"title": "Code Snippet - Dark 2026",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-dark-2026.html",
"target": "compositions/code-snippet-dark-2026.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-dark-modern",
"type": "hyperframes:block",
"title": "Code Snippet - Dark Modern",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-dark-modern.html",
"target": "compositions/code-snippet-dark-modern.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-dark-plus",
"type": "hyperframes:block",
"title": "Code Snippet - Dark+",
"description": "VS Code workbench with per-character typing animation in the Dark+ theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-dark-plus.html",
"target": "compositions/code-snippet-dark-plus.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
@@ -0,0 +1,665 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Snippet Flight</title>
<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: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
font-family: "JetBrains Mono", monospace;
color: #e6edf3;
}
.bg-field {
position: absolute;
inset: 0;
background: radial-gradient(1200px 700px at 50% 18%, #0e1726 0%, #070b12 55%, #05070b 100%);
}
.bg-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(88, 166, 255, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(88, 166, 255, 0.05) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(1100px 620px at 50% 42%, #000 0%, transparent 78%);
}
.bg-glow {
position: absolute;
width: 900px;
height: 900px;
border-radius: 50%;
filter: blur(120px);
opacity: 0.5;
}
.bg-glow.a {
background: #1f6feb55;
left: -180px;
top: -200px;
}
.bg-glow.b {
background: #2ea04355;
right: -200px;
bottom: -260px;
}
.editor {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 1380px;
height: 800px;
background: #0b0f17;
border: 1px solid #1d2733;
border-radius: 16px;
box-shadow:
0 40px 120px rgba(0, 0, 0, 0.6),
0 2px 0 rgba(255, 255, 255, 0.03) inset;
overflow: hidden;
display: flex;
flex-direction: column;
}
.titlebar {
height: 56px;
flex: 0 0 56px;
display: flex;
align-items: center;
gap: 16px;
padding: 0 22px;
background: linear-gradient(#11161f, #0c111a);
border-bottom: 1px solid #1b2430;
}
.dots {
display: flex;
gap: 10px;
}
.dot {
width: 14px;
height: 14px;
border-radius: 50%;
}
.dot.r {
background: #ff5f57;
}
.dot.y {
background: #febc2e;
}
.dot.g {
background: #28c840;
}
.filename {
font-size: 19px;
color: #8b98a9;
letter-spacing: 0.2px;
}
.filename .accent {
color: #d6e2f0;
}
.code-surface {
position: relative;
flex: 1 1 auto;
overflow: hidden;
}
.scene {
position: absolute;
inset: 0;
opacity: 0;
will-change: opacity;
}
.code {
position: absolute;
top: 38px;
left: 0;
right: 0;
padding: 0 44px 0 104px;
font-size: 30px;
line-height: 46px;
font-variant-ligatures: none;
tab-size: 2;
}
.gutter {
position: absolute;
top: 38px;
left: 0;
width: 84px;
padding-right: 18px;
font-size: 30px;
line-height: 46px;
text-align: right;
color: #828c9b;
user-select: none;
}
.ln {
display: block;
height: 46px;
}
.line {
display: block;
min-height: 46px;
white-space: pre;
position: relative;
z-index: 1;
}
.tok {
display: inline-block;
white-space: pre;
will-change: transform, opacity;
}
.caret {
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 32px;
margin-top: 6px;
background: #58a6ff;
border-radius: 1px;
z-index: 3;
}
.hl-box {
position: absolute;
background: rgba(88, 166, 255, 0.16);
border-left: 3px solid #58a6ff;
border-radius: 6px;
z-index: 0;
overflow: hidden;
}
.diff-line {
display: block;
min-height: 0;
line-height: 46px;
white-space: pre;
position: relative;
overflow: hidden;
padding-left: 14px;
}
.diff-sign {
display: inline-block;
width: 22px;
color: #41506220;
}
.diff-del {
background: rgba(248, 81, 73, 0.12);
box-shadow: inset 3px 0 #f85149;
}
.diff-add {
background: rgba(63, 185, 80, 0.12);
box-shadow: inset 3px 0 #3fb950;
}
.diff-del .diff-sign {
color: #f85149;
}
.diff-add .diff-sign {
color: #3fb950;
}
.flight-block {
position: absolute;
white-space: pre;
font-size: 27px;
line-height: 40px;
padding: 11px 22px;
border-radius: 11px;
background: #0f1722;
border: 1px solid #233044;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
will-change: transform, opacity;
}
.flight-target {
position: absolute;
border: 1.5px dashed #2a3a4f;
border-radius: 14px;
opacity: 0;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-snippet-flight"
data-start="0"
data-duration="6"
data-width="1920"
data-height="1080"
>
<div class="bg-field" data-layout-ignore></div>
<div class="bg-grid" data-layout-ignore></div>
<div class="bg-glow a" data-layout-ignore></div>
<div class="bg-glow b" data-layout-ignore></div>
<div class="editor" id="editor" data-layout-ignore>
<div class="titlebar">
<div class="dots">
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
</div>
<span class="filename"
><span class="accent">pipeline.js</span> — Code Snippet Flight</span
>
</div>
<div class="code-surface" id="surface"></div>
</div>
</div>
<script>
window.__TOKENS = {
flight: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: "const x = parse(input)",
tokens: [
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-0",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-2",
content: "x",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-4",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-5",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-6",
content: "parse",
color: "#B392F0",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-7",
content: "(input)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
{
code: "const y = transform(x)",
tokens: [
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-0",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "ulDeJnFQa2Vy-61y5zTTA7sNfq7d4aUawNMAxQ6sVgg-2",
content: "y",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-4",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-5",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "ulDeJnFQa2Vy-61y5zTTA7sNfq7d4aUawNMAxQ6sVgg-6",
content: "transform",
color: "#B392F0",
fontStyle: 0,
},
{
key: "ulDeJnFQa2Vy-61y5zTTA7sNfq7d4aUawNMAxQ6sVgg-7",
content: "(x)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "ulDeJnFQa2Vy-61y5zTTA7sNfq7d4aUawNMAxQ6sVgg-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
{
code: "const z = render(y)",
tokens: [
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-0",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "wFuhzZNydG-3inU2s1h1gU8Kivya8CAP9gl9S4MBQj4-2",
content: "z",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-4",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "qABRRXThYBzvlFJqemsh1aauYJqWMIPHhxkj-uoxex4-5",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "wFuhzZNydG-3inU2s1h1gU8Kivya8CAP9gl9S4MBQj4-6",
content: "render",
color: "#B392F0",
fontStyle: 0,
},
{
key: "wFuhzZNydG-3inU2s1h1gU8Kivya8CAP9gl9S4MBQj4-7",
content: "(y)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "wFuhzZNydG-3inU2s1h1gU8Kivya8CAP9gl9S4MBQj4-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = { id: "code-snippet-flight", effect: "flight", seq: "flight", duration: 6 };
</script>
<script>
// hf-code-anim.js — self-contained code-animation engine for HyperFrames registry blocks.
//
// Reuses Shiki Magic Move's baked output (window.__TOKENS, baked at author time) and
// drives the animation as a PAUSED GSAP timeline the HyperFrames engine seeks per frame —
// NOT CSS transitions (those break under non-sequential frame seeking). FLIP measurement
// runs once inside document.fonts.ready (glyph metrics must be final). Each block sets
// window.__BLOCK = { id, effect, seq, line?, duration } and includes this engine; the
// engine builds one scene that fills the composition and registers window.__timelines[id].
(function () {
"use strict";
var T = window.__TOKENS || {};
function lineDiv() {
var d = document.createElement("div");
d.className = "line";
return d;
}
// Render a code state's keyed tokens into codeEl as lines of inline-block .tok spans.
function renderState(codeEl, state) {
codeEl.textContent = "";
var keyToEl = new Map();
var line = lineDiv();
codeEl.appendChild(line);
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
line = lineDiv();
codeEl.appendChild(line);
continue;
}
var span = document.createElement("span");
span.className = "tok";
span.textContent = t.content;
span.style.color = t.color;
if (t.fontStyle & 1) span.style.fontStyle = "italic";
if (t.fontStyle & 2) span.style.fontWeight = "700";
line.appendChild(span);
keyToEl.set(t.key, span);
}
var last = codeEl.lastChild;
if (last && last.className === "line" && last.children.length === 0)
codeEl.removeChild(last);
return keyToEl;
}
function rectsOf(keyToEl) {
var m = new Map();
keyToEl.forEach(function (el, k) {
var r = el.getBoundingClientRect();
m.set(k, { left: r.left, top: r.top });
});
return m;
}
function makeScene(surface, withGutter) {
var scene = document.createElement("div");
scene.className = "scene";
if (withGutter) {
var g = document.createElement("div");
g.className = "gutter";
scene.appendChild(g);
}
var code = document.createElement("div");
code.className = "code";
scene.appendChild(code);
surface.appendChild(scene);
return { scene: scene, code: code, gutter: scene.querySelector(".gutter") };
}
function fillGutter(g, n) {
var html = "";
for (var i = 1; i <= n; i++) html += '<span class="ln">' + i + "</span>";
g.innerHTML = html;
}
function splitLines(state) {
var lines = [{ text: "", tokens: [] }];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push({ text: "", tokens: [] });
continue;
}
var cur = lines[lines.length - 1];
cur.tokens.push(t);
cur.text += t.content;
}
if (lines.length && lines[lines.length - 1].tokens.length === 0) lines.pop();
return lines;
}
function lineDiff(a, b) {
var n = a.length;
var m = b.length;
var dp = [];
for (var i = 0; i <= n; i++) dp.push(new Array(m + 1).fill(0));
for (var i = n - 1; i >= 0; i--) {
for (var j = m - 1; j >= 0; j--) {
dp[i][j] =
a[i].text === b[j].text
? dp[i + 1][j + 1] + 1
: Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
var ops = [];
var i = 0;
var j = 0;
while (i < n && j < m) {
if (a[i].text === b[j].text) {
ops.push({ type: "same", line: b[j] });
i++;
j++;
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
ops.push({ type: "del", line: a[i] });
i++;
} else {
ops.push({ type: "add", line: b[j] });
j++;
}
}
while (i < n) ops.push({ type: "del", line: a[i++] });
while (j < m) ops.push({ type: "add", line: b[j++] });
return ops;
}
// ---- single-scene effect builders (fade in, play, hold to end) -------------
var FADE = 0.45;
function flight(tl, surface, states, start) {
var FLY = 0.95;
var STAGGER = 0.26;
var GAP = 20;
var parts = makeScene(surface, false);
parts.code.remove();
var scene = parts.scene;
var target = document.createElement("div");
target.className = "flight-target";
scene.appendChild(target);
var W = surface.clientWidth;
var H = surface.clientHeight;
var blocks = states.map(function (st) {
var blk = document.createElement("div");
blk.className = "flight-block";
renderState(blk, st);
scene.appendChild(blk);
return blk;
});
var n = blocks.length;
// Pass 1: measure natural size, then make every chip the SAME width (symmetry).
var maxW = 0;
var chipH = 0;
blocks.forEach(function (blk) {
var r = blk.getBoundingClientRect();
if (r.width > maxW) maxW = r.width;
if (r.height > chipH) chipH = r.height;
});
blocks.forEach(function (blk) {
blk.style.width = maxW + "px";
});
// Pass 2: evenly-stacked, left-aligned, group centered in the surface.
var stackH = n * chipH + (n - 1) * GAP;
var destLeft = Math.round((W - maxW) / 2);
var topY = Math.round((H - stackH) / 2);
blocks.forEach(function (blk, i) {
var destY = topY + i * (chipH + GAP);
blk.style.left = destLeft + "px";
blk.style.top = destY + "px";
// fly straight in from the left to the shared left edge — clean, no skew
var srcX = destLeft - W * 0.32;
tl.fromTo(
blk,
{ x: srcX - destLeft, opacity: 0, scale: 0.96 },
{ x: 0, opacity: 1, scale: 1, duration: FLY, ease: "power3.out" },
start + FADE + i * STAGGER,
);
});
// Even-padded panel tightly wrapping the uniform stack.
var padX = 30;
var padY = 24;
target.style.left = destLeft - padX + "px";
target.style.top = topY - padY + "px";
target.style.width = maxW + padX * 2 + "px";
target.style.height = stackH + padY * 2 + "px";
var landAt = start + FADE + (n - 1) * STAGGER + FLY;
tl.set(scene, { opacity: 1 }, 0);
tl.to(target, { opacity: 1, duration: 0.5, ease: "power1.out" }, landAt - 0.5);
}
function buildEffect(tl, surface, spec) {
var start = 0.45;
var seq = T[spec.seq];
if (spec.effect === "flight") flight(tl, surface, seq.states, start);
}
function go() {
var spec = window.__BLOCK;
var surface = document.getElementById("surface");
var root = document.getElementById("root");
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
window.__timelines["code-snippet-flight"] = tl; // register synchronously
document.fonts.ready.then(function () {
tl.from("#editor", { opacity: 0, scale: 0.985, duration: 0.5, ease: "power2.out" }, 0);
buildEffect(tl, surface, spec);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-flight",
"type": "hyperframes:block",
"title": "Code Snippet Flight",
"description": "Discrete code snippets fly in from the side and assemble into a stacked program, staggered. Block-level FLIP.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 6,
"tags": ["code", "code-animation", "flight", "developer"],
"files": [
{
"path": "code-snippet-flight.html",
"target": "compositions/code-snippet-flight.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-high-contrast-light",
"type": "hyperframes:block",
"title": "Code Snippet - High Contrast Light",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-high-contrast-light.html",
"target": "compositions/code-snippet-high-contrast-light.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-high-contrast",
"type": "hyperframes:block",
"title": "Code Snippet - High Contrast",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-high-contrast.html",
"target": "compositions/code-snippet-high-contrast.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-light-2026",
"type": "hyperframes:block",
"title": "Code Snippet - Light 2026",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-light-2026.html",
"target": "compositions/code-snippet-light-2026.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-light-modern",
"type": "hyperframes:block",
"title": "Code Snippet - Light Modern",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-light-modern.html",
"target": "compositions/code-snippet-light-modern.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-light-plus",
"type": "hyperframes:block",
"title": "Code Snippet - Light+",
"description": "VS Code workbench with per-character typing animation in the Light+ theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-light-plus.html",
"target": "compositions/code-snippet-light-plus.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-monokai",
"type": "hyperframes:block",
"title": "Code Snippet - Monokai",
"description": "VS Code workbench with per-character typing animation in the Monokai theme. Full editor chrome with activity bar, sidebar, tabs, terminal, and status bar.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-monokai.html",
"target": "compositions/code-snippet-monokai.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-solarized-light",
"type": "hyperframes:block",
"title": "Code Snippet - Solarized Light",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-solarized-light.html",
"target": "compositions/code-snippet-solarized-light.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-visual-studio-dark",
"type": "hyperframes:block",
"title": "Code Snippet - Visual Studio Dark",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-visual-studio-dark.html",
"target": "compositions/code-snippet-visual-studio-dark.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-snippet-visual-studio-light",
"type": "hyperframes:block",
"title": "Code Snippet - Visual Studio Light",
"description": "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.",
"tags": ["code", "developer", "showcase", "vscode"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 11,
"files": [
{
"path": "code-snippet-visual-studio-light.html",
"target": "compositions/code-snippet-visual-studio-light.html",
"type": "hyperframes:composition"
},
{
"path": "background.jpeg",
"target": "assets/background.jpeg",
"type": "hyperframes:asset"
}
]
}
+763
View File
@@ -0,0 +1,763 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Code Typing</title>
<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: #05070b;
}
#root {
position: relative;
width: 1920px;
height: 1080px;
font-family: "JetBrains Mono", monospace;
color: #e6edf3;
}
.bg-field {
position: absolute;
inset: 0;
background: radial-gradient(1200px 700px at 50% 18%, #0e1726 0%, #070b12 55%, #05070b 100%);
}
.bg-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(88, 166, 255, 0.05) 1px, transparent 1px),
linear-gradient(90deg, rgba(88, 166, 255, 0.05) 1px, transparent 1px);
background-size: 64px 64px;
mask-image: radial-gradient(1100px 620px at 50% 42%, #000 0%, transparent 78%);
}
.bg-glow {
position: absolute;
width: 900px;
height: 900px;
border-radius: 50%;
filter: blur(120px);
opacity: 0.5;
}
.bg-glow.a {
background: #1f6feb55;
left: -180px;
top: -200px;
}
.bg-glow.b {
background: #2ea04355;
right: -200px;
bottom: -260px;
}
.editor {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 1380px;
height: 800px;
background: #0b0f17;
border: 1px solid #1d2733;
border-radius: 16px;
box-shadow:
0 40px 120px rgba(0, 0, 0, 0.6),
0 2px 0 rgba(255, 255, 255, 0.03) inset;
overflow: hidden;
display: flex;
flex-direction: column;
}
.titlebar {
height: 56px;
flex: 0 0 56px;
display: flex;
align-items: center;
gap: 16px;
padding: 0 22px;
background: linear-gradient(#11161f, #0c111a);
border-bottom: 1px solid #1b2430;
}
.dots {
display: flex;
gap: 10px;
}
.dot {
width: 14px;
height: 14px;
border-radius: 50%;
}
.dot.r {
background: #ff5f57;
}
.dot.y {
background: #febc2e;
}
.dot.g {
background: #28c840;
}
.filename {
font-size: 19px;
color: #8b98a9;
letter-spacing: 0.2px;
}
.filename .accent {
color: #d6e2f0;
}
.code-surface {
position: relative;
flex: 1 1 auto;
overflow: hidden;
}
.scene {
position: absolute;
inset: 0;
opacity: 0;
will-change: opacity;
}
.code {
position: absolute;
top: 38px;
left: 0;
right: 0;
padding: 0 44px 0 104px;
font-size: 30px;
line-height: 46px;
font-variant-ligatures: none;
tab-size: 2;
}
.gutter {
position: absolute;
top: 38px;
left: 0;
width: 84px;
padding-right: 18px;
font-size: 30px;
line-height: 46px;
text-align: right;
color: #828c9b;
user-select: none;
}
.ln {
display: block;
height: 46px;
}
.line {
display: block;
min-height: 46px;
white-space: pre;
position: relative;
z-index: 1;
}
.tok {
display: inline-block;
white-space: pre;
will-change: transform, opacity;
}
.caret {
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 32px;
margin-top: 6px;
background: #58a6ff;
border-radius: 1px;
z-index: 3;
}
.hl-box {
position: absolute;
background: rgba(88, 166, 255, 0.16);
border-left: 3px solid #58a6ff;
border-radius: 6px;
z-index: 0;
overflow: hidden;
}
.diff-line {
display: block;
min-height: 0;
line-height: 46px;
white-space: pre;
position: relative;
overflow: hidden;
padding-left: 14px;
}
.diff-sign {
display: inline-block;
width: 22px;
color: #41506220;
}
.diff-del {
background: rgba(248, 81, 73, 0.12);
box-shadow: inset 3px 0 #f85149;
}
.diff-add {
background: rgba(63, 185, 80, 0.12);
box-shadow: inset 3px 0 #3fb950;
}
.diff-del .diff-sign {
color: #f85149;
}
.diff-add .diff-sign {
color: #3fb950;
}
.flight-block {
position: absolute;
white-space: pre;
font-size: 27px;
line-height: 40px;
padding: 11px 22px;
border-radius: 11px;
background: #0f1722;
border: 1px solid #233044;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
will-change: transform, opacity;
}
.flight-target {
position: absolute;
border: 1.5px dashed #2a3a4f;
border-radius: 14px;
opacity: 0;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="code-typing"
data-start="0"
data-duration="5"
data-width="1920"
data-height="1080"
>
<div class="bg-field" data-layout-ignore></div>
<div class="bg-grid" data-layout-ignore></div>
<div class="bg-glow a" data-layout-ignore></div>
<div class="bg-glow b" data-layout-ignore></div>
<div class="editor" id="editor" data-layout-ignore>
<div class="titlebar">
<div class="dots">
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
</div>
<span class="filename"><span class="accent">loadConfig.js</span> — Code Typing</span>
</div>
<div class="code-surface" id="surface"></div>
</div>
</div>
<script>
window.__TOKENS = {
feature: {
lang: "js",
theme: "github-dark",
bg: "#24292e",
fg: "#e1e4e8",
states: [
{
code: 'async function loadConfig(path) {\n const raw = await readFile(path, "utf8")\n const config = JSON.parse(raw)\n return validate(config)\n}',
tokens: [
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-0",
content: "async",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-1",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-2",
content: "function",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-3",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-4",
content: "loadConfig",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-5",
content: "(",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-6",
content: "path",
color: "#FFAB70",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-7",
content: ") {",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-8",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-9",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-10",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-11",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-12",
content: "raw",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-13",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-14",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-15",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-16",
content: "await",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-17",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-18",
content: "readFile",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-19",
content: "(path,",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-20",
content: " ",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-21",
content: '"utf8"',
color: "#9ECBFF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-22",
content: ")",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-23",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-24",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-25",
content: "const",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-26",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-27",
content: "config",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-28",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-29",
content: "=",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-30",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-31",
content: "JSON",
color: "#79B8FF",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-32",
content: ".",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-33",
content: "parse",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-34",
content: "(raw)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-35",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-36",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-37",
content: "return",
color: "#F97583",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-38",
content: " ",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-39",
content: "validate",
color: "#B392F0",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-40",
content: "(config)",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-41",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-42",
content: "}",
color: "#E1E4E8",
fontStyle: 0,
},
{
key: "SPx9u4TyzfMqSHpbjPHnWFQU8lPVEPieF6W5Vtu-bNA-43",
content: "\n",
color: "#e1e4e8",
fontStyle: 0,
},
],
},
],
},
};
window.__BLOCK = { id: "code-typing", effect: "typing", seq: "feature", duration: 5 };
</script>
<script>
// hf-code-anim.js — self-contained code-animation engine for HyperFrames registry blocks.
//
// Reuses Shiki Magic Move's baked output (window.__TOKENS, baked at author time) and
// drives the animation as a PAUSED GSAP timeline the HyperFrames engine seeks per frame —
// NOT CSS transitions (those break under non-sequential frame seeking). FLIP measurement
// runs once inside document.fonts.ready (glyph metrics must be final). Each block sets
// window.__BLOCK = { id, effect, seq, line?, duration } and includes this engine; the
// engine builds one scene that fills the composition and registers window.__timelines[id].
(function () {
"use strict";
var T = window.__TOKENS || {};
function lineDiv() {
var d = document.createElement("div");
d.className = "line";
return d;
}
// Render a code state's keyed tokens into codeEl as lines of inline-block .tok spans.
function renderState(codeEl, state) {
codeEl.textContent = "";
var keyToEl = new Map();
var line = lineDiv();
codeEl.appendChild(line);
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
line = lineDiv();
codeEl.appendChild(line);
continue;
}
var span = document.createElement("span");
span.className = "tok";
span.textContent = t.content;
span.style.color = t.color;
if (t.fontStyle & 1) span.style.fontStyle = "italic";
if (t.fontStyle & 2) span.style.fontWeight = "700";
line.appendChild(span);
keyToEl.set(t.key, span);
}
var last = codeEl.lastChild;
if (last && last.className === "line" && last.children.length === 0)
codeEl.removeChild(last);
return keyToEl;
}
function rectsOf(keyToEl) {
var m = new Map();
keyToEl.forEach(function (el, k) {
var r = el.getBoundingClientRect();
m.set(k, { left: r.left, top: r.top });
});
return m;
}
function makeScene(surface, withGutter) {
var scene = document.createElement("div");
scene.className = "scene";
if (withGutter) {
var g = document.createElement("div");
g.className = "gutter";
scene.appendChild(g);
}
var code = document.createElement("div");
code.className = "code";
scene.appendChild(code);
surface.appendChild(scene);
return { scene: scene, code: code, gutter: scene.querySelector(".gutter") };
}
function fillGutter(g, n) {
var html = "";
for (var i = 1; i <= n; i++) html += '<span class="ln">' + i + "</span>";
g.innerHTML = html;
}
function splitLines(state) {
var lines = [{ text: "", tokens: [] }];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
lines.push({ text: "", tokens: [] });
continue;
}
var cur = lines[lines.length - 1];
cur.tokens.push(t);
cur.text += t.content;
}
if (lines.length && lines[lines.length - 1].tokens.length === 0) lines.pop();
return lines;
}
function lineDiff(a, b) {
var n = a.length;
var m = b.length;
var dp = [];
for (var i = 0; i <= n; i++) dp.push(new Array(m + 1).fill(0));
for (var i = n - 1; i >= 0; i--) {
for (var j = m - 1; j >= 0; j--) {
dp[i][j] =
a[i].text === b[j].text
? dp[i + 1][j + 1] + 1
: Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
var ops = [];
var i = 0;
var j = 0;
while (i < n && j < m) {
if (a[i].text === b[j].text) {
ops.push({ type: "same", line: b[j] });
i++;
j++;
} else if (dp[i + 1][j] >= dp[i][j + 1]) {
ops.push({ type: "del", line: a[i] });
i++;
} else {
ops.push({ type: "add", line: b[j] });
j++;
}
}
while (i < n) ops.push({ type: "del", line: a[i++] });
while (j < m) ops.push({ type: "add", line: b[j++] });
return ops;
}
// ---- single-scene effect builders (fade in, play, hold to end) -------------
var FADE = 0.45;
function typing(tl, surface, state, start) {
var PER = 0.028; // seconds per character — smooth, fast typewriter
var parts = makeScene(surface, true);
var code = parts.code;
// Per-CHARACTER render (granular reveal reads smoother than per-token pops).
code.textContent = "";
var line = document.createElement("div");
line.className = "line";
code.appendChild(line);
var chars = [];
for (var i = 0; i < state.tokens.length; i++) {
var t = state.tokens[i];
if (t.content === "\n") {
line = document.createElement("div");
line.className = "line";
code.appendChild(line);
continue;
}
for (var c = 0; c < t.content.length; c++) {
var span = document.createElement("span");
span.className = "tok";
span.textContent = t.content[c];
span.style.color = t.color;
if (t.fontStyle & 1) span.style.fontStyle = "italic";
if (t.fontStyle & 2) span.style.fontWeight = "700";
line.appendChild(span);
chars.push({ el: span, ws: t.content[c] === " " });
}
}
var last = code.lastChild;
if (last && last.className === "line" && last.children.length === 0)
code.removeChild(last);
fillGutter(parts.gutter, code.querySelectorAll(".line").length);
var base = code.getBoundingClientRect();
var caret = document.createElement("div");
caret.className = "caret";
code.appendChild(caret);
tl.set(parts.scene, { opacity: 0 }, 0);
tl.to(parts.scene, { opacity: 1, duration: FADE, ease: "power1.out" }, start);
var t0 = start + FADE;
if (chars.length) {
var r0 = chars[0].el.getBoundingClientRect();
tl.set(caret, { x: r0.left - base.left, y: r0.top - base.top, opacity: 1 }, 0);
}
chars.forEach(function (c, i) {
var at = t0 + i * PER;
tl.set(c.el, { opacity: 0 }, 0);
// soft per-char fade (overlaps neighbors → smooth wave); whitespace appears instantly
tl.to(c.el, { opacity: 1, duration: c.ws ? 0.01 : 0.12, ease: "power1.out" }, at);
// caret glides at constant speed to each char's right edge (linear = no stop-start jitter)
var r = c.el.getBoundingClientRect();
tl.to(
caret,
{ x: r.right - base.left, y: r.top - base.top, duration: PER, ease: "none" },
at,
);
});
}
function buildEffect(tl, surface, spec) {
var start = 0.45;
var seq = T[spec.seq];
if (spec.effect === "typing") typing(tl, surface, seq.states[0], start);
}
function go() {
var spec = window.__BLOCK;
var surface = document.getElementById("surface");
var root = document.getElementById("root");
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
// Build inside fonts.ready (glyph metrics must be final), then register.
// Register ONLY after the timeline is fully built: the runtime's
// sub-composition readiness gate treats "key present" as "ready" and
// nests the child once. An empty timeline registered before this build
// would be nested empty and never re-nested → blank render when used as
// a sub-composition. See the contract in engine frameCapture.ts.
document.fonts.ready.then(function () {
tl.from("#editor", { opacity: 0, scale: 0.985, duration: 0.5, ease: "power2.out" }, 0);
buildEffect(tl, surface, spec);
var dur = parseFloat(root.dataset.duration) || tl.duration();
tl.to({}, { duration: dur }, 0); // pad to full composition length
window.__timelines["code-typing"] = tl; // register AFTER setup completes
if (typeof window.__hfForceTimelineRebind === "function") {
window.__hfForceTimelineRebind(); // re-nest now that we are populated
}
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", go);
else go();
})();
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "code-typing",
"type": "hyperframes:block",
"title": "Code Typing",
"description": "Token-streamed typing reveal with a caret that tracks the frontier — deterministic, no CSS animation.",
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 5,
"tags": ["code", "code-animation", "typing", "developer"],
"files": [
{
"path": "code-typing.html",
"target": "compositions/code-typing.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+377
View File
@@ -0,0 +1,377 @@
<!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>
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<style>
[data-composition-id="main"] {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
background: #283618;
}
/* Blueprint grid */
.bp-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
}
/* Layout */
.bp-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1200px;
display: flex;
align-items: center;
justify-content: center;
}
.bp-right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 720px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px 60px 60px 40px;
}
.bp-divider {
position: absolute;
left: 1200px;
top: 60px;
bottom: 60px;
width: 1px;
background: #a7c957;
opacity: 0.15;
}
.bp-number {
font-family: "Space Mono", monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.4em;
text-transform: uppercase;
position: absolute;
top: 40px;
left: 60px;
color: #a7c957;
}
/* Right panel typography */
.bp-name {
font-family: "Bebas Neue", sans-serif;
font-size: 38px;
letter-spacing: 0.08em;
margin-bottom: 20px;
color: #a7c957;
}
.bp-plabel {
font-family: "Space Mono", monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
color: #a7c957;
opacity: 0.5;
}
.bp-prompt {
font-family: "JetBrains Mono", monospace;
font-size: 20px;
line-height: 1.6;
padding: 16px 20px;
border-radius: 6px;
margin-bottom: 20px;
color: #a7c957;
background: rgba(167, 201, 87, 0.06);
border: 1px solid rgba(167, 201, 87, 0.12);
}
.bp-desc {
font-family: "Lato", sans-serif;
font-size: 17px;
line-height: 1.6;
color: #8aaa9a;
opacity: 0.55;
}
/* GL scenes (hidden, just for texture capture) */
.scene {
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.scene-label {
font-family: "Bebas Neue", sans-serif;
font-size: 140px;
letter-spacing: 0.06em;
opacity: 0.12;
}
</style>
<div class="bp-grid"></div>
<div class="bp-divider"></div>
<div class="bp-number">13 / 14</div>
<!-- GL demo scenes (captured as textures, then hidden) -->
<div id="s1" class="scene" style="background: #283618">
<div class="scene-label" style="color: #a7c957">SCENE A</div>
</div>
<div id="s2" class="scene" style="background: #a7c957; opacity: 0">
<div class="scene-label" style="color: #283618">SCENE B</div>
</div>
<!-- GL canvas (left panel only) -->
<canvas
id="gl-canvas"
width="1200"
height="1080"
style="
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
z-index: 10;
pointer-events: none;
display: none;
"
>
</canvas>
<!-- Right panel metadata -->
<div class="bp-right">
<div class="bp-name">Cross-Warp Morph</div>
<div class="bp-plabel">Prompt</div>
<div class="bp-prompt">"use cross-warp morph shader transition"</div>
<div class="bp-desc">
Both scenes displace along a shared FBM noise field in opposite directions. Noise-driven
blend boundary.
</div>
</div>
<div
id="driver"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
window.__timelines = window.__timelines || {};
var glCanvas = document.getElementById("gl-canvas");
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
if (!gl) {
console.warn("WebGL not available");
window.__timelines["main"] = gsap.timeline({ paused: true });
} else {
gl.viewport(0, 0, 1200, 1080);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
var sceneTextures = {};
function captureScene(sceneId) {
var scene = document.getElementById(sceneId);
var origOpacity = scene.style.opacity;
var origZ = scene.style.zIndex;
scene.style.opacity = "1";
scene.style.zIndex = "999";
scene.offsetHeight;
var c = document.createElement("canvas");
c.width = 1200;
c.height = 1080;
var ctx = c.getContext("2d");
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
ctx.fillRect(0, 0, 1200, 1080);
var sr = scene.getBoundingClientRect();
var els = scene.querySelectorAll("*");
for (var i = 0; i < els.length; i++) {
var el = els[i],
cs = window.getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden") continue;
var r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) continue;
var x = r.left - sr.left,
y = r.top - sr.top,
w = r.width,
h = r.height;
ctx.save();
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
var bg = cs.backgroundColor;
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
ctx.fillStyle = bg;
ctx.fillRect(x, y, w, h);
}
var hasChildEls = el.querySelector("div,span,img,video");
var text = "";
for (var j = 0; j < el.childNodes.length; j++)
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
text = text.trim();
if (text && !hasChildEls) {
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
ctx.fillStyle = cs.color;
if (cs.letterSpacing && cs.letterSpacing !== "normal")
ctx.letterSpacing = cs.letterSpacing;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, x + w / 2, y + h / 2);
}
ctx.restore();
}
scene.style.opacity = origOpacity;
scene.style.zIndex = origZ;
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
sceneTextures[sceneId] = tex;
}
var vertSrc =
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
var quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
gl.STATIC_DRAW,
);
function compileShader(src, type) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
console.error("Shader:", gl.getShaderInfoLog(s));
return s;
}
function mkProg(fragSrc) {
var p = gl.createProgram();
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
console.error("Link:", gl.getProgramInfoLog(p));
return p;
}
var H =
"precision mediump float;" +
"varying vec2 v_uv;" +
"uniform sampler2D u_from, u_to;" +
"uniform float u_progress;" +
"uniform vec2 u_resolution;\n";
var NQ =
"float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}" +
"float vnoise(vec2 p){vec2 i=floor(p),f=fract(p);" +
"f=f*f*f*(f*(f*6.-15.)+10.);" +
"return mix(mix(hash(i),hash(i+vec2(1,0)),f.x)," +
"mix(hash(i+vec2(0,1)),hash(i+vec2(1,1)),f.x),f.y);}" +
"float fbm(vec2 p){float v=0.,a=.5;" +
"mat2 R=mat2(.8,.6,-.6,.8);" +
"for(int i=0;i<5;i++){v+=a*vnoise(p);p=R*p*2.02;a*=.5;}return v;}";
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
var progTrans = mkProg(
H +
NQ +
"void main(){vec2 disp=vec2(fbm(v_uv*3.),fbm(v_uv*3.+vec2(7.3,3.7)))-.5;vec2 fromUv=clamp(v_uv+disp*u_progress*.5,0.,1.);vec2 toUv=clamp(v_uv-disp*(1.-u_progress)*.5,0.,1.);vec4 A=texture2D(u_from,fromUv);vec4 B=texture2D(u_to,toUv);float n=fbm(v_uv*4.+vec2(3.1,1.7));float blend=smoothstep(.4,.6,n+u_progress*1.2-.6);gl_FragColor=mix(A,B,blend);}",
);
function renderShader(prog, texFrom, texTo, progress) {
gl.useProgram(prog);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texFrom);
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texTo);
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
var pos = gl.getAttribLocation(prog, "a_pos");
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function easeInOut(p) {
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
}
captureScene("s1");
captureScene("s2");
glCanvas.style.display = "block";
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
document.querySelectorAll(".scene").forEach(function (s) {
s.style.opacity = "0";
});
var tl = gsap.timeline({
paused: true,
onUpdate: function () {
var t = tl.time();
if (t >= 1.0 && t < 3.0) {
renderShader(
progTrans,
sceneTextures["s1"],
sceneTextures["s2"],
easeInOut((t - 1.0) / 2.0),
);
} else if (t >= 3.0) {
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
} else {
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
}
},
});
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
window.__timelines["main"] = tl;
} // end if (gl)
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "cross-warp-morph",
"type": "hyperframes:block",
"title": "Cross Warp Morph",
"description": "Shader transition with cross-warped morphing",
"tags": ["transition", "shader"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "cross-warp-morph.html",
"target": "compositions/cross-warp-morph.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
+457
View File
@@ -0,0 +1,457 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Data Chart</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Libre+Baskerville:wght@400;700&family=Libre+Franklin:wght@300;400;600&display=block"
rel="stylesheet"
/>
<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 {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #faf9f6;
}
</style>
</head>
<body>
<div
id="data-chart"
data-composition-id="data-chart"
data-width="1920"
data-height="1080"
data-start="0"
data-duration="15"
>
<div class="chart-container">
<!-- Header Section -->
<div class="header">
<h1 class="headline">Monthly Revenue vs. Conversion Rate</h1>
<p class="subtitle">JanJun 2024, in thousands</p>
<div class="key">
<div class="key-item">
<div class="key-box revenue-box"></div>
<span class="key-text">Revenue</span>
</div>
<div class="key-item">
<div class="key-line conversion-line"></div>
<span class="key-text">Conversion Rate</span>
</div>
</div>
</div>
<!-- SVG Chart Area -->
<svg class="chart-svg" viewBox="0 0 1600 700" preserveAspectRatio="xMidYMid meet">
<!-- Gridlines Group -->
<g class="gridlines"></g>
<!-- X-Axis Labels -->
<g class="x-axis-labels"></g>
<!-- Bars Group (Revenue) -->
<g class="bars-group"></g>
<!-- Bar Labels Group -->
<g class="bar-labels-group"></g>
<!-- Line Group (Conversion Rate) -->
<g class="line-group">
<path class="conversion-path" fill="none" stroke="#326FA8" stroke-width="1.5" />
<circle class="line-dot" r="5" fill="#326FA8" style="opacity: 0" />
</g>
<!-- Line Labels Group -->
<g class="line-labels-group"></g>
<!-- Baseline -->
<line x1="100" y1="600" x2="1500" y2="600" stroke="black" stroke-width="1" />
</svg>
<!-- Source Line -->
<div class="source">Source: Internal analytics</div>
</div>
<style>
[data-composition-id="data-chart"] {
width: 1920px;
height: 1080px;
background-color: #faf9f6;
font-family: "Libre Franklin", sans-serif;
color: #333;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
[data-composition-id="data-chart"] .chart-container {
width: 1600px;
height: 900px;
display: flex;
flex-direction: column;
position: relative;
transform: scale(1.15);
transform-origin: center center;
}
[data-composition-id="data-chart"] .header {
margin-bottom: 40px;
text-align: left;
}
[data-composition-id="data-chart"] .headline {
font-family: "Libre Baskerville", serif;
font-size: 42px;
margin: 0;
padding: 0;
clip-path: inset(0 100% 0 0);
white-space: nowrap;
}
[data-composition-id="data-chart"] .subtitle {
font-size: 16px;
color: #666;
margin: 8px 0 16px 0;
clip-path: inset(0 100% 0 0);
white-space: nowrap;
}
[data-composition-id="data-chart"] .key {
display: flex;
gap: 24px;
opacity: 0;
}
[data-composition-id="data-chart"] .key-item {
display: flex;
align-items: center;
gap: 8px;
}
[data-composition-id="data-chart"] .key-box {
width: 10px;
height: 10px;
background-color: #5c5c5c;
}
[data-composition-id="data-chart"] .key-line {
width: 16px;
height: 1.5px;
background-color: #326fa8;
}
[data-composition-id="data-chart"] .key-text {
font-size: 13px;
color: #666;
}
[data-composition-id="data-chart"] .chart-svg {
width: 100%;
height: 600px;
overflow: visible;
}
[data-composition-id="data-chart"] .source {
position: absolute;
bottom: 0;
left: 0;
font-size: 11px;
color: #999;
opacity: 0;
}
[data-composition-id="data-chart"] .grid-line {
stroke: #e8e8e8;
stroke-width: 0.5px;
opacity: 0;
}
[data-composition-id="data-chart"] .axis-label {
font-size: 14px;
fill: #666;
text-anchor: middle;
}
[data-composition-id="data-chart"] .bar {
fill: #5c5c5c;
}
[data-composition-id="data-chart"] .bar-label {
font-size: 14px;
fill: #333;
text-anchor: middle;
opacity: 0;
}
[data-composition-id="data-chart"] .line-label {
font-size: 14px;
fill: #326fa8;
font-weight: 600;
text-anchor: middle;
opacity: 0;
}
</style>
<script>
(function () {
const svg = document.querySelector('[data-composition-id="data-chart"] .chart-svg');
const tl = gsap.timeline({ paused: true });
// Data
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"];
const revenueData = [8, 12, 15, 11, 18, 22];
const conversionData = [2.1, 2.8, 3.2, 2.9, 3.8, 4.2];
// Chart Dimensions
const chartWidth = 1400;
const chartHeight = 500;
const startX = 100;
const startY = 600;
const barWidth = 80;
const spacing = (chartWidth - barWidth * months.length) / (months.length + 1);
// Scales
const maxRevenue = 25;
const maxConversion = 5;
const getBarY = (val) => startY - (val / maxRevenue) * chartHeight;
const getLineY = (val) => startY - (val / maxConversion) * chartHeight;
const getX = (i) => startX + spacing + i * (barWidth + spacing) + barWidth / 2;
// Setup Elements
const gridGroup = svg.querySelector(".gridlines");
const xAxisGroup = svg.querySelector(".x-axis-labels");
const barsGroup = svg.querySelector(".bars-group");
const barLabelsGroup = svg.querySelector(".bar-labels-group");
const lineLabelsGroup = svg.querySelector(".line-labels-group");
const conversionPath = svg.querySelector(".conversion-path");
const lineDot = svg.querySelector(".line-dot");
// Create Gridlines
for (let i = 1; i <= 5; i++) {
const y = startY - i * (chartHeight / 5);
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("x1", startX);
line.setAttribute("y1", y);
line.setAttribute("x2", startX + chartWidth);
line.setAttribute("y2", y);
line.setAttribute("class", "grid-line");
gridGroup.appendChild(line);
}
// Create X-Axis Labels & Bars & Bar Labels
const linePoints = [];
months.forEach((month, i) => {
const x = getX(i);
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
label.setAttribute("x", x);
label.setAttribute("y", startY + 30);
label.setAttribute("class", "axis-label");
label.textContent = month;
xAxisGroup.appendChild(label);
const barHeight = (revenueData[i] / maxRevenue) * chartHeight;
const bar = document.createElementNS("http://www.w3.org/2000/svg", "rect");
bar.setAttribute("x", x - barWidth / 2);
bar.setAttribute("y", startY);
bar.setAttribute("width", barWidth);
bar.setAttribute("height", 0);
bar.setAttribute("class", "bar");
barsGroup.appendChild(bar);
const barLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
barLabel.setAttribute("x", x);
barLabel.setAttribute("y", getBarY(revenueData[i]) - 10);
barLabel.setAttribute("class", "bar-label");
barLabel.textContent = `$${revenueData[i]}K`;
barLabelsGroup.appendChild(barLabel);
linePoints.push(`${x},${getLineY(conversionData[i])}`);
const lineLabel = document.createElementNS("http://www.w3.org/2000/svg", "text");
lineLabel.setAttribute("x", x);
lineLabel.setAttribute("y", getLineY(conversionData[i]) - 15);
lineLabel.setAttribute("class", "line-label");
lineLabel.textContent = `${conversionData[i]}%`;
lineLabelsGroup.appendChild(lineLabel);
});
// Set Path Data
conversionPath.setAttribute("d", `M ${linePoints.join(" L ")}`);
const pathLength = conversionPath.getTotalLength();
conversionPath.style.strokeDasharray = pathLength;
conversionPath.style.strokeDashoffset = pathLength;
// --- ANIMATION TIMELINE ---
tl.to(
'[data-composition-id="data-chart"] .headline',
{
clipPath: "inset(0 0% 0 0)",
duration: 1.2,
ease: "power1.inOut",
},
0,
);
tl.to(
'[data-composition-id="data-chart"] .subtitle',
{
clipPath: "inset(0 0% 0 0)",
duration: 1.2,
ease: "power1.inOut",
},
0.2,
);
tl.to(
'[data-composition-id="data-chart"] .key',
{
opacity: 1,
duration: 0.4,
ease: "power2.out",
},
1.0,
);
tl.to(
'[data-composition-id="data-chart"] .grid-line',
{
opacity: 1,
duration: 0.5,
stagger: 0.25,
ease: "power2.out",
},
0.5,
);
// Bars
const bars = barsGroup.querySelectorAll(".bar");
const barLabels = barLabelsGroup.querySelectorAll(".bar-label");
bars.forEach((bar, i) => {
const barHeight = (revenueData[i] / maxRevenue) * chartHeight;
const startTime = 1.5 + i * 0.5;
tl.to(
bar,
{
attr: { height: barHeight, y: startY - barHeight },
duration: 0.8,
ease: "power2.out",
},
startTime,
);
tl.to(
barLabels[i],
{
opacity: 1,
duration: 0.3,
ease: "power2.out",
},
startTime + 0.8,
);
});
// Line
const lastBarStartTime = 1.5 + (months.length - 1) * 0.5;
const lineStartTime = lastBarStartTime + 0.5;
tl.to(
conversionPath,
{
strokeDashoffset: 0,
duration: 3,
ease: "none",
},
lineStartTime,
);
// Line Dot & Labels
tl.set(
lineDot,
{
opacity: 1,
attr: { cx: getX(0), cy: getLineY(conversionData[0]) },
},
lineStartTime,
);
const lineLabels = lineLabelsGroup.querySelectorAll(".line-label");
months.forEach((_, i) => {
if (i > 0) {
const x = getX(i);
const y = getLineY(conversionData[i]);
tl.to(
lineDot,
{
attr: { cx: x, cy: y },
duration: 3 / (months.length - 1),
ease: "none",
},
lineStartTime + ((i - 1) / (months.length - 1)) * 3,
);
}
const labelTime = lineStartTime + (i / (months.length - 1)) * 3 + 0.2;
lineLabels[i].textContent = "0.0%";
tl.to(
lineLabels[i],
{
opacity: 1,
duration: 0.1,
ease: "power2.out",
},
labelTime,
);
const dummy = { val: 0 };
tl.to(
dummy,
{
val: conversionData[i],
duration: 0.8,
ease: "power2.out",
onUpdate: () => {
lineLabels[i].textContent = dummy.val.toFixed(1) + "%";
},
},
labelTime,
);
});
// Source Line
tl.to(
'[data-composition-id="data-chart"] .source',
{
opacity: 1,
duration: 0.5,
ease: "power2.out",
},
">+0.5",
);
window.__timelines = window.__timelines || {};
window.__timelines["data-chart"] = tl;
})();
</script>
</div>
</body>
</html>
@@ -0,0 +1,38 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "data-chart",
"type": "hyperframes:block",
"title": "Data Chart",
"description": "Animated bar + line chart with staggered reveal, NYT-style typography, and value labels",
"tags": ["data", "chart", "statistics"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 15,
"files": [
{
"path": "data-chart.html",
"target": "compositions/data-chart.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/data-chart.mp4",
"poster": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/data-chart.png"
},
"params": [
{
"key": "--bg-color",
"label": "Background",
"type": "color",
"default": "#faf9f6"
},
{
"key": "--text-color",
"label": "Text color",
"type": "color",
"default": "#333333"
}
]
}
@@ -0,0 +1,380 @@
<!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>
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<style>
[data-composition-id="main"] {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
background: #0d1b2a;
}
/* Blueprint grid */
.bp-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
}
/* Layout */
.bp-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1200px;
display: flex;
align-items: center;
justify-content: center;
}
.bp-right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 720px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px 60px 60px 40px;
}
.bp-divider {
position: absolute;
left: 1200px;
top: 60px;
bottom: 60px;
width: 1px;
background: #00f5d4;
opacity: 0.15;
}
.bp-number {
font-family: "Space Mono", monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.4em;
text-transform: uppercase;
position: absolute;
top: 40px;
left: 60px;
color: #00f5d4;
}
/* Right panel typography */
.bp-name {
font-family: "Bebas Neue", sans-serif;
font-size: 38px;
letter-spacing: 0.08em;
margin-bottom: 20px;
color: #00f5d4;
}
.bp-plabel {
font-family: "Space Mono", monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
color: #00f5d4;
opacity: 0.5;
}
.bp-prompt {
font-family: "JetBrains Mono", monospace;
font-size: 20px;
line-height: 1.6;
padding: 16px 20px;
border-radius: 6px;
margin-bottom: 20px;
color: #00f5d4;
background: rgba(0, 245, 212, 0.06);
border: 1px solid rgba(0, 245, 212, 0.12);
}
.bp-desc {
font-family: "Lato", sans-serif;
font-size: 17px;
line-height: 1.6;
color: #8aa8c0;
opacity: 0.55;
}
/* GL scenes (hidden, just for texture capture) */
.scene {
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.scene-label {
font-family: "Bebas Neue", sans-serif;
font-size: 140px;
letter-spacing: 0.06em;
opacity: 0.12;
}
</style>
<div class="bp-grid"></div>
<div class="bp-divider"></div>
<div class="bp-number">01 / 14</div>
<!-- GL demo scenes (captured as textures, then hidden) -->
<div id="s1" class="scene" style="background: #0d1b2a">
<div class="scene-label" style="color: #00f5d4">SCENE A</div>
</div>
<div id="s2" class="scene" style="background: #00f5d4; opacity: 0">
<div class="scene-label" style="color: #0d1b2a">SCENE B</div>
</div>
<!-- GL canvas (left panel only) -->
<canvas
id="gl-canvas"
width="1200"
height="1080"
style="
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
z-index: 10;
pointer-events: none;
display: none;
"
>
</canvas>
<!-- Right panel metadata -->
<div class="bp-right">
<div class="bp-name">Domain Warp Dissolve</div>
<div class="bp-plabel">Prompt</div>
<div class="bp-prompt">"use domain warp dissolve shader transition"</div>
<div class="bp-desc">
Cascaded fbm(p + fbm(p)) displaces both scenes along a warp field. Iridescent
cosine-palette edge glow.
</div>
</div>
<div
id="driver"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
window.__timelines = window.__timelines || {};
var glCanvas = document.getElementById("gl-canvas");
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
if (!gl) {
console.warn("WebGL not available");
window.__timelines["main"] = gsap.timeline({ paused: true });
} else {
gl.viewport(0, 0, 1200, 1080);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
var sceneTextures = {};
function captureScene(sceneId) {
var scene = document.getElementById(sceneId);
var origOpacity = scene.style.opacity;
var origZ = scene.style.zIndex;
scene.style.opacity = "1";
scene.style.zIndex = "999";
scene.offsetHeight;
var c = document.createElement("canvas");
c.width = 1200;
c.height = 1080;
var ctx = c.getContext("2d");
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
ctx.fillRect(0, 0, 1200, 1080);
var sr = scene.getBoundingClientRect();
var els = scene.querySelectorAll("*");
for (var i = 0; i < els.length; i++) {
var el = els[i],
cs = window.getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden") continue;
var r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) continue;
var x = r.left - sr.left,
y = r.top - sr.top,
w = r.width,
h = r.height;
ctx.save();
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
var bg = cs.backgroundColor;
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
ctx.fillStyle = bg;
ctx.fillRect(x, y, w, h);
}
var hasChildEls = el.querySelector("div,span,img,video");
var text = "";
for (var j = 0; j < el.childNodes.length; j++)
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
text = text.trim();
if (text && !hasChildEls) {
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
ctx.fillStyle = cs.color;
if (cs.letterSpacing && cs.letterSpacing !== "normal")
ctx.letterSpacing = cs.letterSpacing;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, x + w / 2, y + h / 2);
}
ctx.restore();
}
scene.style.opacity = origOpacity;
scene.style.zIndex = origZ;
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
sceneTextures[sceneId] = tex;
}
var vertSrc =
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
var quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
gl.STATIC_DRAW,
);
function compileShader(src, type) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
console.error("Shader:", gl.getShaderInfoLog(s));
return s;
}
function mkProg(fragSrc) {
var p = gl.createProgram();
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
console.error("Link:", gl.getProgramInfoLog(p));
return p;
}
var H =
"precision mediump float;" +
"varying vec2 v_uv;" +
"uniform sampler2D u_from, u_to;" +
"uniform float u_progress;" +
"uniform vec2 u_resolution;\n";
var NQ =
"float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}" +
"float vnoise(vec2 p){vec2 i=floor(p),f=fract(p);" +
"f=f*f*f*(f*(f*6.-15.)+10.);" +
"return mix(mix(hash(i),hash(i+vec2(1,0)),f.x)," +
"mix(hash(i+vec2(0,1)),hash(i+vec2(1,1)),f.x),f.y);}" +
"float fbm(vec2 p){float v=0.,a=.5;" +
"mat2 R=mat2(.8,.6,-.6,.8);" +
"for(int i=0;i<5;i++){v+=a*vnoise(p);p=R*p*2.02;a*=.5;}return v;}";
var CP =
"vec3 palette(float t,vec3 a,vec3 b,vec3 c,vec3 d){" + "return a+b*cos(6.2832*(c*t+d));}";
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
var progTrans = mkProg(
H +
NQ +
CP +
"void main(){vec2 q=vec2(fbm(v_uv*3.),fbm(v_uv*3.+vec2(5.2,1.3)));vec2 r=vec2(fbm(v_uv*3.+q*4.+vec2(1.7,9.2)),fbm(v_uv*3.+q*4.+vec2(8.3,2.8)));float n=fbm(v_uv*3.+r*2.);vec2 warpDir=(q-.5)*.4;vec4 A=texture2D(u_from,clamp(v_uv+warpDir*u_progress,0.,1.));vec4 B=texture2D(u_to,clamp(v_uv-warpDir*(1.-u_progress),0.,1.));float e=smoothstep(u_progress-.08,u_progress+.08,n);float ed=abs(n-u_progress);float em=smoothstep(.1,0.,ed)*(1.-step(1.,u_progress));vec3 ec=palette(ed*8.,vec3(.5),vec3(.5),vec3(1.),vec3(0.,.33,.67));gl_FragColor=vec4(mix(B,A,e).rgb+ec*em*2.,1.);}",
);
function renderShader(prog, texFrom, texTo, progress) {
gl.useProgram(prog);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texFrom);
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texTo);
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
var pos = gl.getAttribLocation(prog, "a_pos");
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function easeInOut(p) {
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
}
captureScene("s1");
captureScene("s2");
glCanvas.style.display = "block";
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
document.querySelectorAll(".scene").forEach(function (s) {
s.style.opacity = "0";
});
var tl = gsap.timeline({
paused: true,
onUpdate: function () {
var t = tl.time();
if (t >= 1.0 && t < 3.0) {
renderShader(
progTrans,
sceneTextures["s1"],
sceneTextures["s2"],
easeInOut((t - 1.0) / 2.0),
);
} else if (t >= 3.0) {
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
} else {
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
}
},
});
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
window.__timelines["main"] = tl;
} // end if (gl)
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "domain-warp-dissolve",
"type": "hyperframes:block",
"title": "Domain Warp Dissolve",
"description": "Shader transition with fractal noise domain warping",
"tags": ["transition", "shader"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "domain-warp-dissolve.html",
"target": "compositions/domain-warp-dissolve.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,366 @@
<!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>
@import url("https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Bebas+Neue&family=JetBrains+Mono:wght@400;700&family=Lato:wght@400;700&display=block");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
overflow: hidden;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="4"
data-width="1920"
data-height="1080"
>
<style>
[data-composition-id="main"] {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
background: #03071e;
}
/* Blueprint grid */
.bp-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px);
background-size: 40px 40px;
pointer-events: none;
}
/* Layout */
.bp-left {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 1200px;
display: flex;
align-items: center;
justify-content: center;
}
.bp-right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 720px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 60px 60px 60px 40px;
}
.bp-divider {
position: absolute;
left: 1200px;
top: 60px;
bottom: 60px;
width: 1px;
background: #ffba08;
opacity: 0.15;
}
.bp-number {
font-family: "Space Mono", monospace;
font-size: 14px;
font-weight: 700;
letter-spacing: 0.4em;
text-transform: uppercase;
position: absolute;
top: 40px;
left: 60px;
color: #ffba08;
}
/* Right panel typography */
.bp-name {
font-family: "Bebas Neue", sans-serif;
font-size: 38px;
letter-spacing: 0.08em;
margin-bottom: 20px;
color: #ffba08;
}
.bp-plabel {
font-family: "Space Mono", monospace;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.3em;
text-transform: uppercase;
margin-bottom: 10px;
color: #ffba08;
opacity: 0.5;
}
.bp-prompt {
font-family: "JetBrains Mono", monospace;
font-size: 20px;
line-height: 1.6;
padding: 16px 20px;
border-radius: 6px;
margin-bottom: 20px;
color: #ffba08;
background: rgba(255, 186, 8, 0.06);
border: 1px solid rgba(255, 186, 8, 0.12);
}
.bp-desc {
font-family: "Lato", sans-serif;
font-size: 17px;
line-height: 1.6;
color: #888;
opacity: 0.55;
}
/* GL scenes (hidden, just for texture capture) */
.scene {
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.scene-label {
font-family: "Bebas Neue", sans-serif;
font-size: 140px;
letter-spacing: 0.06em;
opacity: 0.12;
}
</style>
<div class="bp-grid"></div>
<div class="bp-divider"></div>
<div class="bp-number">12 / 14</div>
<!-- GL demo scenes (captured as textures, then hidden) -->
<div id="s1" class="scene" style="background: #03071e">
<div class="scene-label" style="color: #ffba08">SCENE A</div>
</div>
<div id="s2" class="scene" style="background: #ffba08; opacity: 0">
<div class="scene-label" style="color: #03071e">SCENE B</div>
</div>
<!-- GL canvas (left panel only) -->
<canvas
id="gl-canvas"
width="1200"
height="1080"
style="
position: absolute;
top: 0;
left: 0;
width: 1200px;
height: 1080px;
z-index: 10;
pointer-events: none;
display: none;
"
>
</canvas>
<!-- Right panel metadata -->
<div class="bp-right">
<div class="bp-name">Flash Through White</div>
<div class="bp-plabel">Prompt</div>
<div class="bp-prompt">"use flash through white shader transition"</div>
<div class="bp-desc">
Both scenes brighten to a white midpoint. Works on dark backgrounds where
color-dip-to-black is invisible.
</div>
</div>
<div
id="driver"
class="clip"
data-start="0"
data-duration="4"
data-track-index="0"
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
></div>
</div>
<script>
window.__timelines = window.__timelines || {};
var glCanvas = document.getElementById("gl-canvas");
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
if (!gl) {
console.warn("WebGL not available");
window.__timelines["main"] = gsap.timeline({ paused: true });
} else {
gl.viewport(0, 0, 1200, 1080);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
var sceneTextures = {};
function captureScene(sceneId) {
var scene = document.getElementById(sceneId);
var origOpacity = scene.style.opacity;
var origZ = scene.style.zIndex;
scene.style.opacity = "1";
scene.style.zIndex = "999";
scene.offsetHeight;
var c = document.createElement("canvas");
c.width = 1200;
c.height = 1080;
var ctx = c.getContext("2d");
ctx.fillStyle = window.getComputedStyle(scene).backgroundColor;
ctx.fillRect(0, 0, 1200, 1080);
var sr = scene.getBoundingClientRect();
var els = scene.querySelectorAll("*");
for (var i = 0; i < els.length; i++) {
var el = els[i],
cs = window.getComputedStyle(el);
if (cs.display === "none" || cs.visibility === "hidden") continue;
var r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) continue;
var x = r.left - sr.left,
y = r.top - sr.top,
w = r.width,
h = r.height;
ctx.save();
ctx.globalAlpha = parseFloat(cs.opacity) || 1;
var bg = cs.backgroundColor;
if (bg && bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent") {
ctx.fillStyle = bg;
ctx.fillRect(x, y, w, h);
}
var hasChildEls = el.querySelector("div,span,img,video");
var text = "";
for (var j = 0; j < el.childNodes.length; j++)
if (el.childNodes[j].nodeType === 3) text += el.childNodes[j].textContent;
text = text.trim();
if (text && !hasChildEls) {
ctx.font = cs.fontWeight + " " + cs.fontSize + " " + cs.fontFamily;
ctx.fillStyle = cs.color;
if (cs.letterSpacing && cs.letterSpacing !== "normal")
ctx.letterSpacing = cs.letterSpacing;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, x + w / 2, y + h / 2);
}
ctx.restore();
}
scene.style.opacity = origOpacity;
scene.style.zIndex = origZ;
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
sceneTextures[sceneId] = tex;
}
var vertSrc =
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
var quadBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
gl.STATIC_DRAW,
);
function compileShader(src, type) {
var s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
console.error("Shader:", gl.getShaderInfoLog(s));
return s;
}
function mkProg(fragSrc) {
var p = gl.createProgram();
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS))
console.error("Link:", gl.getProgramInfoLog(p));
return p;
}
var H =
"precision mediump float;" +
"varying vec2 v_uv;" +
"uniform sampler2D u_from, u_to;" +
"uniform float u_progress;" +
"uniform vec2 u_resolution;\n";
var progPass = mkProg(H + "void main(){gl_FragColor=texture2D(u_from,v_uv);}");
var progTrans = mkProg(
H +
"void main(){vec4 A=texture2D(u_from,v_uv),B=texture2D(u_to,v_uv);float toWhite=smoothstep(0.,.45,u_progress);vec3 fromC=mix(A.rgb,vec3(1.),toWhite);float fromWhite=1.-smoothstep(.5,1.,u_progress);vec3 toC=mix(B.rgb,vec3(1.),fromWhite);gl_FragColor=vec4(mix(fromC,toC,smoothstep(.35,.65,u_progress)),1.);}",
);
function renderShader(prog, texFrom, texTo, progress) {
gl.useProgram(prog);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texFrom);
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texTo);
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1200, 1080);
var pos = gl.getAttribLocation(prog, "a_pos");
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function easeInOut(p) {
return p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2;
}
captureScene("s1");
captureScene("s2");
glCanvas.style.display = "block";
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
document.querySelectorAll(".scene").forEach(function (s) {
s.style.opacity = "0";
});
var tl = gsap.timeline({
paused: true,
onUpdate: function () {
var t = tl.time();
if (t >= 1.0 && t < 3.0) {
renderShader(
progTrans,
sceneTextures["s1"],
sceneTextures["s2"],
easeInOut((t - 1.0) / 2.0),
);
} else if (t >= 3.0) {
renderShader(progPass, sceneTextures["s2"], sceneTextures["s2"], 0);
} else {
renderShader(progPass, sceneTextures["s1"], sceneTextures["s1"], 0);
}
},
});
tl.to({ v: 0 }, { v: 1, duration: 4, ease: "none" }, 0);
window.__timelines["main"] = tl;
} // end if (gl)
</script>
</body>
</html>
@@ -0,0 +1,24 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "flash-through-white",
"type": "hyperframes:block",
"title": "Flash Through White",
"description": "Shader transition with white flash crossfade",
"tags": ["transition", "shader"],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 4,
"files": [
{
"path": "flash-through-white.html",
"target": "compositions/flash-through-white.html",
"type": "hyperframes:composition"
}
],
"preview": {
"video": "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"
}
}
@@ -0,0 +1,467 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1440, height=2560" />
<title>Flowchart Vertical</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=block"
rel="stylesheet"
/>
<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 {
margin: 0;
width: 1440px;
height: 2560px;
overflow: hidden;
background-color: #ffffff;
}
</style>
</head>
<body>
<div
id="flowchart-vertical"
data-composition-id="flowchart-vertical"
data-width="1440"
data-height="2560"
data-start="0"
data-duration="12"
>
<div class="canvas">
<svg class="connectors" width="1440" height="2560" viewBox="0 0 1440 2560">
<!-- Level 1 to 2 -->
<path
id="path-1-L"
class="connector"
d="M 720 210 L 720 360 L 440 360 L 440 530"
fill="none"
stroke="#333"
stroke-width="4"
/>
<path
id="path-1-R"
class="connector"
d="M 720 210 L 720 360 L 1000 360 L 1000 530"
fill="none"
stroke="#333"
stroke-width="4"
/>
<!-- Level 2 to 3 (Left side) -->
<path
id="path-2-LL"
class="connector"
d="M 440 590 L 440 760 L 280 760 L 280 930"
fill="none"
stroke="#333"
stroke-width="4"
/>
<path
id="path-2-LR"
class="connector"
d="M 440 590 L 440 760 L 600 760 L 600 930"
fill="none"
stroke="#333"
stroke-width="4"
/>
<!-- Level 2 to 3 (Right side) -->
<path
id="path-2-RL"
class="connector"
d="M 1000 590 L 1000 760 L 840 760 L 840 930"
fill="none"
stroke="#333"
stroke-width="4"
/>
<path
id="path-2-RR"
class="connector"
d="M 1000 590 L 1000 760 L 1160 760 L 1160 930"
fill="none"
stroke="#333"
stroke-width="4"
/>
</svg>
<div id="label-yes" class="connector-label">Yes</div>
<div id="label-not-sure" class="connector-label">Not sure</div>
<!-- Level 1 -->
<div id="node-root" class="node yellow" style="left: 720px; top: 180px">
Should I learn to code?
</div>
<!-- Level 2 -->
<div id="node-yes" class="node green" style="left: 440px; top: 560px">Yes</div>
<div id="node-not-sure" class="node peach" style="left: 1000px; top: 560px">Not sure</div>
<!-- Level 3 -->
<div id="node-python" class="node lavender" style="left: 280px; top: 960px">
<div style="position: relative; display: inline-block">
<span id="python-text">Start with Pythom</span>
<svg class="squiggle-container" width="64" height="6" viewBox="0 0 64 6">
<path
id="squiggle"
d="M 0 3 Q 2 0 4 3 T 8 3 T 12 3 T 16 3 T 20 3 T 24 3 T 28 3 T 32 3 T 36 3 T 40 3 T 44 3 T 48 3 T 52 3 T 56 3 T 60 3 T 64 3"
fill="none"
stroke="#E53935"
stroke-width="2"
/>
</svg>
</div>
</div>
<div id="node-nocode" class="node blue" style="left: 600px; top: 960px">
Try no-code first
</div>
<div id="node-website" class="node pink" style="left: 840px; top: 960px">
Build a personal website
</div>
<div id="node-course" class="node yellow" style="left: 1160px; top: 960px">
Take a free intro course
</div>
<!-- Cursor -->
<div id="cursor" class="cursor-container">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z"
fill="white"
stroke="black"
/>
</svg>
<div class="cursor-tag">You</div>
</div>
<!-- Emoji -->
<div id="emoji-thumb" class="emoji">👍</div>
<!-- Overlay -->
<div id="fade-overlay"></div>
</div>
<style>
#flowchart-vertical {
width: 1440px;
height: 2560px;
background-color: #ffffff;
background-image: radial-gradient(#e5e5e5 1px, transparent 1px);
background-size: 20px 20px;
position: absolute;
overflow: hidden;
font-family: "Inter", sans-serif;
}
#flowchart-vertical .canvas {
width: 100%;
height: 100%;
position: absolute;
transform: none;
transform-origin: 720px 640px;
}
#flowchart-vertical .node {
position: absolute;
transform: translate(-50%, -50%) scale(0);
padding: 16px 24px;
border-radius: 12px;
font-size: 18px;
font-weight: 500;
color: #333;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
white-space: nowrap;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
}
#flowchart-vertical .node.yellow {
background-color: #e8d44d;
}
#flowchart-vertical .node.green {
background-color: #c2e8a0;
}
#flowchart-vertical .node.peach {
background-color: #f5c5a3;
}
#flowchart-vertical .node.lavender {
background-color: #d4c5f9;
}
#flowchart-vertical .node.blue {
background-color: #a8d8f0;
}
#flowchart-vertical .node.pink {
background-color: #f8b4c8;
}
#flowchart-vertical .connectors {
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
}
#flowchart-vertical .connector {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
}
#flowchart-vertical .connector-label {
position: absolute;
font-size: 14px;
font-weight: 600;
color: #333;
background: white;
padding: 2px 6px;
border-radius: 4px;
opacity: 0;
z-index: 6;
transform: translate(-50%, -50%);
}
#flowchart-vertical #label-yes {
left: 580px;
top: 420px;
}
#flowchart-vertical #label-not-sure {
left: 860px;
top: 420px;
}
#flowchart-vertical .cursor-container {
position: absolute;
left: 1440px;
top: 2560px;
z-index: 100;
pointer-events: none;
display: flex;
align-items: flex-start;
}
#flowchart-vertical .cursor-tag {
background-color: #9747ff;
color: white;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
margin-left: 4px;
margin-top: 12px;
}
#flowchart-vertical .squiggle-container {
position: absolute;
right: 0;
bottom: -4px;
opacity: 0;
}
#flowchart-vertical .emoji {
position: absolute;
font-size: 32px;
left: 390px;
top: 960px;
transform: translate(-50%, -50%) scale(0);
z-index: 20;
}
#flowchart-vertical #fade-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: white;
opacity: 0;
z-index: 1000;
pointer-events: none;
}
#flowchart-vertical .selection-border {
position: absolute;
top: -4px;
left: -4px;
right: -4px;
bottom: -4px;
border: 2px solid #0b84f3;
border-radius: 16px;
pointer-events: none;
opacity: 0;
}
#flowchart-vertical .text-highlight {
background-color: #d0e4ff;
}
</style>
<script>
(function () {
const tl = gsap.timeline({ paused: true });
const S = "#flowchart-vertical";
const nodePython = document.querySelector(S + " #node-python");
const pythonText = document.querySelector(S + " #python-text");
// 1. Root node scales in
tl.to(S + " #node-root", { scale: 1, duration: 0.4, ease: "power2.out" });
// 2. Hold
tl.addLabel("hold1", "+=0.6");
// 3. Connectors draw
tl.to(
S + " .connector#path-1-L, " + S + " .connector#path-1-R",
{ strokeDashoffset: 0, duration: 0.5, ease: "none" },
"hold1",
);
tl.to(
S + " #label-yes, " + S + " #label-not-sure",
{ opacity: 1, duration: 0.2 },
"hold1+=0.25",
);
// 4. Level 2 nodes
tl.to(S + " #node-yes", { scale: 1, duration: 0.4, ease: "back.out(1.7)" }, "hold1+=0.4");
tl.to(
S + " #node-not-sure",
{ scale: 1, duration: 0.4, ease: "back.out(1.7)" },
"hold1+=0.6",
);
// 5. Hold
tl.addLabel("hold2", "+=0.5");
// 6. Level 2→3 connectors
tl.to(
S +
" .connector#path-2-LL, " +
S +
" .connector#path-2-LR, " +
S +
" .connector#path-2-RL, " +
S +
" .connector#path-2-RR",
{ strokeDashoffset: 0, duration: 0.4, ease: "none" },
"hold2",
);
// 7. Leaf nodes
const leafNodes = [
S + " #node-python",
S + " #node-nocode",
S + " #node-website",
S + " #node-course",
];
leafNodes.forEach((id, i) => {
tl.to(
id,
{ scale: 1, duration: 0.4, ease: "back.out(1.7)" },
`hold2+=${0.3 + i * 0.15}`,
);
});
tl.to(S + " .squiggle-container", { opacity: 1, duration: 0.1 }, "hold2+=0.3");
// 8. Hold
tl.addLabel("hold3", "+=0.8");
// 9. Cursor drifts in
tl.to(S + " #cursor", { x: -1110, y: -1560, duration: 1, ease: "power1.inOut" }, "hold3");
// 10. Cursor clicks — selection border
tl.add(() => {
if (!nodePython) return;
if (!nodePython.querySelector(".selection-border")) {
const border = document.createElement("div");
border.className = "selection-border";
nodePython.appendChild(border);
}
gsap.set(S + " .selection-border", { opacity: 1 });
}, "hold3+=1");
tl.to(
S + " #cursor",
{ scale: 0.8, duration: 0.05, yoyo: true, repeat: 1, overwrite: "auto" },
"hold3+=1",
);
// 11. Hold
tl.addLabel("hold4", "+=0.3");
// 12. Double-click to highlight "Pythom"
tl.to(
S + " #cursor",
{ scale: 0.8, duration: 0.05, yoyo: true, repeat: 3, overwrite: "auto" },
"hold4",
);
tl.add(() => {
if (!pythonText) return;
pythonText.innerHTML = 'Start with <span class="text-highlight">Pythom</span>';
}, "hold4+=0.1");
// 13. Hold
tl.addLabel("hold5", "+=0.2");
// 14. Type correction: "Pythom" → "Python"
const typingStart = tl.labels["hold5"];
const words = ["P", "Py", "Pyt", "Pyth", "Pytho", "Python"];
words.forEach((word, i) => {
tl.add(
() => {
if (pythonText)
pythonText.innerHTML = `Start with <span class="text-highlight">${word}</span>`;
},
typingStart + i * 0.05,
);
});
const typingEnd = typingStart + words.length * 0.05;
tl.add(() => {
if (pythonText) pythonText.innerHTML = "Start with Python";
gsap.set(S + " .squiggle-container", { opacity: 0 });
}, typingEnd);
// 15. Hold
tl.addLabel("hold6", typingEnd + 0.5);
// 16. Cursor clicks away to deselect
tl.to(S + " #cursor", { x: -1050, y: -1520, duration: 0.3, overwrite: "auto" }, "hold6");
tl.to(
S + " #cursor",
{ scale: 0.8, duration: 0.05, yoyo: true, repeat: 1, overwrite: "auto" },
"hold6+=0.3",
);
tl.to(S + " .selection-border", { opacity: 0, duration: 0.1 }, "hold6+=0.3");
// 17. Emoji pop
tl.to(
S + " #emoji-thumb",
{ scale: 1, duration: 0.15, ease: "back.out(2)" },
"hold6+=0.4",
);
// 18. Hold
tl.addLabel("hold7", "+=2");
// 19. Fade out
tl.to(S + " #fade-overlay", { opacity: 1, duration: 0.5 }, "hold7");
window.__timelines = window.__timelines || {};
window.__timelines["flowchart-vertical"] = tl;
})();
</script>
</div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More