Files
heygen-com--hyperframes/registry/examples/motion-blur/index.html
T
wehub-resource-sync 85453da49f
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docs / Validate docs (push) Has been cancelled
Sync skills to ClawHub / Publish changed skills (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:58:35 +08:00

573 lines
20 KiB
HTML
Vendored

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Motion Blur — Velocity Showcase</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 {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #06060a;
}
#comp {
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
font-family: "SF Mono", ui-monospace, monospace;
background: #06060a;
}
.header {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 80px;
display: flex;
align-items: flex-end;
padding: 0 72px 20px;
border-bottom: 1px solid #0f0f18;
}
.header-title {
font-size: 11px;
letter-spacing: 0.4em;
text-transform: uppercase;
color: #1e1e2a;
}
.header-sub {
margin-left: auto;
font-size: 11px;
letter-spacing: 0.25em;
text-transform: uppercase;
color: #14141c;
}
/* Each group = one speed level, containing a shape row + text row */
.group {
position: absolute;
left: 0;
right: 0;
height: 184px; /* 72 + 16 + 72 + 24 bottom */
}
/* Group bottom separator */
.group::after {
content: "";
position: absolute;
bottom: 0;
left: 72px;
right: 72px;
height: 1px;
background: #0d0d15;
}
/* Duration label — left, spanning both rows */
.dur {
position: absolute;
left: 72px;
top: 0;
width: 90px;
height: 160px; /* 72+16+72 */
display: flex;
flex-direction: column;
justify-content: center;
}
.dur-num {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.04em;
color: #fff;
line-height: 1;
}
.dur-unit {
font-size: 9px;
letter-spacing: 0.25em;
text-transform: uppercase;
color: #252532;
margin-top: 5px;
}
/* Row-type hint ("shape" / "text") — right of dur label */
.row-hint {
position: absolute;
left: 176px;
width: 44px;
height: 72px;
display: flex;
align-items: center;
font-size: 8px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: #161620;
}
/* Speed label — right, spanning both rows */
.spd {
position: absolute;
right: 72px;
top: 0;
width: 100px;
height: 160px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-end;
}
.spd-label {
font-size: 10px;
letter-spacing: 0.3em;
text-transform: uppercase;
color: #181822;
}
/* Animated elements — both types live at left:0, GSAP drives x */
.pill {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 72px;
border-radius: 36px;
will-change: transform, filter;
}
.word {
position: absolute;
left: 0;
top: 88px; /* 72 + 16 gap */
height: 72px;
line-height: 72px;
white-space: nowrap;
font-size: 56px;
font-weight: 800;
letter-spacing: -0.03em;
will-change: transform, filter;
}
/* Inner divider between shape row and text row */
.inner-div {
position: absolute;
left: 220px;
right: 200px;
top: 80px; /* 72 + 8 */
height: 1px;
background: #0a0a12;
}
/* Track guide lines */
.track-a,
.track-b {
position: absolute;
left: 220px;
right: 200px;
height: 1px;
background: #0c0c14;
}
.track-a {
top: 35px;
} /* center of shape row */
.track-b {
top: 123px;
} /* 88 + 35 = center of text row */
</style>
</head>
<body>
<div
id="comp"
data-composition-id="motion-blur-example"
data-width="1920"
data-height="1080"
data-start="0"
data-duration="4"
>
<div class="header" data-layout-ignore>
<span class="header-title">Motion Blur — Velocity Showcase</span>
<span class="header-sub">feGaussianBlur + scaleX · blur ∝ velocity</span>
</div>
<!-- Group 1: 3.0s slow — top: 80 -->
<div class="group" style="top: 80px">
<div class="dur" data-layout-ignore>
<span class="dur-num">3.0</span><span class="dur-unit">seconds</span>
</div>
<div class="row-hint" data-layout-ignore style="top: 0">shape</div>
<div class="row-hint" data-layout-ignore style="top: 88px">text</div>
<div class="track-a"></div>
<div class="inner-div"></div>
<div class="track-b"></div>
<div
class="pill"
id="s1"
style="
background: linear-gradient(135deg, #60a5fa, #2563eb);
box-shadow: 0 0 32px rgba(96, 165, 250, 0.18);
"
></div>
<div
class="word"
id="t1"
style="color: #3b82f6; text-shadow: 0 0 40px rgba(96, 165, 250, 0.3)"
>
DRIFT
</div>
<div class="spd" data-layout-ignore><span class="spd-label">slow</span></div>
</div>
<!-- Group 2: 1.5s medium — top: 264 -->
<div class="group" style="top: 264px">
<div class="dur" data-layout-ignore>
<span class="dur-num">1.5</span><span class="dur-unit">seconds</span>
</div>
<div class="row-hint" data-layout-ignore style="top: 0">shape</div>
<div class="row-hint" data-layout-ignore style="top: 88px">text</div>
<div class="track-a"></div>
<div class="inner-div"></div>
<div class="track-b"></div>
<div
class="pill"
id="s2"
style="
background: linear-gradient(135deg, #34d399, #059669);
box-shadow: 0 0 32px rgba(52, 211, 153, 0.18);
"
></div>
<div
class="word"
id="t2"
style="color: #10b981; text-shadow: 0 0 40px rgba(52, 211, 153, 0.3)"
>
GLIDE
</div>
<div class="spd" data-layout-ignore><span class="spd-label">medium</span></div>
</div>
<!-- Group 3: 0.7s fast — top: 448 -->
<div class="group" style="top: 448px">
<div class="dur" data-layout-ignore>
<span class="dur-num">0.7</span><span class="dur-unit">seconds</span>
</div>
<div class="row-hint" data-layout-ignore style="top: 0">shape</div>
<div class="row-hint" data-layout-ignore style="top: 88px">text</div>
<div class="track-a"></div>
<div class="inner-div"></div>
<div class="track-b"></div>
<div
class="pill"
id="s3"
style="
background: linear-gradient(135deg, #c084fc, #7c3aed);
box-shadow: 0 0 32px rgba(192, 132, 252, 0.18);
"
></div>
<div
class="word"
id="t3"
style="color: #a855f7; text-shadow: 0 0 40px rgba(192, 132, 252, 0.3)"
>
RUSH
</div>
<div class="spd" data-layout-ignore><span class="spd-label">fast</span></div>
</div>
<!-- Group 4: 0.35s faster — top: 632 -->
<div class="group" style="top: 632px">
<div class="dur" data-layout-ignore>
<span class="dur-num">0.35</span><span class="dur-unit">seconds</span>
</div>
<div class="row-hint" data-layout-ignore style="top: 0">shape</div>
<div class="row-hint" data-layout-ignore style="top: 88px">text</div>
<div class="track-a"></div>
<div class="inner-div"></div>
<div class="track-b"></div>
<div
class="pill"
id="s4"
style="
background: linear-gradient(135deg, #fb923c, #ea580c);
box-shadow: 0 0 32px rgba(251, 146, 60, 0.18);
"
></div>
<div
class="word"
id="t4"
style="color: #f97316; text-shadow: 0 0 40px rgba(251, 146, 60, 0.3)"
>
BLAST
</div>
<div class="spd" data-layout-ignore><span class="spd-label">faster</span></div>
</div>
<!-- Group 5: 0.2s extreme — top: 816 -->
<div class="group" style="top: 816px">
<div class="dur" data-layout-ignore>
<span class="dur-num">0.2</span><span class="dur-unit">seconds</span>
</div>
<div class="row-hint" data-layout-ignore style="top: 0">shape</div>
<div class="row-hint" data-layout-ignore style="top: 88px">text</div>
<div class="track-a"></div>
<div class="inner-div"></div>
<div class="track-b"></div>
<div
class="pill"
id="s5"
style="
background: linear-gradient(135deg, #f87171, #dc2626);
box-shadow: 0 0 32px rgba(248, 113, 113, 0.18);
"
></div>
<div
class="word"
id="t5"
style="color: #ef4444; text-shadow: 0 0 40px rgba(248, 113, 113, 0.3)"
>
WARP
</div>
<div class="spd" data-layout-ignore><span class="spd-label">extreme</span></div>
</div>
<script>
(function () {
/* ── attachMotionBlur ─────────────────────────────────────── */
if (!window._hfMbUid) window._hfMbUid = 0;
var ns = "http://www.w3.org/2000/svg";
function attachMotionBlur(selector, tl, opts) {
opts = opts || {};
var blurScale = opts.blurScale !== undefined ? opts.blurScale : 0.008;
var blurMax = opts.blurMax !== undefined ? opts.blurMax : 20;
var stretchScale = opts.stretchScale !== undefined ? opts.stretchScale : 0.0002;
var stretchMax = opts.stretchMax !== undefined ? opts.stretchMax : 0;
var axis = opts.axis || "both";
var items = Array.isArray(selector) ? selector : [selector];
var targets = items.reduce(function (acc, s) {
if (typeof s === "string") {
document.querySelectorAll(s).forEach(function (el) {
acc.push(el);
});
} else if (s instanceof Element) {
acc.push(s);
}
return acc;
}, []);
// Ghost trail: copies placed only behind the element → inherently one-sided.
// Top layer: small Gaussian at current position so element looks blurry, not sharp.
var GHOST_CFG = [
{ frac: 0.25, slope: 0.55 },
{ frac: 0.55, slope: 0.28 },
{ frac: 1.0, slope: 0.1 },
];
var state = targets.map(function (el) {
var uid = "hf-mb-" + window._hfMbUid++;
var svg = document.createElementNS(ns, "svg");
svg.setAttribute("style", "position:absolute;width:0;height:0;overflow:hidden;");
var filter = document.createElementNS(ns, "filter");
filter.id = uid;
filter.setAttribute("x", "-110%");
filter.setAttribute("y", "-25%");
filter.setAttribute("width", "260%");
filter.setAttribute("height", "150%");
var ghosts = GHOST_CFG.map(function (cfg, gi) {
var feOff = document.createElementNS(ns, "feOffset");
feOff.setAttribute("in", "SourceGraphic");
feOff.setAttribute("dx", "0");
feOff.setAttribute("dy", "0");
feOff.setAttribute("result", "go" + gi);
var feGB = document.createElementNS(ns, "feGaussianBlur");
feGB.setAttribute("in", "go" + gi);
feGB.setAttribute("stdDeviation", "0 0");
feGB.setAttribute("result", "gb" + gi);
var feCT = document.createElementNS(ns, "feComponentTransfer");
feCT.setAttribute("in", "gb" + gi);
feCT.setAttribute("result", "gf" + gi);
var feFuncA = document.createElementNS(ns, "feFuncA");
feFuncA.setAttribute("type", "linear");
feFuncA.setAttribute("slope", String(cfg.slope));
feCT.appendChild(feFuncA);
filter.appendChild(feOff);
filter.appendChild(feGB);
filter.appendChild(feCT);
return { feOff: feOff, feGB: feGB, frac: cfg.frac };
});
var feTopBlur = document.createElementNS(ns, "feGaussianBlur");
feTopBlur.setAttribute("in", "SourceGraphic");
feTopBlur.setAttribute("stdDeviation", "0 0");
feTopBlur.setAttribute("result", "top");
filter.appendChild(feTopBlur);
var feMerge = document.createElementNS(ns, "feMerge");
for (var mi = GHOST_CFG.length - 1; mi >= 0; mi--) {
var mn = document.createElementNS(ns, "feMergeNode");
mn.setAttribute("in", "gf" + mi);
feMerge.appendChild(mn);
}
var mnTop = document.createElementNS(ns, "feMergeNode");
mnTop.setAttribute("in", "top");
feMerge.appendChild(mnTop);
filter.appendChild(feMerge);
svg.appendChild(filter);
document.body.appendChild(svg);
return {
el: el,
ghosts: ghosts,
feTopBlur: feTopBlur,
filterId: uid,
prevX: parseFloat(gsap.getProperty(el, "x")) || 0,
prevY: parseFloat(gsap.getProperty(el, "y")) || 0,
prevTime: tl.time(),
};
});
// tl.eventCallback("onUpdate") is not available in the HyperFrames renderer —
// the runtime proxies the timeline. Tween onUpdate fires on every seek instead.
var _proxy = { t: 0 };
tl.to(
_proxy,
{
t: 1,
duration: Math.max(tl.duration(), 0.1),
ease: "none",
onUpdate: function () {
var time = tl.time();
state.forEach(function (s) {
var x = parseFloat(gsap.getProperty(s.el, "x")) || 0;
var y = parseFloat(gsap.getProperty(s.el, "y")) || 0;
var dt = time - s.prevTime;
if (dt > 0.0005) {
var vx = axis !== "y" ? (x - s.prevX) / dt : 0;
var vy = axis !== "x" ? (y - s.prevY) / dt : 0;
var bx = Math.min(Math.abs(vx) * blurScale, blurMax);
var by = Math.min(Math.abs(vy) * blurScale, blurMax);
var bxFinal = axis !== "y" ? bx : Math.max(by * 0.08, 0.4);
var byFinal = axis !== "x" ? by : Math.max(bx * 0.08, 0.4);
var active = bx > 0.3 || by > 0.3;
if (active) {
s.el.style.filter = "url(#" + s.filterId + ")";
s.ghosts.forEach(function (g) {
var dx =
axis !== "y" ? (vx >= 0 ? -bxFinal * g.frac : bxFinal * g.frac) : 0;
var dy =
axis !== "x" ? (vy >= 0 ? -byFinal * g.frac : byFinal * g.frac) : 0;
g.feOff.setAttribute("dx", dx.toFixed(2));
g.feOff.setAttribute("dy", dy.toFixed(2));
var gbx =
axis !== "y"
? (bxFinal * g.frac * 0.5).toFixed(2)
: Math.max(byFinal * g.frac * 0.04, 0.4).toFixed(2);
var gby =
axis !== "x"
? (byFinal * g.frac * 0.5).toFixed(2)
: Math.max(bxFinal * g.frac * 0.04, 0.4).toFixed(2);
g.feGB.setAttribute("stdDeviation", gbx + " " + gby);
});
s.feTopBlur.setAttribute(
"stdDeviation",
(bxFinal * 0.15).toFixed(2) + " " + (byFinal * 0.15).toFixed(2),
);
if (stretchMax > 0) {
var sx = 1 + Math.min(Math.abs(vx) * stretchScale, stretchMax);
var sy = 1 + Math.min(Math.abs(vy) * stretchScale, stretchMax);
var ox = axis !== "y" ? (vx >= 0 ? "100% 50%" : "0% 50%") : "50% 50%";
var oy = axis !== "x" ? (vy >= 0 ? "50% 100%" : "50% 0%") : "50% 50%";
gsap.set(s.el, {
scaleX: axis !== "y" ? sx : 1,
scaleY: axis !== "x" ? sy : 1,
transformOrigin: axis === "x" ? ox : axis === "y" ? oy : "50% 50%",
});
}
} else {
s.el.style.filter = "";
s.ghosts.forEach(function (g) {
g.feOff.setAttribute("dx", "0");
g.feOff.setAttribute("dy", "0");
g.feGB.setAttribute("stdDeviation", "0 0");
});
s.feTopBlur.setAttribute("stdDeviation", "0 0");
if (stretchMax > 0) {
gsap.set(s.el, { scaleX: 1, scaleY: 1, transformOrigin: "50% 50%" });
}
}
s.prevX = x;
s.prevY = y;
s.prevTime = time;
} else if (dt < -0.0005) {
s.el.style.filter = "";
s.ghosts.forEach(function (g) {
g.feOff.setAttribute("dx", "0");
g.feOff.setAttribute("dy", "0");
g.feGB.setAttribute("stdDeviation", "0 0");
});
s.feTopBlur.setAttribute("stdDeviation", "0 0");
if (stretchMax > 0) {
gsap.set(s.el, { scaleX: 1, scaleY: 1, transformOrigin: "50% 50%" });
}
s.prevX = x;
s.prevY = y;
s.prevTime = time;
}
// dt ≈ 0: runtime double-fires — skip.
});
},
},
0,
);
}
/* ── Timeline ─────────────────────────────────────────────── */
var tl = gsap.timeline({ paused: true });
// All elements start at x=-400 (off-screen left), travel to x=1920 (off-screen right).
// Shape + text in each group share the same duration → same velocity → same blur.
gsap.set(["#s1", "#s2", "#s3", "#s4", "#s5", "#t1", "#t2", "#t3", "#t4", "#t5"], {
x: -400,
});
tl.to(["#s1", "#t1"], { x: 1640, duration: 3.0, ease: "power3.inOut" }, 0);
tl.to(["#s2", "#t2"], { x: 1640, duration: 1.5, ease: "power3.inOut" }, 0);
tl.to(["#s3", "#t3"], { x: 1640, duration: 0.7, ease: "power3.inOut" }, 0);
tl.to(["#s4", "#t4"], { x: 1640, duration: 0.35, ease: "power3.inOut" }, 0);
tl.to(["#s5", "#t5"], { x: 1640, duration: 0.2, ease: "power3.inOut" }, 0);
tl.set(document.body, {}, 4);
attachMotionBlur(
["#s1", "#s2", "#s3", "#s4", "#s5", "#t1", "#t2", "#t3", "#t4", "#t5"],
tl,
{ axis: "x", blurMax: 80, stretchMax: 0 },
);
window.__timelines = window.__timelines || {};
window.__timelines["motion-blur-example"] = tl;
})();
</script>
</div>
</body>
</html>