mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 16:42:27 +00:00
The contributed HTML predates any oxfmt pass, so format:check failed for 42 files in both the Format and Preflight jobs. All 29 items re-rendered after formatting and verified against frames — no visual change.
157 lines
5.2 KiB
HTML
Vendored
157 lines
5.2 KiB
HTML
Vendored
<!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>
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
background: transparent;
|
|
overflow: hidden;
|
|
}
|
|
#mk-ch-root {
|
|
/* ---- mk tokens: override in the host to re-skin the family ---- */
|
|
--mk-font: "Inter", -apple-system, sans-serif;
|
|
--mk-ink: #1d1d1f;
|
|
/* faint = transient pre-sweep tier (tweens up to full ink) — distinct from the family --mk-ink-dim */
|
|
--mk-ink-faint: #bcbcc2;
|
|
--mk-ink-dark: #f5f5f7;
|
|
--mk-ink-faint-dark: rgba(245, 245, 247, 0.32);
|
|
|
|
position: relative;
|
|
width: 1920px;
|
|
height: 1080px;
|
|
overflow: hidden;
|
|
background: transparent; /* overlays footage or mk-background */
|
|
}
|
|
#mk-ch-box {
|
|
position: absolute;
|
|
font-family: var(--mk-font);
|
|
font-weight: 500;
|
|
letter-spacing: -0.015em;
|
|
}
|
|
.mk-ch-word {
|
|
display: inline;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div
|
|
id="mk-ch-root"
|
|
data-composition-id="mk-callout-highlight"
|
|
data-start="0"
|
|
data-duration="8"
|
|
data-width="1920"
|
|
data-height="1080"
|
|
>
|
|
<div id="mk-ch-box" data-layout-allow-occlusion></div>
|
|
<div
|
|
id="mk-ch-drv"
|
|
class="clip"
|
|
data-start="0"
|
|
data-duration="8"
|
|
data-track-index="0"
|
|
style="position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none"
|
|
></div>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
window.__timelines = window.__timelines || {};
|
|
|
|
/* ---- published parameters (inspector-style CONFIG) ----
|
|
The mechanic: one scalar (highlight progress 0..1) sweeps word-by-word
|
|
emphasis across the sentence — a "highlight amount"
|
|
slider. Tween the scalar over the speaker's sentence to follow speech. */
|
|
var CONFIG = {
|
|
scheme: "light", // "light" (ink on light bg) | "dark" (white on footage)
|
|
text: "Functionality was our goal from the very beginning",
|
|
fontSize: 60,
|
|
lineHeight: 1.3,
|
|
maxWidth: 700, // px; sentence wraps inside this
|
|
x: 1030, // box left edge; null = centered horizontally
|
|
y: null, // box top edge; null = centered vertically
|
|
align: "left",
|
|
sweep: { start: 1.2, end: 6.2 }, // block-local seconds, linear
|
|
animationIn: true, // fade/rise entrance before the sweep
|
|
animationOut: true,
|
|
};
|
|
|
|
var DUR = 8;
|
|
var root = document.getElementById("mk-ch-root");
|
|
var box = document.getElementById("mk-ch-box");
|
|
|
|
var FULL = CONFIG.scheme === "dark" ? "#f5f5f7" : "#1d1d1f";
|
|
var FAINT = CONFIG.scheme === "dark" ? "rgba(245,245,247,0.32)" : "#bcbcc2";
|
|
|
|
box.style.fontSize = CONFIG.fontSize + "px";
|
|
box.style.lineHeight = String(CONFIG.lineHeight);
|
|
box.style.maxWidth = CONFIG.maxWidth + "px";
|
|
box.style.textAlign = CONFIG.align;
|
|
|
|
/* build word spans */
|
|
var wordEls = [];
|
|
CONFIG.text.split(/\s+/).forEach(function (w, i) {
|
|
if (i > 0) box.appendChild(document.createTextNode(" "));
|
|
var span = document.createElement("span");
|
|
span.id = "mk-ch-w-" + i;
|
|
span.className = "mk-ch-word";
|
|
span.textContent = w;
|
|
span.style.color = FAINT;
|
|
box.appendChild(span);
|
|
wordEls.push(span);
|
|
});
|
|
|
|
/* position (measure after building) */
|
|
var rect = box.getBoundingClientRect();
|
|
box.style.left =
|
|
(CONFIG.x === null ? Math.round((1920 - rect.width) / 2) : CONFIG.x) + "px";
|
|
box.style.top =
|
|
(CONFIG.y === null ? Math.round((1080 - rect.height) / 2) : CONFIG.y) + "px";
|
|
|
|
/* state proxy: GSAP animates st.p, render derives every word color from it */
|
|
var st = { p: 0 };
|
|
var mix = gsap.utils.interpolate(FAINT, FULL);
|
|
function render() {
|
|
var k = st.p * wordEls.length;
|
|
for (var i = 0; i < wordEls.length; i++) {
|
|
var f = Math.max(0, Math.min(1, k - i));
|
|
wordEls[i].style.color = mix(f);
|
|
}
|
|
}
|
|
|
|
var tl = gsap.timeline({ paused: true });
|
|
|
|
if (CONFIG.animationIn) {
|
|
gsap.set(box, { opacity: 0, y: 24 });
|
|
tl.to(box, { opacity: 1, y: 0, duration: 0.7, ease: "power3.out" }, 0.3);
|
|
}
|
|
|
|
/* the highlight sweep — one scalar, linear so it tracks speech evenly.
|
|
To follow a real voiceover, replace with several tweens between
|
|
per-phrase progress values (keyframes on the slider). */
|
|
tl.to(
|
|
st,
|
|
{ p: 1, duration: CONFIG.sweep.end - CONFIG.sweep.start, ease: "none" },
|
|
CONFIG.sweep.start,
|
|
);
|
|
|
|
if (CONFIG.animationOut) {
|
|
tl.to(box, { opacity: 0, y: -16, duration: 0.4, ease: "power2.in" }, DUR - 0.5);
|
|
}
|
|
tl.set(root, { visibility: "hidden" }, DUR - 0.02);
|
|
|
|
tl.eventCallback("onUpdate", render);
|
|
render();
|
|
|
|
window.__timelines["mk-callout-highlight"] = tl;
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|