feat(registry): add mk-callout-highlight — word-sweep highlight

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jbernard077
2026-07-06 12:50:58 -04:00
co-authored by Claude Fable 5
parent 3e4a4042e5
commit 9be7a6415c
4 changed files with 225 additions and 0 deletions
@@ -0,0 +1,44 @@
---
title: "Word-Sweep Highlight"
description: "A sentence whose word-by-word emphasis is driven by a single scalar — tween it to sync the highlight with a voiceover"
---
# Word-Sweep Highlight
A sentence whose word-by-word emphasis is driven by a single scalar — tween it to sync the highlight with a voiceover
`typography` `karaoke` `captions` `minimal`
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/mk-callout-highlight.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/mk-callout-highlight.png" autoPlay muted loop playsInline />
## Install
<CodeGroup>
```bash Terminal
npx hyperframes add mk-callout-highlight
```
</CodeGroup>
## Details
| Property | Value |
| --- | --- |
| Type | Block |
| Dimensions | 1920×1080 |
| Duration | 8s |
## Files
| File | Target | Type |
| --- | --- | --- |
| `mk-callout-highlight.html` | `compositions/mk-callout-highlight.html` | hyperframes:composition |
## Usage
After installing, add the block to your host composition:
```html
<div data-composition-id="mk-callout-highlight" data-composition-src="compositions/mk-callout-highlight.html" data-start="0" data-duration="8" data-track-index="1" data-width="1920" data-height="1080"></div>
```
@@ -0,0 +1,152 @@
<!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>
@@ -0,0 +1,25 @@
{
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
"name": "mk-callout-highlight",
"type": "hyperframes:block",
"title": "Word-Sweep Highlight",
"description": "A sentence whose word-by-word emphasis is driven by a single scalar \u2014 tween it to sync the highlight with a voiceover",
"tags": [
"typography",
"karaoke",
"captions",
"minimal"
],
"dimensions": {
"width": 1920,
"height": 1080
},
"duration": 8,
"files": [
{
"path": "mk-callout-highlight.html",
"target": "compositions/mk-callout-highlight.html",
"type": "hyperframes:composition"
}
]
}
+4
View File
@@ -567,6 +567,10 @@
"name": "mk-specs-list",
"type": "hyperframes:block"
},
{
"name": "mk-callout-highlight",
"type": "hyperframes:block"
},
{
"name": "parallax-zoom",
"type": "hyperframes:component"