mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
Merge pull request #927 from heygen-com/fix/caption-polish
fix(registry): polish caption timing and add highlight style
This commit is contained in:
@@ -9,7 +9,7 @@ RGB chromatic aberration with CRT scanline overlay
|
||||
|
||||
`captions` `caption-style` `glitch` `cyber` `tech`
|
||||
|
||||
<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/components/caption-glitch-rgb.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-glitch-rgb.png" autoPlay muted loop playsInline />
|
||||
<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/components/caption-glitch-rgb.mp4?v=1779066308" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-glitch-rgb.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Highlight"
|
||||
description: "Red background sweep behind each active word, TikTok-style"
|
||||
---
|
||||
|
||||
# Highlight
|
||||
|
||||
Red background sweep behind each active word, TikTok-style
|
||||
|
||||
`captions` `caption-style` `highlight` `social` `tiktok`
|
||||
|
||||
<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/components/caption-highlight.mp4?v=1779066308" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-highlight.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add caption-highlight
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `caption-highlight.html` | `compositions/components/caption-highlight.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/caption-highlight.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: "Typewriter"
|
||||
description: "Green terminal character-by-character reveal with blinking cursor"
|
||||
---
|
||||
|
||||
# Typewriter
|
||||
|
||||
Green terminal character-by-character reveal with blinking cursor
|
||||
|
||||
`captions` `caption-style` `terminal` `typewriter` `hacker`
|
||||
|
||||
<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/components/caption-typewriter.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-typewriter.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add caption-typewriter
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `caption-typewriter.html` | `compositions/components/caption-typewriter.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/caption-typewriter.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -9,7 +9,7 @@ Elegant font-weight transition between caption lines
|
||||
|
||||
`captions` `caption-style` `minimal` `typography`
|
||||
|
||||
<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/components/caption-weight-shift.mp4" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-weight-shift.png" autoPlay muted loop playsInline />
|
||||
<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/components/caption-weight-shift.mp4?v=1779066308" poster="https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-weight-shift.png" autoPlay muted loop playsInline />
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
+1
-1
@@ -103,6 +103,7 @@
|
||||
"catalog/components/caption-emoji-pop",
|
||||
"catalog/components/caption-glitch-rgb",
|
||||
"catalog/components/caption-gradient-fill",
|
||||
"catalog/components/caption-highlight",
|
||||
"catalog/components/caption-kinetic-slam",
|
||||
"catalog/components/caption-matrix-decode",
|
||||
"catalog/components/caption-neon-accent",
|
||||
@@ -111,7 +112,6 @@
|
||||
"catalog/components/caption-particle-burst",
|
||||
"catalog/components/caption-pill-karaoke",
|
||||
"catalog/components/caption-texture-lava",
|
||||
"catalog/components/caption-typewriter",
|
||||
"catalog/components/caption-weight-shift"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -114,6 +114,21 @@
|
||||
"href": "/catalog/components/caption-gradient-fill",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-gradient-fill.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-highlight",
|
||||
"type": "component",
|
||||
"title": "Highlight",
|
||||
"description": "Red background sweep behind each active word, TikTok-style",
|
||||
"tags": [
|
||||
"captions",
|
||||
"caption-style",
|
||||
"highlight",
|
||||
"social",
|
||||
"tiktok"
|
||||
],
|
||||
"href": "/catalog/components/caption-highlight",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-highlight.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-kinetic-slam",
|
||||
"type": "component",
|
||||
@@ -233,21 +248,6 @@
|
||||
"href": "/catalog/components/caption-texture-lava",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-texture-lava.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-typewriter",
|
||||
"type": "component",
|
||||
"title": "Typewriter",
|
||||
"description": "Green terminal character-by-character reveal with blinking cursor",
|
||||
"tags": [
|
||||
"captions",
|
||||
"caption-style",
|
||||
"terminal",
|
||||
"typewriter",
|
||||
"hacker"
|
||||
],
|
||||
"href": "/catalog/components/caption-typewriter",
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/caption-typewriter.png"
|
||||
},
|
||||
{
|
||||
"name": "caption-weight-shift",
|
||||
"type": "component",
|
||||
|
||||
@@ -257,15 +257,32 @@ async function buildFontFaceCss(
|
||||
const unresolved: string[] = [];
|
||||
|
||||
for (const [normalizedFamily, originalCaseFamily] of requestedFamilies) {
|
||||
// Path 1: pre-bundled fonts via FONT_ALIASES
|
||||
// Path 1: pre-bundled fonts via FONT_ALIASES — emit embedded faces,
|
||||
// then fetch from Google Fonts to fill any weights not in the bundle.
|
||||
const canonicalKey = FONT_ALIASES[normalizedFamily];
|
||||
if (canonicalKey) {
|
||||
const canonical = CANONICAL_FONTS[canonicalKey];
|
||||
if (!canonical) continue;
|
||||
|
||||
const coveredWeights = new Set<string>();
|
||||
for (const face of canonical.faces) {
|
||||
const style = face.style || "normal";
|
||||
const src = fontDataUri(canonical.packageName, face.weight, style);
|
||||
rules.push(buildFontFaceRule(originalCaseFamily, src, face.weight, style));
|
||||
coveredWeights.add(`${face.weight}:${style}`);
|
||||
}
|
||||
|
||||
// Fetch all weights from Google Fonts and add any that aren't
|
||||
// already covered by the embedded bundle. This ensures that
|
||||
// compositions requesting e.g. wght@200 get that weight even
|
||||
// if the bundle only ships 400/700/900.
|
||||
const googleFaces = await fetchGoogleFont(originalCaseFamily, options);
|
||||
for (const face of googleFaces) {
|
||||
const key = `${face.weight}:${face.style}`;
|
||||
if (!coveredWeights.has(key)) {
|
||||
rules.push(buildFontFaceRule(originalCaseFamily, face.dataUri, face.weight, face.style));
|
||||
coveredWeights.add(key);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.35, nextStart - 0.05);
|
||||
var gEnd = Math.min(WORDS[we].end + 0.5, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
});
|
||||
|
||||
@@ -210,13 +210,13 @@
|
||||
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ clipPath: "inset(0 0% 0 0)", duration: 0.15, ease: "power3.out" },
|
||||
{ clipPath: "inset(0 0% 0 0)", duration: 0.3, ease: "power2.out" },
|
||||
w.start,
|
||||
);
|
||||
if (isKW) {
|
||||
tl.to(wordEl, { color: "#FFD700", duration: 0.05 }, w.start + 0.1);
|
||||
}
|
||||
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", duration: 0.12 }, w.end);
|
||||
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", duration: 0.2 }, w.end);
|
||||
});
|
||||
|
||||
var wordEls = grp.querySelectorAll(".wp-word");
|
||||
@@ -224,7 +224,7 @@
|
||||
wordEls,
|
||||
{
|
||||
clipPath: "inset(0 0% 0 100%)",
|
||||
duration: 0.14,
|
||||
duration: 0.25,
|
||||
stagger: 0.04,
|
||||
ease: "power2.in",
|
||||
},
|
||||
|
||||
+4
-4
@@ -169,7 +169,7 @@
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.35, nextStart - 0.05);
|
||||
var gEnd = Math.min(WORDS[we].end + 0.5, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
});
|
||||
|
||||
@@ -210,13 +210,13 @@
|
||||
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ clipPath: "inset(0 0% 0 0)", duration: 0.15, ease: "power3.out" },
|
||||
{ clipPath: "inset(0 0% 0 0)", duration: 0.3, ease: "power2.out" },
|
||||
w.start,
|
||||
);
|
||||
if (isKW) {
|
||||
tl.to(wordEl, { color: "#FFD700", duration: 0.05 }, w.start + 0.1);
|
||||
}
|
||||
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", duration: 0.12 }, w.end);
|
||||
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", duration: 0.2 }, w.end);
|
||||
});
|
||||
|
||||
var wordEls = grp.querySelectorAll(".wp-word");
|
||||
@@ -224,7 +224,7 @@
|
||||
wordEls,
|
||||
{
|
||||
clipPath: "inset(0 0% 0 100%)",
|
||||
duration: 0.14,
|
||||
duration: 0.25,
|
||||
stagger: 0.04,
|
||||
ease: "power2.in",
|
||||
},
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-clip-wipe/preview.mp4?v=1779051416"
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-clip-wipe/preview.mp4?v=1779057707"
|
||||
}
|
||||
|
||||
+133
-101
@@ -25,7 +25,7 @@
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#glitch-rgb {
|
||||
#caption-glitch-rgb {
|
||||
position: relative;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
@@ -43,8 +43,13 @@
|
||||
.gl-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
z-index: 1;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0.08) 0%,
|
||||
rgba(0, 0, 0, 0.16) 54%,
|
||||
rgba(0, 0, 0, 0.5) 100%
|
||||
);
|
||||
pointer-events: none;
|
||||
}
|
||||
.gl-scanlines {
|
||||
@@ -56,9 +61,10 @@
|
||||
to bottom,
|
||||
transparent 0px,
|
||||
transparent 3px,
|
||||
rgba(0, 0, 0, 0.08) 3px,
|
||||
rgba(0, 0, 0, 0.08) 4px
|
||||
rgba(0, 0, 0, 0.16) 3px,
|
||||
rgba(0, 0, 0, 0.16) 4px
|
||||
);
|
||||
opacity: 0.55;
|
||||
}
|
||||
#gl-container {
|
||||
position: absolute;
|
||||
@@ -75,7 +81,7 @@
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
gap: 14px;
|
||||
padding: 0 100px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
@@ -85,17 +91,18 @@
|
||||
font-weight: 700;
|
||||
font-size: 88px;
|
||||
text-transform: uppercase;
|
||||
color: rgba(180, 230, 255, 0.45);
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 1;
|
||||
will-change: transform, text-shadow, color;
|
||||
letter-spacing: 0.03em;
|
||||
line-height: 0.96;
|
||||
text-shadow: 0 5px 18px rgba(0, 0, 0, 0.52);
|
||||
will-change: transform, text-shadow;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="glitch-rgb"
|
||||
id="caption-glitch-rgb"
|
||||
data-composition-id="caption-glitch-rgb"
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
@@ -121,30 +128,7 @@
|
||||
(function () {
|
||||
window.__timelines = window.__timelines || {};
|
||||
|
||||
var _fitCanvas = document.createElement("canvas");
|
||||
var _fitCtx = _fitCanvas.getContext("2d");
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
size -= 2;
|
||||
}
|
||||
return minSize;
|
||||
}
|
||||
|
||||
function mulberry32(seed) {
|
||||
return function () {
|
||||
seed |= 0;
|
||||
seed = (seed + 0x6d2b79f5) | 0;
|
||||
var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
|
||||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
var WORDS = [
|
||||
var TRANSCRIPT = [
|
||||
{ text: "Every", start: 0.0, end: 0.3 },
|
||||
{ text: "great", start: 0.3, end: 0.55 },
|
||||
{ text: "video", start: 0.55, end: 0.85 },
|
||||
@@ -175,27 +159,69 @@
|
||||
{ text: "cinema.", start: 7.3, end: 7.7 },
|
||||
];
|
||||
|
||||
// Keywords get white + glow on activation
|
||||
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
|
||||
var _fitCanvas = document.createElement("canvas");
|
||||
var _fitCtx = _fitCanvas.getContext("2d");
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
size -= 2;
|
||||
}
|
||||
return minSize;
|
||||
}
|
||||
|
||||
var RAW_GROUPS = [
|
||||
[0, 3],
|
||||
[4, 7],
|
||||
[8, 8],
|
||||
[9, 12],
|
||||
[13, 15],
|
||||
[16, 16],
|
||||
[17, 19],
|
||||
[20, 22],
|
||||
[23, 24],
|
||||
[25, 27],
|
||||
];
|
||||
function mulberry32(seed) {
|
||||
return function () {
|
||||
seed |= 0;
|
||||
seed = (seed + 0x6d2b79f5) | 0;
|
||||
var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
|
||||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
function buildGroups(words) {
|
||||
var groups = [];
|
||||
var start = 0;
|
||||
var chars = 0;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
chars += words[i].text.length + 1;
|
||||
var endsSentence = /[.!?]$/.test(words[i].text);
|
||||
var nextGap = i + 1 < words.length ? words[i + 1].start - words[i].end : 0;
|
||||
var full = i - start >= 3 || chars >= 21;
|
||||
if (endsSentence || nextGap > 0.28 || full || i === words.length - 1) {
|
||||
groups.push([start, i]);
|
||||
start = i + 1;
|
||||
chars = 0;
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
function glitchPlan(word, nextWord) {
|
||||
var nextStart = nextWord ? nextWord.start : word.end + 0.3;
|
||||
var available = Math.min(word.end, nextStart) - word.start - 0.02;
|
||||
var total = Math.min(0.24, Math.max(0.08, available));
|
||||
return {
|
||||
d1: total * 0.35,
|
||||
d2: total * 0.65,
|
||||
};
|
||||
}
|
||||
|
||||
function shouldAftershock(word) {
|
||||
return /\d|\$|%/.test(word.text) || word.text.replace(/[^\w]/g, "").length >= 7;
|
||||
}
|
||||
|
||||
var RAW_GROUPS = buildGroups(TRANSCRIPT);
|
||||
var GROUPS = RAW_GROUPS.map(function (pair, gi) {
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.35, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
var ws = pair[0];
|
||||
var we = pair[1];
|
||||
var nextStart =
|
||||
gi + 1 < RAW_GROUPS.length ? TRANSCRIPT[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var end = Math.min(TRANSCRIPT[we].end + 0.24, nextStart - 0.04);
|
||||
return { wordStart: ws, wordEnd: we, start: TRANSCRIPT[ws].start, end: end };
|
||||
});
|
||||
|
||||
var BASE_FONT = 88;
|
||||
@@ -203,7 +229,7 @@
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (g, gi) {
|
||||
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
|
||||
var groupWords = TRANSCRIPT.slice(g.wordStart, g.wordEnd + 1);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "gl-group";
|
||||
grp.id = "gl-grp-" + gi;
|
||||
@@ -230,77 +256,83 @@
|
||||
tl.set(grp, { visibility: "visible" }, g.start);
|
||||
tl.fromTo(
|
||||
grp,
|
||||
{ opacity: 0, x: -8 },
|
||||
{ opacity: 1, x: 0, duration: 0.18, ease: "power3.out" },
|
||||
{ opacity: 0 },
|
||||
{ opacity: 1, duration: 0.12, ease: "power2.out" },
|
||||
g.start,
|
||||
);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var wordEl = document.getElementById("gl-w-" + wi);
|
||||
var isKW = KEYWORDS.has(wi);
|
||||
var plan = glitchPlan(w, TRANSCRIPT[wi + 1]);
|
||||
|
||||
var rng = mulberry32(wi * 777 + 13);
|
||||
var j1 = (rng() - 0.5) * 10;
|
||||
var j2 = (rng() - 0.5) * 8;
|
||||
var j3 = (rng() - 0.5) * 6;
|
||||
var shadowMag = 3 + rng() * 4;
|
||||
var travel = -(8 + rng() * 8);
|
||||
var shadowMag = 5 + rng() * 7;
|
||||
var sm = shadowMag.toFixed(1);
|
||||
var nextWord = TRANSCRIPT[wi + 1];
|
||||
var nextStart = nextWord ? nextWord.start : g.end;
|
||||
var aftershockEnd = Math.min(g.end - 0.08, nextStart - 0.04);
|
||||
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j1,
|
||||
color: "#ffffff",
|
||||
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
|
||||
duration: 0.045,
|
||||
x: travel,
|
||||
textShadow:
|
||||
sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff, 0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: plan.d1,
|
||||
ease: "none",
|
||||
},
|
||||
w.start,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j2,
|
||||
textShadow:
|
||||
"-" +
|
||||
(shadowMag * 0.7).toFixed(1) +
|
||||
"px 0 #ff003c, " +
|
||||
(shadowMag * 0.7).toFixed(1) +
|
||||
"px 0 #00e5ff",
|
||||
duration: 0.038,
|
||||
ease: "none",
|
||||
},
|
||||
w.start + 0.045,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j3,
|
||||
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
|
||||
duration: 0.03,
|
||||
ease: "none",
|
||||
},
|
||||
w.start + 0.083,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: 0,
|
||||
textShadow: "none",
|
||||
color: isKW ? "#ffffff" : "#00e5ff",
|
||||
duration: 0.05,
|
||||
ease: "power2.out",
|
||||
textShadow: "0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: plan.d2,
|
||||
ease: "power3.out",
|
||||
},
|
||||
w.start + 0.113,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ color: "rgba(180,230,255,0.4)", textShadow: "none", duration: 0.12 },
|
||||
w.end,
|
||||
w.start + plan.d1,
|
||||
);
|
||||
|
||||
if (shouldAftershock(w) && aftershockEnd - w.end > 0.22) {
|
||||
var pulseStart = w.end + 0.08;
|
||||
var pulseIndex = 0;
|
||||
while (pulseStart + 0.1 < aftershockEnd) {
|
||||
var pulseTravel = -(3 + rng() * 5);
|
||||
var pulseShadow = (3 + rng() * 5).toFixed(1);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: pulseTravel,
|
||||
textShadow:
|
||||
pulseShadow +
|
||||
"px 0 #ff003c, -" +
|
||||
pulseShadow +
|
||||
"px 0 #00e5ff, 0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: 0.045,
|
||||
ease: "none",
|
||||
},
|
||||
pulseStart,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: 0,
|
||||
textShadow: "0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: 0.075,
|
||||
ease: "power3.out",
|
||||
},
|
||||
pulseStart + 0.045,
|
||||
);
|
||||
pulseIndex++;
|
||||
pulseStart += pulseIndex % 2 === 0 ? 0.18 : 0.24;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
|
||||
tl.to(grp, { opacity: 0, duration: 0.1, ease: "power2.in" }, g.end - 0.1);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
|
||||
+133
-101
@@ -25,7 +25,7 @@
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#glitch-rgb {
|
||||
#caption-glitch-rgb {
|
||||
position: relative;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
@@ -43,8 +43,13 @@
|
||||
.gl-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
z-index: 1;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(0, 0, 0, 0.08) 0%,
|
||||
rgba(0, 0, 0, 0.16) 54%,
|
||||
rgba(0, 0, 0, 0.5) 100%
|
||||
);
|
||||
pointer-events: none;
|
||||
}
|
||||
.gl-scanlines {
|
||||
@@ -56,9 +61,10 @@
|
||||
to bottom,
|
||||
transparent 0px,
|
||||
transparent 3px,
|
||||
rgba(0, 0, 0, 0.08) 3px,
|
||||
rgba(0, 0, 0, 0.08) 4px
|
||||
rgba(0, 0, 0, 0.16) 3px,
|
||||
rgba(0, 0, 0, 0.16) 4px
|
||||
);
|
||||
opacity: 0.55;
|
||||
}
|
||||
#gl-container {
|
||||
position: absolute;
|
||||
@@ -75,7 +81,7 @@
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
gap: 14px;
|
||||
padding: 0 100px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
@@ -85,17 +91,18 @@
|
||||
font-weight: 700;
|
||||
font-size: 88px;
|
||||
text-transform: uppercase;
|
||||
color: rgba(180, 230, 255, 0.45);
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 1;
|
||||
will-change: transform, text-shadow, color;
|
||||
letter-spacing: 0.03em;
|
||||
line-height: 0.96;
|
||||
text-shadow: 0 5px 18px rgba(0, 0, 0, 0.52);
|
||||
will-change: transform, text-shadow;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="glitch-rgb"
|
||||
id="caption-glitch-rgb"
|
||||
data-composition-id="caption-glitch-rgb"
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
@@ -121,30 +128,7 @@
|
||||
(function () {
|
||||
window.__timelines = window.__timelines || {};
|
||||
|
||||
var _fitCanvas = document.createElement("canvas");
|
||||
var _fitCtx = _fitCanvas.getContext("2d");
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
size -= 2;
|
||||
}
|
||||
return minSize;
|
||||
}
|
||||
|
||||
function mulberry32(seed) {
|
||||
return function () {
|
||||
seed |= 0;
|
||||
seed = (seed + 0x6d2b79f5) | 0;
|
||||
var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
|
||||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
var WORDS = [
|
||||
var TRANSCRIPT = [
|
||||
{ text: "Every", start: 0.0, end: 0.3 },
|
||||
{ text: "great", start: 0.3, end: 0.55 },
|
||||
{ text: "video", start: 0.55, end: 0.85 },
|
||||
@@ -175,27 +159,69 @@
|
||||
{ text: "cinema.", start: 7.3, end: 7.7 },
|
||||
];
|
||||
|
||||
// Keywords get white + glow on activation
|
||||
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
|
||||
var _fitCanvas = document.createElement("canvas");
|
||||
var _fitCtx = _fitCanvas.getContext("2d");
|
||||
function fitFontSize(text, baseFontSize, fontWeight, fontFamily, maxWidth) {
|
||||
var size = baseFontSize;
|
||||
var minSize = Math.floor(baseFontSize * 0.45);
|
||||
while (size > minSize) {
|
||||
_fitCtx.font = fontWeight + " " + size + "px " + fontFamily;
|
||||
if (_fitCtx.measureText(text).width <= maxWidth) return size;
|
||||
size -= 2;
|
||||
}
|
||||
return minSize;
|
||||
}
|
||||
|
||||
var RAW_GROUPS = [
|
||||
[0, 3],
|
||||
[4, 7],
|
||||
[8, 8],
|
||||
[9, 12],
|
||||
[13, 15],
|
||||
[16, 16],
|
||||
[17, 19],
|
||||
[20, 22],
|
||||
[23, 24],
|
||||
[25, 27],
|
||||
];
|
||||
function mulberry32(seed) {
|
||||
return function () {
|
||||
seed |= 0;
|
||||
seed = (seed + 0x6d2b79f5) | 0;
|
||||
var t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
|
||||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
||||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
function buildGroups(words) {
|
||||
var groups = [];
|
||||
var start = 0;
|
||||
var chars = 0;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
chars += words[i].text.length + 1;
|
||||
var endsSentence = /[.!?]$/.test(words[i].text);
|
||||
var nextGap = i + 1 < words.length ? words[i + 1].start - words[i].end : 0;
|
||||
var full = i - start >= 3 || chars >= 21;
|
||||
if (endsSentence || nextGap > 0.28 || full || i === words.length - 1) {
|
||||
groups.push([start, i]);
|
||||
start = i + 1;
|
||||
chars = 0;
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
function glitchPlan(word, nextWord) {
|
||||
var nextStart = nextWord ? nextWord.start : word.end + 0.3;
|
||||
var available = Math.min(word.end, nextStart) - word.start - 0.02;
|
||||
var total = Math.min(0.24, Math.max(0.08, available));
|
||||
return {
|
||||
d1: total * 0.35,
|
||||
d2: total * 0.65,
|
||||
};
|
||||
}
|
||||
|
||||
function shouldAftershock(word) {
|
||||
return /\d|\$|%/.test(word.text) || word.text.replace(/[^\w]/g, "").length >= 7;
|
||||
}
|
||||
|
||||
var RAW_GROUPS = buildGroups(TRANSCRIPT);
|
||||
var GROUPS = RAW_GROUPS.map(function (pair, gi) {
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.35, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
var ws = pair[0];
|
||||
var we = pair[1];
|
||||
var nextStart =
|
||||
gi + 1 < RAW_GROUPS.length ? TRANSCRIPT[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var end = Math.min(TRANSCRIPT[we].end + 0.24, nextStart - 0.04);
|
||||
return { wordStart: ws, wordEnd: we, start: TRANSCRIPT[ws].start, end: end };
|
||||
});
|
||||
|
||||
var BASE_FONT = 88;
|
||||
@@ -203,7 +229,7 @@
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (g, gi) {
|
||||
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
|
||||
var groupWords = TRANSCRIPT.slice(g.wordStart, g.wordEnd + 1);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "gl-group";
|
||||
grp.id = "gl-grp-" + gi;
|
||||
@@ -230,77 +256,83 @@
|
||||
tl.set(grp, { visibility: "visible" }, g.start);
|
||||
tl.fromTo(
|
||||
grp,
|
||||
{ opacity: 0, x: -8 },
|
||||
{ opacity: 1, x: 0, duration: 0.18, ease: "power3.out" },
|
||||
{ opacity: 0 },
|
||||
{ opacity: 1, duration: 0.12, ease: "power2.out" },
|
||||
g.start,
|
||||
);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var wordEl = document.getElementById("gl-w-" + wi);
|
||||
var isKW = KEYWORDS.has(wi);
|
||||
var plan = glitchPlan(w, TRANSCRIPT[wi + 1]);
|
||||
|
||||
var rng = mulberry32(wi * 777 + 13);
|
||||
var j1 = (rng() - 0.5) * 10;
|
||||
var j2 = (rng() - 0.5) * 8;
|
||||
var j3 = (rng() - 0.5) * 6;
|
||||
var shadowMag = 3 + rng() * 4;
|
||||
var travel = -(8 + rng() * 8);
|
||||
var shadowMag = 5 + rng() * 7;
|
||||
var sm = shadowMag.toFixed(1);
|
||||
var nextWord = TRANSCRIPT[wi + 1];
|
||||
var nextStart = nextWord ? nextWord.start : g.end;
|
||||
var aftershockEnd = Math.min(g.end - 0.08, nextStart - 0.04);
|
||||
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j1,
|
||||
color: "#ffffff",
|
||||
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
|
||||
duration: 0.045,
|
||||
x: travel,
|
||||
textShadow:
|
||||
sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff, 0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: plan.d1,
|
||||
ease: "none",
|
||||
},
|
||||
w.start,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j2,
|
||||
textShadow:
|
||||
"-" +
|
||||
(shadowMag * 0.7).toFixed(1) +
|
||||
"px 0 #ff003c, " +
|
||||
(shadowMag * 0.7).toFixed(1) +
|
||||
"px 0 #00e5ff",
|
||||
duration: 0.038,
|
||||
ease: "none",
|
||||
},
|
||||
w.start + 0.045,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: j3,
|
||||
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
|
||||
duration: 0.03,
|
||||
ease: "none",
|
||||
},
|
||||
w.start + 0.083,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: 0,
|
||||
textShadow: "none",
|
||||
color: isKW ? "#ffffff" : "#00e5ff",
|
||||
duration: 0.05,
|
||||
ease: "power2.out",
|
||||
textShadow: "0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: plan.d2,
|
||||
ease: "power3.out",
|
||||
},
|
||||
w.start + 0.113,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ color: "rgba(180,230,255,0.4)", textShadow: "none", duration: 0.12 },
|
||||
w.end,
|
||||
w.start + plan.d1,
|
||||
);
|
||||
|
||||
if (shouldAftershock(w) && aftershockEnd - w.end > 0.22) {
|
||||
var pulseStart = w.end + 0.08;
|
||||
var pulseIndex = 0;
|
||||
while (pulseStart + 0.1 < aftershockEnd) {
|
||||
var pulseTravel = -(3 + rng() * 5);
|
||||
var pulseShadow = (3 + rng() * 5).toFixed(1);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: pulseTravel,
|
||||
textShadow:
|
||||
pulseShadow +
|
||||
"px 0 #ff003c, -" +
|
||||
pulseShadow +
|
||||
"px 0 #00e5ff, 0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: 0.045,
|
||||
ease: "none",
|
||||
},
|
||||
pulseStart,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{
|
||||
x: 0,
|
||||
textShadow: "0 5px 18px rgba(0,0,0,0.52)",
|
||||
duration: 0.075,
|
||||
ease: "power3.out",
|
||||
},
|
||||
pulseStart + 0.045,
|
||||
);
|
||||
pulseIndex++;
|
||||
pulseStart += pulseIndex % 2 === 0 ? 0.18 : 0.24;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
|
||||
tl.to(grp, { opacity: 0, duration: 0.1, ease: "power2.in" }, g.end - 0.1);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-glitch-rgb/preview.mp4?v=1779051416"
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-glitch-rgb/preview.mp4?v=1779065047"
|
||||
}
|
||||
|
||||
@@ -233,11 +233,11 @@
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var el = document.getElementById("gr-w-" + wi);
|
||||
tl.to(el, { opacity: 1, scale: 1.1, duration: 0.08 }, w.start);
|
||||
tl.to(el, { opacity: 0.3, scale: 1, duration: 0.08 }, w.end);
|
||||
tl.to(el, { opacity: 1, scale: 1.1, duration: 0.15 }, w.start);
|
||||
tl.to(el, { opacity: 0.3, scale: 1, duration: 0.15 }, w.end);
|
||||
});
|
||||
|
||||
tl.to(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
|
||||
tl.to(grp, { y: -26, opacity: 0, duration: 0.25 }, g.end - 0.25);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
|
||||
+3
-3
@@ -233,11 +233,11 @@
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var el = document.getElementById("gr-w-" + wi);
|
||||
tl.to(el, { opacity: 1, scale: 1.1, duration: 0.08 }, w.start);
|
||||
tl.to(el, { opacity: 0.3, scale: 1, duration: 0.08 }, w.end);
|
||||
tl.to(el, { opacity: 1, scale: 1.1, duration: 0.15 }, w.start);
|
||||
tl.to(el, { opacity: 0.3, scale: 1, duration: 0.15 }, w.end);
|
||||
});
|
||||
|
||||
tl.to(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
|
||||
tl.to(grp, { y: -26, opacity: 0, duration: 0.25 }, g.end - 0.25);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-gradient-fill/preview.mp4?v=1779051416"
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-gradient-fill/preview.mp4?v=1779057707"
|
||||
}
|
||||
|
||||
+106
-91
@@ -3,11 +3,11 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Typewriter</title>
|
||||
<title>Highlight</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=JetBrains+Mono:wght@700&display=swap"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
@@ -23,16 +23,16 @@
|
||||
height: 1080px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#typewriter {
|
||||
#highlight {
|
||||
position: relative;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#tw-video {
|
||||
#hl-video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
@@ -40,78 +40,77 @@
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.tw-overlay {
|
||||
.hl-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
#tw-container {
|
||||
#hl-container {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
.tw-group {
|
||||
.hl-group {
|
||||
position: absolute;
|
||||
bottom: 120px;
|
||||
bottom: 140px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
padding: 0 80px;
|
||||
gap: 8px;
|
||||
padding: 0 100px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.tw-word {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-weight: 700;
|
||||
font-size: 76px;
|
||||
color: #00ff41;
|
||||
text-shadow: 0 0 12px rgba(0, 255, 65, 0.5);
|
||||
.hl-word {
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 800;
|
||||
font-size: 80px;
|
||||
text-transform: uppercase;
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
letter-spacing: 0.04em;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
padding: 6px 12px 8px;
|
||||
text-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
|
||||
transform-origin: 50% 58%;
|
||||
will-change: transform, filter;
|
||||
}
|
||||
.tw-char {
|
||||
display: none;
|
||||
.hl-word-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(135deg, #ff1745 0%, #df1238 100%);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 12px 30px rgba(229, 20, 58, 0.32);
|
||||
opacity: 0;
|
||||
transform: scaleX(0);
|
||||
transform-origin: 0% 50%;
|
||||
z-index: -1;
|
||||
}
|
||||
.tw-cursor {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-weight: 700;
|
||||
font-size: 76px;
|
||||
color: #00ff41;
|
||||
text-shadow: 0 0 12px rgba(0, 255, 65, 0.5);
|
||||
display: none;
|
||||
.hl-word-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="typewriter"
|
||||
data-composition-id="caption-typewriter"
|
||||
id="highlight"
|
||||
data-composition-id="caption-highlight"
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
data-fps="30"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<video
|
||||
id="tw-video"
|
||||
muted
|
||||
playsinline
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
data-track-index="0"
|
||||
data-has-audio="false"
|
||||
></video>
|
||||
<div class="tw-overlay"></div>
|
||||
<div id="tw-container"></div>
|
||||
<div class="hl-overlay"></div>
|
||||
<div id="hl-container"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -162,82 +161,98 @@
|
||||
{ text: "cinema.", start: 7.3, end: 7.7 },
|
||||
];
|
||||
|
||||
var GROUPS = [
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.1 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.05 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.6 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.5 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.4 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 4.75 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.4 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.2 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 6.75 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.8 },
|
||||
var RAW_GROUPS = [
|
||||
[0, 3],
|
||||
[4, 7],
|
||||
[8, 8],
|
||||
[9, 12],
|
||||
[13, 15],
|
||||
[16, 16],
|
||||
[17, 19],
|
||||
[20, 22],
|
||||
[23, 24],
|
||||
[25, 27],
|
||||
];
|
||||
var GROUPS = RAW_GROUPS.map(function (pair, gi) {
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.5, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
});
|
||||
|
||||
var container = document.getElementById("tw-container");
|
||||
var container = document.getElementById("hl-container");
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (g, gi) {
|
||||
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "hl-group";
|
||||
grp.id = "hl-grp-" + gi;
|
||||
|
||||
var groupText = groupWords
|
||||
.map(function (w) {
|
||||
return w.text;
|
||||
return w.text.toUpperCase();
|
||||
})
|
||||
.join(" ");
|
||||
var fontSize = fitFontSize(groupText, 76, "700", "'JetBrains Mono', monospace", 1760);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "tw-group";
|
||||
grp.id = "tw-grp-" + gi;
|
||||
var computedSize = fitFontSize(groupText, 80, "800", "Montserrat", 1620);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var wordWrap = document.createElement("span");
|
||||
wordWrap.className = "tw-word";
|
||||
wordWrap.id = "tw-w-" + wi;
|
||||
wordWrap.style.fontSize = fontSize + "px";
|
||||
var wordEl = document.createElement("span");
|
||||
wordEl.className = "hl-word";
|
||||
wordEl.id = "hl-w-" + wi;
|
||||
wordEl.style.fontSize = computedSize + "px";
|
||||
|
||||
w.text.split("").forEach(function (c, ci) {
|
||||
var charEl = document.createElement("span");
|
||||
charEl.className = "tw-char";
|
||||
charEl.id = "tw-c-" + wi + "-" + ci;
|
||||
charEl.textContent = c;
|
||||
wordWrap.appendChild(charEl);
|
||||
});
|
||||
var bgEl = document.createElement("span");
|
||||
bgEl.className = "hl-word-bg";
|
||||
bgEl.id = "hl-bg-" + wi;
|
||||
|
||||
var cursor = document.createElement("span");
|
||||
cursor.className = "tw-cursor";
|
||||
cursor.id = "tw-cur-" + wi;
|
||||
cursor.textContent = "_";
|
||||
cursor.style.fontSize = fontSize + "px";
|
||||
wordWrap.appendChild(cursor);
|
||||
grp.appendChild(wordWrap);
|
||||
var textEl = document.createElement("span");
|
||||
textEl.className = "hl-word-text";
|
||||
textEl.textContent = w.text.toUpperCase();
|
||||
|
||||
wordEl.appendChild(bgEl);
|
||||
wordEl.appendChild(textEl);
|
||||
grp.appendChild(wordEl);
|
||||
});
|
||||
|
||||
container.appendChild(grp);
|
||||
|
||||
tl.set(grp, { visibility: "visible", opacity: 1 }, g.start);
|
||||
tl.set(grp, { visibility: "visible" }, g.start);
|
||||
tl.fromTo(
|
||||
grp,
|
||||
{ opacity: 0 },
|
||||
{ opacity: 1, duration: 0.12, ease: "power2.out" },
|
||||
g.start,
|
||||
);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var chars = w.text.split("");
|
||||
var wordDuration = Math.max(w.end - w.start, 0.1);
|
||||
var charCount = chars.length;
|
||||
var cursorEl = document.getElementById("tw-cur-" + wi);
|
||||
var bgEl = document.getElementById("hl-bg-" + wi);
|
||||
var wordEl = document.getElementById("hl-w-" + wi);
|
||||
|
||||
tl.set(cursorEl, { display: "inline" }, w.start);
|
||||
chars.forEach(function (c, ci) {
|
||||
var charEl = document.getElementById("tw-c-" + wi + "-" + ci);
|
||||
tl.set(charEl, { display: "inline" }, w.start + ci * (wordDuration / charCount));
|
||||
});
|
||||
tl.set(cursorEl, { display: "none" }, w.end);
|
||||
tl.to(bgEl, { opacity: 1, scaleX: 1, duration: 0.15, ease: "power2.out" }, w.start);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ filter: "brightness(1.05)", duration: 0.08, ease: "power2.out" },
|
||||
w.start,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ filter: "brightness(1)", duration: 0.16, ease: "power2.out" },
|
||||
w.start + 0.08,
|
||||
);
|
||||
tl.to(bgEl, { opacity: 0, scaleX: 1.02, duration: 0.1, ease: "power2.in" }, w.end);
|
||||
tl.set(bgEl, { scaleX: 0 }, w.end + 0.1);
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
|
||||
tl.to(grp, { opacity: 0, duration: 0.1, ease: "power2.in" }, g.end - 0.1);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
window.__timelines["caption-typewriter"] = tl;
|
||||
tl.seek(0);
|
||||
window.__timelines["caption-highlight"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
Vendored
+106
-91
@@ -3,11 +3,11 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Typewriter</title>
|
||||
<title>Highlight</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=JetBrains+Mono:wght@700&display=swap"
|
||||
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@800&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
@@ -23,16 +23,16 @@
|
||||
height: 1080px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#typewriter {
|
||||
#highlight {
|
||||
position: relative;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
background: #0a0a0a;
|
||||
}
|
||||
#tw-video {
|
||||
#hl-video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 0;
|
||||
@@ -40,78 +40,77 @@
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
.tw-overlay {
|
||||
.hl-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
#tw-container {
|
||||
#hl-container {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 10;
|
||||
pointer-events: none;
|
||||
}
|
||||
.tw-group {
|
||||
.hl-group {
|
||||
position: absolute;
|
||||
bottom: 120px;
|
||||
bottom: 140px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
padding: 0 80px;
|
||||
gap: 8px;
|
||||
padding: 0 100px;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.tw-word {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-weight: 700;
|
||||
font-size: 76px;
|
||||
color: #00ff41;
|
||||
text-shadow: 0 0 12px rgba(0, 255, 65, 0.5);
|
||||
.hl-word {
|
||||
font-family: "Montserrat", sans-serif;
|
||||
font-weight: 800;
|
||||
font-size: 80px;
|
||||
text-transform: uppercase;
|
||||
color: #ffffff;
|
||||
display: inline-block;
|
||||
letter-spacing: 0.04em;
|
||||
letter-spacing: 0.02em;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
padding: 6px 12px 8px;
|
||||
text-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
|
||||
transform-origin: 50% 58%;
|
||||
will-change: transform, filter;
|
||||
}
|
||||
.tw-char {
|
||||
display: none;
|
||||
.hl-word-bg {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(135deg, #ff1745 0%, #df1238 100%);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 12px 30px rgba(229, 20, 58, 0.32);
|
||||
opacity: 0;
|
||||
transform: scaleX(0);
|
||||
transform-origin: 0% 50%;
|
||||
z-index: -1;
|
||||
}
|
||||
.tw-cursor {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
font-weight: 700;
|
||||
font-size: 76px;
|
||||
color: #00ff41;
|
||||
text-shadow: 0 0 12px rgba(0, 255, 65, 0.5);
|
||||
display: none;
|
||||
.hl-word-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="typewriter"
|
||||
data-composition-id="caption-typewriter"
|
||||
id="highlight"
|
||||
data-composition-id="caption-highlight"
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
data-fps="30"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<video
|
||||
id="tw-video"
|
||||
muted
|
||||
playsinline
|
||||
data-start="0"
|
||||
data-duration="8"
|
||||
data-track-index="0"
|
||||
data-has-audio="false"
|
||||
></video>
|
||||
<div class="tw-overlay"></div>
|
||||
<div id="tw-container"></div>
|
||||
<div class="hl-overlay"></div>
|
||||
<div id="hl-container"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -162,82 +161,98 @@
|
||||
{ text: "cinema.", start: 7.3, end: 7.7 },
|
||||
];
|
||||
|
||||
var GROUPS = [
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.1 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.05 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.6 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.5 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.4 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 4.75 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.4 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.2 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 6.75 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.8 },
|
||||
var RAW_GROUPS = [
|
||||
[0, 3],
|
||||
[4, 7],
|
||||
[8, 8],
|
||||
[9, 12],
|
||||
[13, 15],
|
||||
[16, 16],
|
||||
[17, 19],
|
||||
[20, 22],
|
||||
[23, 24],
|
||||
[25, 27],
|
||||
];
|
||||
var GROUPS = RAW_GROUPS.map(function (pair, gi) {
|
||||
var ws = pair[0],
|
||||
we = pair[1];
|
||||
var nextStart = gi + 1 < RAW_GROUPS.length ? WORDS[RAW_GROUPS[gi + 1][0]].start : 8.0;
|
||||
var gEnd = Math.min(WORDS[we].end + 0.5, nextStart - 0.05);
|
||||
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
|
||||
});
|
||||
|
||||
var container = document.getElementById("tw-container");
|
||||
var container = document.getElementById("hl-container");
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (g, gi) {
|
||||
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "hl-group";
|
||||
grp.id = "hl-grp-" + gi;
|
||||
|
||||
var groupText = groupWords
|
||||
.map(function (w) {
|
||||
return w.text;
|
||||
return w.text.toUpperCase();
|
||||
})
|
||||
.join(" ");
|
||||
var fontSize = fitFontSize(groupText, 76, "700", "'JetBrains Mono', monospace", 1760);
|
||||
var grp = document.createElement("div");
|
||||
grp.className = "tw-group";
|
||||
grp.id = "tw-grp-" + gi;
|
||||
var computedSize = fitFontSize(groupText, 80, "800", "Montserrat", 1620);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var wordWrap = document.createElement("span");
|
||||
wordWrap.className = "tw-word";
|
||||
wordWrap.id = "tw-w-" + wi;
|
||||
wordWrap.style.fontSize = fontSize + "px";
|
||||
var wordEl = document.createElement("span");
|
||||
wordEl.className = "hl-word";
|
||||
wordEl.id = "hl-w-" + wi;
|
||||
wordEl.style.fontSize = computedSize + "px";
|
||||
|
||||
w.text.split("").forEach(function (c, ci) {
|
||||
var charEl = document.createElement("span");
|
||||
charEl.className = "tw-char";
|
||||
charEl.id = "tw-c-" + wi + "-" + ci;
|
||||
charEl.textContent = c;
|
||||
wordWrap.appendChild(charEl);
|
||||
});
|
||||
var bgEl = document.createElement("span");
|
||||
bgEl.className = "hl-word-bg";
|
||||
bgEl.id = "hl-bg-" + wi;
|
||||
|
||||
var cursor = document.createElement("span");
|
||||
cursor.className = "tw-cursor";
|
||||
cursor.id = "tw-cur-" + wi;
|
||||
cursor.textContent = "_";
|
||||
cursor.style.fontSize = fontSize + "px";
|
||||
wordWrap.appendChild(cursor);
|
||||
grp.appendChild(wordWrap);
|
||||
var textEl = document.createElement("span");
|
||||
textEl.className = "hl-word-text";
|
||||
textEl.textContent = w.text.toUpperCase();
|
||||
|
||||
wordEl.appendChild(bgEl);
|
||||
wordEl.appendChild(textEl);
|
||||
grp.appendChild(wordEl);
|
||||
});
|
||||
|
||||
container.appendChild(grp);
|
||||
|
||||
tl.set(grp, { visibility: "visible", opacity: 1 }, g.start);
|
||||
tl.set(grp, { visibility: "visible" }, g.start);
|
||||
tl.fromTo(
|
||||
grp,
|
||||
{ opacity: 0 },
|
||||
{ opacity: 1, duration: 0.12, ease: "power2.out" },
|
||||
g.start,
|
||||
);
|
||||
|
||||
groupWords.forEach(function (w, i) {
|
||||
var wi = g.wordStart + i;
|
||||
var chars = w.text.split("");
|
||||
var wordDuration = Math.max(w.end - w.start, 0.1);
|
||||
var charCount = chars.length;
|
||||
var cursorEl = document.getElementById("tw-cur-" + wi);
|
||||
var bgEl = document.getElementById("hl-bg-" + wi);
|
||||
var wordEl = document.getElementById("hl-w-" + wi);
|
||||
|
||||
tl.set(cursorEl, { display: "inline" }, w.start);
|
||||
chars.forEach(function (c, ci) {
|
||||
var charEl = document.getElementById("tw-c-" + wi + "-" + ci);
|
||||
tl.set(charEl, { display: "inline" }, w.start + ci * (wordDuration / charCount));
|
||||
});
|
||||
tl.set(cursorEl, { display: "none" }, w.end);
|
||||
tl.to(bgEl, { opacity: 1, scaleX: 1, duration: 0.15, ease: "power2.out" }, w.start);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ filter: "brightness(1.05)", duration: 0.08, ease: "power2.out" },
|
||||
w.start,
|
||||
);
|
||||
tl.to(
|
||||
wordEl,
|
||||
{ filter: "brightness(1)", duration: 0.16, ease: "power2.out" },
|
||||
w.start + 0.08,
|
||||
);
|
||||
tl.to(bgEl, { opacity: 0, scaleX: 1.02, duration: 0.1, ease: "power2.in" }, w.end);
|
||||
tl.set(bgEl, { scaleX: 0 }, w.end + 0.1);
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
|
||||
tl.to(grp, { opacity: 0, duration: 0.1, ease: "power2.in" }, g.end - 0.1);
|
||||
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
|
||||
});
|
||||
|
||||
window.__timelines["caption-typewriter"] = tl;
|
||||
tl.seek(0);
|
||||
window.__timelines["caption-highlight"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
|
||||
"name": "caption-highlight",
|
||||
"type": "hyperframes:component",
|
||||
"title": "Highlight",
|
||||
"description": "Red background sweep behind each active word, TikTok-style",
|
||||
"tags": ["captions", "caption-style", "highlight", "social", "tiktok"],
|
||||
"files": [
|
||||
{
|
||||
"path": "caption-highlight.html",
|
||||
"target": "compositions/components/caption-highlight.html",
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-highlight/preview.mp4"
|
||||
}
|
||||
@@ -181,16 +181,16 @@
|
||||
];
|
||||
|
||||
var GROUPS = [
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.05 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.05 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.6 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.5 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.4 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 4.75 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.4 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.2 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 6.75 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.8 },
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.35 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.35 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.9 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.8 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.7 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 5.0 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.7 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.5 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 7.05 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.9 },
|
||||
];
|
||||
|
||||
var container = document.getElementById("sc-container");
|
||||
@@ -248,10 +248,10 @@
|
||||
var scr1El = document.getElementById("sc-scr1-" + wi);
|
||||
|
||||
tl.set(scr0El, { display: "inline" }, w.start);
|
||||
tl.set(scr1El, { display: "inline" }, w.start + 0.05);
|
||||
tl.set(scr0El, { display: "none" }, w.start + 0.05);
|
||||
tl.set(realEl, { display: "inline" }, w.start + 0.1);
|
||||
tl.set(scr1El, { display: "none" }, w.start + 0.1);
|
||||
tl.set(scr1El, { display: "inline" }, w.start + 0.1);
|
||||
tl.set(scr0El, { display: "none" }, w.start + 0.1);
|
||||
tl.set(realEl, { display: "inline" }, w.start + 0.2);
|
||||
tl.set(scr1El, { display: "none" }, w.start + 0.2);
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
|
||||
|
||||
+14
-14
@@ -181,16 +181,16 @@
|
||||
];
|
||||
|
||||
var GROUPS = [
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.05 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.05 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.6 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.5 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.4 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 4.75 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.4 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.2 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 6.75 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.8 },
|
||||
{ wordStart: 0, wordEnd: 3, start: 0.0, end: 1.35 },
|
||||
{ wordStart: 4, wordEnd: 7, start: 1.1, end: 2.35 },
|
||||
{ wordStart: 8, wordEnd: 8, start: 2.1, end: 2.9 },
|
||||
{ wordStart: 9, wordEnd: 12, start: 2.65, end: 3.8 },
|
||||
{ wordStart: 13, wordEnd: 15, start: 3.55, end: 4.7 },
|
||||
{ wordStart: 16, wordEnd: 16, start: 3.95, end: 5.0 },
|
||||
{ wordStart: 17, wordEnd: 19, start: 4.9, end: 5.7 },
|
||||
{ wordStart: 20, wordEnd: 22, start: 5.65, end: 6.5 },
|
||||
{ wordStart: 23, wordEnd: 24, start: 6.35, end: 7.05 },
|
||||
{ wordStart: 25, wordEnd: 27, start: 6.8, end: 7.9 },
|
||||
];
|
||||
|
||||
var container = document.getElementById("sc-container");
|
||||
@@ -248,10 +248,10 @@
|
||||
var scr1El = document.getElementById("sc-scr1-" + wi);
|
||||
|
||||
tl.set(scr0El, { display: "inline" }, w.start);
|
||||
tl.set(scr1El, { display: "inline" }, w.start + 0.05);
|
||||
tl.set(scr0El, { display: "none" }, w.start + 0.05);
|
||||
tl.set(realEl, { display: "inline" }, w.start + 0.1);
|
||||
tl.set(scr1El, { display: "none" }, w.start + 0.1);
|
||||
tl.set(scr1El, { display: "inline" }, w.start + 0.1);
|
||||
tl.set(scr0El, { display: "none" }, w.start + 0.1);
|
||||
tl.set(realEl, { display: "inline" }, w.start + 0.2);
|
||||
tl.set(scr1El, { display: "none" }, w.start + 0.2);
|
||||
});
|
||||
|
||||
tl.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-matrix-decode/preview.mp4?v=1779051416"
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-matrix-decode/preview.mp4?v=1779060427"
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/registry-item.json",
|
||||
"name": "caption-typewriter",
|
||||
"type": "hyperframes:component",
|
||||
"title": "Typewriter",
|
||||
"description": "Green terminal character-by-character reveal with blinking cursor",
|
||||
"tags": ["captions", "caption-style", "terminal", "typewriter", "hacker"],
|
||||
"files": [
|
||||
{
|
||||
"path": "caption-typewriter.html",
|
||||
"target": "compositions/components/caption-typewriter.html",
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-typewriter/preview.mp4?v=1779051416"
|
||||
}
|
||||
@@ -59,7 +59,7 @@
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 1400px;
|
||||
height: 260px;
|
||||
height: 278px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -70,7 +70,7 @@
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 1400px;
|
||||
height: 260px;
|
||||
height: 278px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -224,7 +224,7 @@
|
||||
}
|
||||
|
||||
function splitLines(words) {
|
||||
if (measureLineWidth(words) <= MAX_LINE_WIDTH) {
|
||||
if (words.length < 2) {
|
||||
return [{ words: words, startIndex: 0 }];
|
||||
}
|
||||
var bestSplit = Math.ceil(words.length / 2);
|
||||
@@ -248,6 +248,35 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
function avoidSingleWordGroups(groups) {
|
||||
var out = [];
|
||||
groups.forEach(function (group) {
|
||||
if (
|
||||
group.words.length === 1 &&
|
||||
out.length > 0 &&
|
||||
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP
|
||||
) {
|
||||
out[out.length - 1] = makeGroup(out[out.length - 1].words.concat(group.words));
|
||||
} else {
|
||||
out.push(group);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < out.length; i++) {
|
||||
if (out[i].words.length !== 1) continue;
|
||||
if (i + 1 < out.length && out[i + 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
out[i] = makeGroup(out[i].words.concat(out[i + 1].words));
|
||||
out.splice(i + 1, 1);
|
||||
} else if (i > 0 && out[i - 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
out[i - 1] = makeGroup(out[i - 1].words.concat(out[i].words));
|
||||
out.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function makeGroups(words) {
|
||||
var groups = [];
|
||||
var current = [];
|
||||
@@ -273,7 +302,7 @@
|
||||
}
|
||||
});
|
||||
if (current.length) groups.push(makeGroup(current));
|
||||
return groups;
|
||||
return avoidSingleWordGroups(groups);
|
||||
}
|
||||
|
||||
function makeGroup(words) {
|
||||
@@ -311,9 +340,10 @@
|
||||
lineEl.id = "caption-group-" + groupIndex + "-line-" + lineIndex;
|
||||
lineEl.style.fontWeight = lineIndex === 0 ? FONT_WEIGHT_BOLD : FONT_WEIGHT_LIGHT;
|
||||
lineEl.style.fontSize = computedSize + "px";
|
||||
line.words.forEach(function (word) {
|
||||
line.words.forEach(function (word, wordIndex) {
|
||||
var wordEl = document.createElement("span");
|
||||
wordEl.textContent = word.text.toLowerCase();
|
||||
wordEl.style.display = "inline-block";
|
||||
lineEl.appendChild(wordEl);
|
||||
});
|
||||
copyEl.appendChild(lineEl);
|
||||
@@ -362,6 +392,7 @@
|
||||
var line2El = document.getElementById("caption-group-" + groupIndex + "-line-1");
|
||||
var line2FirstWord = group.lines[1].words[0];
|
||||
var switchTime = line2FirstWord.start;
|
||||
|
||||
tl.to(
|
||||
line1El,
|
||||
{ fontWeight: FONT_WEIGHT_LIGHT, duration: WEIGHT_TRANSITION, ease: "power2.out" },
|
||||
|
||||
+36
-5
@@ -59,7 +59,7 @@
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 1400px;
|
||||
height: 260px;
|
||||
height: 278px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -70,7 +70,7 @@
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 1400px;
|
||||
height: 260px;
|
||||
height: 278px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -224,7 +224,7 @@
|
||||
}
|
||||
|
||||
function splitLines(words) {
|
||||
if (measureLineWidth(words) <= MAX_LINE_WIDTH) {
|
||||
if (words.length < 2) {
|
||||
return [{ words: words, startIndex: 0 }];
|
||||
}
|
||||
var bestSplit = Math.ceil(words.length / 2);
|
||||
@@ -248,6 +248,35 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
function avoidSingleWordGroups(groups) {
|
||||
var out = [];
|
||||
groups.forEach(function (group) {
|
||||
if (
|
||||
group.words.length === 1 &&
|
||||
out.length > 0 &&
|
||||
out[out.length - 1].words.length < MAX_WORDS_PER_GROUP
|
||||
) {
|
||||
out[out.length - 1] = makeGroup(out[out.length - 1].words.concat(group.words));
|
||||
} else {
|
||||
out.push(group);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < out.length; i++) {
|
||||
if (out[i].words.length !== 1) continue;
|
||||
if (i + 1 < out.length && out[i + 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
out[i] = makeGroup(out[i].words.concat(out[i + 1].words));
|
||||
out.splice(i + 1, 1);
|
||||
} else if (i > 0 && out[i - 1].words.length < MAX_WORDS_PER_GROUP) {
|
||||
out[i - 1] = makeGroup(out[i - 1].words.concat(out[i].words));
|
||||
out.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function makeGroups(words) {
|
||||
var groups = [];
|
||||
var current = [];
|
||||
@@ -273,7 +302,7 @@
|
||||
}
|
||||
});
|
||||
if (current.length) groups.push(makeGroup(current));
|
||||
return groups;
|
||||
return avoidSingleWordGroups(groups);
|
||||
}
|
||||
|
||||
function makeGroup(words) {
|
||||
@@ -311,9 +340,10 @@
|
||||
lineEl.id = "caption-group-" + groupIndex + "-line-" + lineIndex;
|
||||
lineEl.style.fontWeight = lineIndex === 0 ? FONT_WEIGHT_BOLD : FONT_WEIGHT_LIGHT;
|
||||
lineEl.style.fontSize = computedSize + "px";
|
||||
line.words.forEach(function (word) {
|
||||
line.words.forEach(function (word, wordIndex) {
|
||||
var wordEl = document.createElement("span");
|
||||
wordEl.textContent = word.text.toLowerCase();
|
||||
wordEl.style.display = "inline-block";
|
||||
lineEl.appendChild(wordEl);
|
||||
});
|
||||
copyEl.appendChild(lineEl);
|
||||
@@ -362,6 +392,7 @@
|
||||
var line2El = document.getElementById("caption-group-" + groupIndex + "-line-1");
|
||||
var line2FirstWord = group.lines[1].words[0];
|
||||
var switchTime = line2FirstWord.start;
|
||||
|
||||
tl.to(
|
||||
line1El,
|
||||
{ fontWeight: FONT_WEIGHT_LIGHT, duration: WEIGHT_TRANSITION, ease: "power2.out" },
|
||||
|
||||
@@ -12,5 +12,5 @@
|
||||
"type": "hyperframes:snippet"
|
||||
}
|
||||
],
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-weight-shift/preview.mp4?v=1779051416"
|
||||
"preview": "https://static.heygen.ai/hyperframes-oss/registry/components/caption-weight-shift/preview.mp4?v=1779065047"
|
||||
}
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
"name": "caption-glitch-rgb",
|
||||
"type": "hyperframes:component"
|
||||
},
|
||||
{
|
||||
"name": "caption-typewriter",
|
||||
"type": "hyperframes:component"
|
||||
},
|
||||
{
|
||||
"name": "caption-matrix-decode",
|
||||
"type": "hyperframes:component"
|
||||
@@ -127,6 +123,10 @@
|
||||
"name": "caption-neon-glow",
|
||||
"type": "hyperframes:component"
|
||||
},
|
||||
{
|
||||
"name": "caption-highlight",
|
||||
"type": "hyperframes:component"
|
||||
},
|
||||
{
|
||||
"name": "instagram-follow",
|
||||
"type": "hyperframes:block"
|
||||
|
||||
Reference in New Issue
Block a user