style: format caption component files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Miguel Ángel
2026-05-17 19:59:43 +00:00
co-authored by Claude Sonnet 4.6
parent 78ddd2602b
commit a19a772dc5
30 changed files with 4548 additions and 2758 deletions
+171 -110
View File
@@ -6,42 +6,75 @@
<title>Clip Wipe</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=Poppins:wght@800&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@800&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#clip-wipe {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#wp-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.wp-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#wp-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.wp-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
visibility: hidden;
}
.wp-word {
font-family: 'Poppins', sans-serif;
font-weight: 800; font-size: 88px;
font-family: "Poppins", sans-serif;
font-weight: 800;
font-size: 88px;
text-transform: uppercase;
color: #ffffff;
display: inline-block; letter-spacing: 0.04em; line-height: 1;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
clip-path: inset(0 100% 0 0);
will-change: clip-path, color, opacity;
}
@@ -57,114 +90,142 @@
data-width="1920"
data-height="1080"
>
<video id="wp-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="wp-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="wp-overlay"></div>
<div id="wp-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var container = document.getElementById('wp-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 = 'wp-group';
grp.id = 'wp-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'wp-word';
span.id = 'wp-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = '88px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
var container = document.getElementById("wp-container");
var tl = gsap.timeline({ paused: true });
tl.set(grp, { visibility: 'visible' }, g.start);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "wp-group";
grp.id = "wp-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('wp-w-' + wi);
var isKW = KEYWORDS.has(wi);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "wp-word";
span.id = "wp-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = "88px";
grp.appendChild(span);
});
tl.to(wordEl, { clipPath: 'inset(0 0% 0 0)', duration: 0.15, ease: 'power3.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);
container.appendChild(grp);
tl.set(grp, { visibility: "visible" }, g.start);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById("wp-w-" + wi);
var isKW = KEYWORDS.has(wi);
tl.to(
wordEl,
{ clipPath: "inset(0 0% 0 0)", duration: 0.15, ease: "power3.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);
});
var wordEls = grp.querySelectorAll(".wp-word");
tl.to(
wordEls,
{
clipPath: "inset(0 0% 0 100%)",
duration: 0.14,
stagger: 0.04,
ease: "power2.in",
},
g.end - 0.2,
);
tl.set(grp, { visibility: "hidden", opacity: 0 }, g.end);
});
var wordEls = grp.querySelectorAll('.wp-word');
tl.to(wordEls, {
clipPath: 'inset(0 0% 0 100%)',
duration: 0.14, stagger: 0.04, ease: 'power2.in'
}, g.end - 0.2);
tl.set(grp, { visibility: 'hidden', opacity: 0 }, g.end);
});
tl.seek(0);
window.__timelines['clip-wipe'] = tl;
})();
tl.seek(0);
window.__timelines["clip-wipe"] = tl;
})();
</script>
</body>
</html>
+171 -110
View File
@@ -6,42 +6,75 @@
<title>Clip Wipe</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=Poppins:wght@800&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@800&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#clip-wipe {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#wp-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.wp-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#wp-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.wp-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
visibility: hidden;
}
.wp-word {
font-family: 'Poppins', sans-serif;
font-weight: 800; font-size: 88px;
font-family: "Poppins", sans-serif;
font-weight: 800;
font-size: 88px;
text-transform: uppercase;
color: #ffffff;
display: inline-block; letter-spacing: 0.04em; line-height: 1;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
clip-path: inset(0 100% 0 0);
will-change: clip-path, color, opacity;
}
@@ -57,114 +90,142 @@
data-width="1920"
data-height="1080"
>
<video id="wp-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="wp-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="wp-overlay"></div>
<div id="wp-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var container = document.getElementById('wp-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 = 'wp-group';
grp.id = 'wp-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'wp-word';
span.id = 'wp-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = '88px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
var container = document.getElementById("wp-container");
var tl = gsap.timeline({ paused: true });
tl.set(grp, { visibility: 'visible' }, g.start);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "wp-group";
grp.id = "wp-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('wp-w-' + wi);
var isKW = KEYWORDS.has(wi);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "wp-word";
span.id = "wp-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = "88px";
grp.appendChild(span);
});
tl.to(wordEl, { clipPath: 'inset(0 0% 0 0)', duration: 0.15, ease: 'power3.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);
container.appendChild(grp);
tl.set(grp, { visibility: "visible" }, g.start);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById("wp-w-" + wi);
var isKW = KEYWORDS.has(wi);
tl.to(
wordEl,
{ clipPath: "inset(0 0% 0 0)", duration: 0.15, ease: "power3.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);
});
var wordEls = grp.querySelectorAll(".wp-word");
tl.to(
wordEls,
{
clipPath: "inset(0 0% 0 100%)",
duration: 0.14,
stagger: 0.04,
ease: "power2.in",
},
g.end - 0.2,
);
tl.set(grp, { visibility: "hidden", opacity: 0 }, g.end);
});
var wordEls = grp.querySelectorAll('.wp-word');
tl.to(wordEls, {
clipPath: 'inset(0 0% 0 100%)',
duration: 0.14, stagger: 0.04, ease: 'power2.in'
}, g.end - 0.2);
tl.set(grp, { visibility: 'hidden', opacity: 0 }, g.end);
});
tl.seek(0);
window.__timelines['clip-wipe'] = tl;
})();
tl.seek(0);
window.__timelines["clip-wipe"] = tl;
})();
</script>
</body>
</html>
@@ -6,7 +6,10 @@
<title>Editorial Emphasis</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400&family=Playfair+Display:ital,wght@0,800;1,800&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400&family=Playfair+Display:ital,wght@0,800;1,800&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -85,8 +88,10 @@
.word {
display: inline-block;
color: #F5F0D0;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #f5f0d0;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
will-change: transform, opacity;
backface-visibility: hidden;
}
@@ -111,7 +116,7 @@
font-weight: 800;
font-style: italic;
line-height: 0.9;
color: #F5F0D0;
color: #f5f0d0;
}
</style>
</head>
@@ -149,49 +154,108 @@
// Generic transcript words
var W = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// Block layout: [wordIndex, type] — n=normal, i=italic, e=emphasis(large)
// Emphasis words: HyperFrames(8), HTML(12), professional(15), code(24), cinema.(27)
var BLOCKS = [
{ line1: [[0,"n"],[1,"n"],[2,"n"]], line2: [[3,"n"],[4,"n"]] },
{ line1: [[5,"n"],[6,"n"]], line2: [[7,"e"]] },
{ line1: [[8,"e"]], line2: null },
{ line1: [[9,"n"],[10,"n"],[11,"n"]], line2: [[12,"e"]] },
{ line1: [[13,"n"],[14,"n"]], line2: [[15,"e"]] },
{ line1: [[16,"n"],[17,"n"]], line2: null },
{ line1: [[18,"n"]], line2: [[19,"n"],[20,"n"]] },
{ line1: [[21,"n"],[22,"n"]], line2: null },
{ line1: [[23,"i"],[24,"e"]], line2: null },
{ line1: [[25,"n"],[26,"n"]], line2: [[27,"e"]] },
{
line1: [
[0, "n"],
[1, "n"],
[2, "n"],
],
line2: [
[3, "n"],
[4, "n"],
],
},
{
line1: [
[5, "n"],
[6, "n"],
],
line2: [[7, "e"]],
},
{ line1: [[8, "e"]], line2: null },
{
line1: [
[9, "n"],
[10, "n"],
[11, "n"],
],
line2: [[12, "e"]],
},
{
line1: [
[13, "n"],
[14, "n"],
],
line2: [[15, "e"]],
},
{
line1: [
[16, "n"],
[17, "n"],
],
line2: null,
},
{
line1: [[18, "n"]],
line2: [
[19, "n"],
[20, "n"],
],
},
{
line1: [
[21, "n"],
[22, "n"],
],
line2: null,
},
{
line1: [
[23, "i"],
[24, "e"],
],
line2: null,
},
{
line1: [
[25, "n"],
[26, "n"],
],
line2: [[27, "e"]],
},
];
var CLASS_MAP = { n: "word word--normal", i: "word word--italic", e: "word word--emphasis" };
@@ -243,7 +307,9 @@
el.style.position = "relative";
var lines = el.querySelectorAll(".caption-line");
var maxW = 0;
lines.forEach(function (line) { if (line.scrollWidth > maxW) maxW = line.scrollWidth; });
lines.forEach(function (line) {
if (line.scrollWidth > maxW) maxW = line.scrollWidth;
});
if (maxW > SAFE_WIDTH) {
var s = SAFE_WIDTH / maxW;
el.style.transform = "scale(" + s + ")";
@@ -256,27 +322,39 @@
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
var allEls = BLOCKS.map(function (_, i) { return document.getElementById("b" + i); });
var allEls = BLOCKS.map(function (_, i) {
return document.getElementById("b" + i);
});
function blockStart(bi) { return W[BLOCKS[bi].line1[0][0]].start; }
function blockStart(bi) {
return W[BLOCKS[bi].line1[0][0]].start;
}
BLOCKS.forEach(function (block, bi) {
var el = allEls[bi];
var start = blockStart(bi);
var nextStart = bi < BLOCKS.length - 1 ? blockStart(bi + 1) : DURATION;
allEls.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allEls.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
tl.set(el, { opacity: 1 }, start);
block.line1.forEach(function (pair, wi) {
var wordEl = document.getElementById("b" + bi + "L1w" + wi);
var wordStart = W[pair[0]].start;
tl.set(wordEl, { opacity: 0, scale: 1.12, transformOrigin: "0% 100%" }, start);
tl.to(wordEl, { opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" }, wordStart);
tl.to(
wordEl,
{ opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" },
wordStart,
);
});
if (block.line2) {
var hasEmphasis = block.line2.some(function (p) { return p[1] === "e"; });
var hasEmphasis = block.line2.some(function (p) {
return p[1] === "e";
});
var l2El = document.getElementById("b" + bi + "L2");
if (hasEmphasis) {
var l2Start = W[block.line2[0][0]].start;
@@ -288,7 +366,11 @@
var wordEl = document.getElementById("b" + bi + "L2w" + wi);
var wordStart = W[pair[0]].start;
tl.set(wordEl, { opacity: 0, scale: 1.12, transformOrigin: "0% 100%" }, start);
tl.to(wordEl, { opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" }, wordStart);
tl.to(
wordEl,
{ opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" },
wordStart,
);
});
}
}
+131 -49
View File
@@ -6,7 +6,10 @@
<title>Editorial Emphasis</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400&family=Playfair+Display:ital,wght@0,800;1,800&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400&family=Playfair+Display:ital,wght@0,800;1,800&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -85,8 +88,10 @@
.word {
display: inline-block;
color: #F5F0D0;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #f5f0d0;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
will-change: transform, opacity;
backface-visibility: hidden;
}
@@ -111,7 +116,7 @@
font-weight: 800;
font-style: italic;
line-height: 0.9;
color: #F5F0D0;
color: #f5f0d0;
}
</style>
</head>
@@ -149,49 +154,108 @@
// Generic transcript words
var W = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// Block layout: [wordIndex, type] — n=normal, i=italic, e=emphasis(large)
// Emphasis words: HyperFrames(8), HTML(12), professional(15), code(24), cinema.(27)
var BLOCKS = [
{ line1: [[0,"n"],[1,"n"],[2,"n"]], line2: [[3,"n"],[4,"n"]] },
{ line1: [[5,"n"],[6,"n"]], line2: [[7,"e"]] },
{ line1: [[8,"e"]], line2: null },
{ line1: [[9,"n"],[10,"n"],[11,"n"]], line2: [[12,"e"]] },
{ line1: [[13,"n"],[14,"n"]], line2: [[15,"e"]] },
{ line1: [[16,"n"],[17,"n"]], line2: null },
{ line1: [[18,"n"]], line2: [[19,"n"],[20,"n"]] },
{ line1: [[21,"n"],[22,"n"]], line2: null },
{ line1: [[23,"i"],[24,"e"]], line2: null },
{ line1: [[25,"n"],[26,"n"]], line2: [[27,"e"]] },
{
line1: [
[0, "n"],
[1, "n"],
[2, "n"],
],
line2: [
[3, "n"],
[4, "n"],
],
},
{
line1: [
[5, "n"],
[6, "n"],
],
line2: [[7, "e"]],
},
{ line1: [[8, "e"]], line2: null },
{
line1: [
[9, "n"],
[10, "n"],
[11, "n"],
],
line2: [[12, "e"]],
},
{
line1: [
[13, "n"],
[14, "n"],
],
line2: [[15, "e"]],
},
{
line1: [
[16, "n"],
[17, "n"],
],
line2: null,
},
{
line1: [[18, "n"]],
line2: [
[19, "n"],
[20, "n"],
],
},
{
line1: [
[21, "n"],
[22, "n"],
],
line2: null,
},
{
line1: [
[23, "i"],
[24, "e"],
],
line2: null,
},
{
line1: [
[25, "n"],
[26, "n"],
],
line2: [[27, "e"]],
},
];
var CLASS_MAP = { n: "word word--normal", i: "word word--italic", e: "word word--emphasis" };
@@ -243,7 +307,9 @@
el.style.position = "relative";
var lines = el.querySelectorAll(".caption-line");
var maxW = 0;
lines.forEach(function (line) { if (line.scrollWidth > maxW) maxW = line.scrollWidth; });
lines.forEach(function (line) {
if (line.scrollWidth > maxW) maxW = line.scrollWidth;
});
if (maxW > SAFE_WIDTH) {
var s = SAFE_WIDTH / maxW;
el.style.transform = "scale(" + s + ")";
@@ -256,27 +322,39 @@
window.__timelines = window.__timelines || {};
var tl = gsap.timeline({ paused: true });
var allEls = BLOCKS.map(function (_, i) { return document.getElementById("b" + i); });
var allEls = BLOCKS.map(function (_, i) {
return document.getElementById("b" + i);
});
function blockStart(bi) { return W[BLOCKS[bi].line1[0][0]].start; }
function blockStart(bi) {
return W[BLOCKS[bi].line1[0][0]].start;
}
BLOCKS.forEach(function (block, bi) {
var el = allEls[bi];
var start = blockStart(bi);
var nextStart = bi < BLOCKS.length - 1 ? blockStart(bi + 1) : DURATION;
allEls.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allEls.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
tl.set(el, { opacity: 1 }, start);
block.line1.forEach(function (pair, wi) {
var wordEl = document.getElementById("b" + bi + "L1w" + wi);
var wordStart = W[pair[0]].start;
tl.set(wordEl, { opacity: 0, scale: 1.12, transformOrigin: "0% 100%" }, start);
tl.to(wordEl, { opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" }, wordStart);
tl.to(
wordEl,
{ opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" },
wordStart,
);
});
if (block.line2) {
var hasEmphasis = block.line2.some(function (p) { return p[1] === "e"; });
var hasEmphasis = block.line2.some(function (p) {
return p[1] === "e";
});
var l2El = document.getElementById("b" + bi + "L2");
if (hasEmphasis) {
var l2Start = W[block.line2[0][0]].start;
@@ -288,7 +366,11 @@
var wordEl = document.getElementById("b" + bi + "L2w" + wi);
var wordStart = W[pair[0]].start;
tl.set(wordEl, { opacity: 0, scale: 1.12, transformOrigin: "0% 100%" }, start);
tl.to(wordEl, { opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" }, wordStart);
tl.to(
wordEl,
{ opacity: 1, scale: 1, duration: ENTRY_DUR, ease: "power2.out" },
wordStart,
);
});
}
}
+150 -59
View File
@@ -6,7 +6,10 @@
<title>Emoji Pop</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=Gabarito:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Gabarito:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -155,67 +158,117 @@
var ACCENT_COLORS = ["#FF76FF", "#FF0002", "#B2F7FF"];
var KEYWORDS = new Set(["hyperframes", "html", "professional", "code", "cinema"]);
var TRANSITION_WORDS = new Set([
"the", "a", "an", "and", "or", "but", "is", "are", "was", "were",
"to", "of", "in", "on", "at", "for", "with", "by", "from", "as",
"it", "its", "this", "that", "these", "those", "be", "been",
"have", "has", "had", "do", "does", "did", "will", "would", "could",
"should", "may", "might", "must", "can", "if", "then", "so", "just",
"not", "no", "yes", "up", "out", "about"
"the",
"a",
"an",
"and",
"or",
"but",
"is",
"are",
"was",
"were",
"to",
"of",
"in",
"on",
"at",
"for",
"with",
"by",
"from",
"as",
"it",
"its",
"this",
"that",
"these",
"those",
"be",
"been",
"have",
"has",
"had",
"do",
"does",
"did",
"will",
"would",
"could",
"should",
"may",
"might",
"must",
"can",
"if",
"then",
"so",
"just",
"not",
"no",
"yes",
"up",
"out",
"about",
]);
// Emoji map for key words
var WORD_EMOJI = {
"hyperframes": "🎬",
"html": "💻",
"professional": "✨",
"code": "⌨️",
"cinema": "🎥",
"video": "📹",
"frame": "🖼️"
hyperframes: "🎬",
html: "💻",
professional: "✨",
code: "⌨️",
cinema: "🎥",
video: "📹",
frame: "🖼️",
};
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
var text = String(item.word || item.text || "").trim();
var clean = text.toLowerCase().replace(/[^a-z]/g, "");
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
emoji: WORD_EMOJI[clean] || null,
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
var text = String(item.word || item.text || "").trim();
var clean = text.toLowerCase().replace(/[^a-z]/g, "");
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
emoji: WORD_EMOJI[clean] || null,
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
function seededRandom(seed) {
@@ -272,7 +325,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current, groups.length));
current = [];
}
@@ -285,9 +343,18 @@
var colors = assignWordColors(words, groupIndex);
var emoji = null;
for (var i = 0; i < words.length; i++) {
if (words[i].emoji) { emoji = words[i].emoji; break; }
if (words[i].emoji) {
emoji = words[i].emoji;
break;
}
}
return { words: words.slice(), colors: colors, emoji: emoji, start: words[0].start, end: words[words.length - 1].end };
return {
words: words.slice(),
colors: colors,
emoji: emoji,
start: words[0].start,
end: words[words.length - 1].end,
};
}
function shadowForColor(color) {
@@ -295,7 +362,21 @@
var r = parseInt(hex.slice(0, 2), 16);
var g = parseInt(hex.slice(2, 4), 16);
var b = parseInt(hex.slice(4, 6), 16);
return "0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" + r + "," + g + "," + b + ",1), 0 0 8px rgba(" + r + "," + g + "," + b + ",0.6)";
return (
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" +
r +
"," +
g +
"," +
b +
",1), 0 0 8px rgba(" +
r +
"," +
g +
"," +
b +
",0.6)"
);
}
function buildCaptions(groups) {
@@ -343,7 +424,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -356,8 +439,16 @@
});
tl.set(groupEl, { opacity: 0, scaleX: 0.8, scaleY: 1 }, visibleStart);
tl.to(groupEl, { opacity: 1, scaleX: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(groupEl, { scaleX: 0.75, opacity: 0.8, duration: EXIT_DURATION, ease: "power2.in", force3D: true }, exitStart);
tl.to(
groupEl,
{ opacity: 1, scaleX: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
tl.to(
groupEl,
{ scaleX: 0.75, opacity: 0.8, duration: EXIT_DURATION, ease: "power2.in", force3D: true },
exitStart,
);
tl.set(groupEl, { opacity: 0 }, visibleEnd);
});
+150 -59
View File
@@ -6,7 +6,10 @@
<title>Emoji Pop</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=Gabarito:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Gabarito:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -155,67 +158,117 @@
var ACCENT_COLORS = ["#FF76FF", "#FF0002", "#B2F7FF"];
var KEYWORDS = new Set(["hyperframes", "html", "professional", "code", "cinema"]);
var TRANSITION_WORDS = new Set([
"the", "a", "an", "and", "or", "but", "is", "are", "was", "were",
"to", "of", "in", "on", "at", "for", "with", "by", "from", "as",
"it", "its", "this", "that", "these", "those", "be", "been",
"have", "has", "had", "do", "does", "did", "will", "would", "could",
"should", "may", "might", "must", "can", "if", "then", "so", "just",
"not", "no", "yes", "up", "out", "about"
"the",
"a",
"an",
"and",
"or",
"but",
"is",
"are",
"was",
"were",
"to",
"of",
"in",
"on",
"at",
"for",
"with",
"by",
"from",
"as",
"it",
"its",
"this",
"that",
"these",
"those",
"be",
"been",
"have",
"has",
"had",
"do",
"does",
"did",
"will",
"would",
"could",
"should",
"may",
"might",
"must",
"can",
"if",
"then",
"so",
"just",
"not",
"no",
"yes",
"up",
"out",
"about",
]);
// Emoji map for key words
var WORD_EMOJI = {
"hyperframes": "🎬",
"html": "💻",
"professional": "✨",
"code": "⌨️",
"cinema": "🎥",
"video": "📹",
"frame": "🖼️"
hyperframes: "🎬",
html: "💻",
professional: "✨",
code: "⌨️",
cinema: "🎥",
video: "📹",
frame: "🖼️",
};
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
var text = String(item.word || item.text || "").trim();
var clean = text.toLowerCase().replace(/[^a-z]/g, "");
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
emoji: WORD_EMOJI[clean] || null,
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
var text = String(item.word || item.text || "").trim();
var clean = text.toLowerCase().replace(/[^a-z]/g, "");
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
emoji: WORD_EMOJI[clean] || null,
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
function seededRandom(seed) {
@@ -272,7 +325,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current, groups.length));
current = [];
}
@@ -285,9 +343,18 @@
var colors = assignWordColors(words, groupIndex);
var emoji = null;
for (var i = 0; i < words.length; i++) {
if (words[i].emoji) { emoji = words[i].emoji; break; }
if (words[i].emoji) {
emoji = words[i].emoji;
break;
}
}
return { words: words.slice(), colors: colors, emoji: emoji, start: words[0].start, end: words[words.length - 1].end };
return {
words: words.slice(),
colors: colors,
emoji: emoji,
start: words[0].start,
end: words[words.length - 1].end,
};
}
function shadowForColor(color) {
@@ -295,7 +362,21 @@
var r = parseInt(hex.slice(0, 2), 16);
var g = parseInt(hex.slice(2, 4), 16);
var b = parseInt(hex.slice(4, 6), 16);
return "0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" + r + "," + g + "," + b + ",1), 0 0 8px rgba(" + r + "," + g + "," + b + ",0.6)";
return (
"0 4px 8px rgba(0,0,0,0.7), 0 0 2px rgba(" +
r +
"," +
g +
"," +
b +
",1), 0 0 8px rgba(" +
r +
"," +
g +
"," +
b +
",0.6)"
);
}
function buildCaptions(groups) {
@@ -343,7 +424,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -356,8 +439,16 @@
});
tl.set(groupEl, { opacity: 0, scaleX: 0.8, scaleY: 1 }, visibleStart);
tl.to(groupEl, { opacity: 1, scaleX: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(groupEl, { scaleX: 0.75, opacity: 0.8, duration: EXIT_DURATION, ease: "power2.in", force3D: true }, exitStart);
tl.to(
groupEl,
{ opacity: 1, scaleX: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
tl.to(
groupEl,
{ scaleX: 0.75, opacity: 0.8, duration: EXIT_DURATION, ease: "power2.in", force3D: true },
exitStart,
);
tl.set(groupEl, { opacity: 0 }, visibleEnd);
});
+229 -124
View File
@@ -6,50 +6,89 @@
<title>Glitch RGB</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=Space+Grotesk:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#glitch-rgb {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#gl-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.gl-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
.gl-scanlines {
position: absolute; inset: 0; z-index: 5; pointer-events: none;
position: absolute;
inset: 0;
z-index: 5;
pointer-events: none;
background: repeating-linear-gradient(
to bottom,
transparent 0px, transparent 3px,
rgba(0,0,0,0.08) 3px, rgba(0,0,0,0.08) 4px
transparent 0px,
transparent 3px,
rgba(0, 0, 0, 0.08) 3px,
rgba(0, 0, 0, 0.08) 4px
);
}
#gl-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.gl-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
opacity: 0;
visibility: hidden;
}
.gl-word {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700; font-size: 88px;
font-family: "Space Grotesk", sans-serif;
font-weight: 700;
font-size: 88px;
text-transform: uppercase;
color: rgba(180,230,255,0.45);
display: inline-block; letter-spacing: 0.05em; line-height: 1;
color: rgba(180, 230, 255, 0.45);
display: inline-block;
letter-spacing: 0.05em;
line-height: 1;
will-change: transform, text-shadow, color;
}
</style>
@@ -64,124 +103,190 @@
data-width="1920"
data-height="1080"
>
<video id="gl-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="gl-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="gl-overlay"></div>
<div class="gl-scanlines"></div>
<div id="gl-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ 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.
// Keywords get white + glow on activation
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var BASE_FONT = 88;
var container = document.getElementById('gl-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 = 'gl-group';
grp.id = 'gl-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'gl-word';
span.id = 'gl-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = BASE_FONT + 'px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
var BASE_FONT = 88;
var container = document.getElementById("gl-container");
var tl = gsap.timeline({ paused: true });
tl.set(grp, { visibility: 'visible' }, g.start);
tl.fromTo(grp,
{ opacity: 0, x: -8 },
{ opacity: 1, x: 0, duration: 0.18, ease: 'power3.out' },
g.start
);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "gl-group";
grp.id = "gl-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('gl-w-' + wi);
var isKW = KEYWORDS.has(wi);
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 sm = shadowMag.toFixed(1);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "gl-word";
span.id = "gl-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = BASE_FONT + "px";
grp.appendChild(span);
});
tl.to(wordEl, { x: j1, color: '#ffffff', textShadow: sm + 'px 0 #ff003c, -' + sm + 'px 0 #00e5ff', duration: 0.045, 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' }, w.start + 0.113);
tl.to(wordEl, { color: 'rgba(180,230,255,0.4)', textShadow: 'none', duration: 0.12 }, w.end);
container.appendChild(grp);
tl.set(grp, { visibility: "visible" }, g.start);
tl.fromTo(
grp,
{ opacity: 0, x: -8 },
{ opacity: 1, x: 0, duration: 0.18, ease: "power3.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 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 sm = shadowMag.toFixed(1);
tl.to(
wordEl,
{
x: j1,
color: "#ffffff",
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
duration: 0.045,
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",
},
w.start + 0.113,
);
tl.to(
wordEl,
{ color: "rgba(180,230,255,0.4)", textShadow: "none", duration: 0.12 },
w.end,
);
});
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
tl.seek(0);
window.__timelines['glitch-rgb'] = tl;
})();
tl.seek(0);
window.__timelines["glitch-rgb"] = tl;
})();
</script>
</body>
</html>
+229 -124
View File
@@ -6,50 +6,89 @@
<title>Glitch RGB</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=Space+Grotesk:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#glitch-rgb {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#gl-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.gl-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
.gl-scanlines {
position: absolute; inset: 0; z-index: 5; pointer-events: none;
position: absolute;
inset: 0;
z-index: 5;
pointer-events: none;
background: repeating-linear-gradient(
to bottom,
transparent 0px, transparent 3px,
rgba(0,0,0,0.08) 3px, rgba(0,0,0,0.08) 4px
transparent 0px,
transparent 3px,
rgba(0, 0, 0, 0.08) 3px,
rgba(0, 0, 0, 0.08) 4px
);
}
#gl-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.gl-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
opacity: 0;
visibility: hidden;
}
.gl-word {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700; font-size: 88px;
font-family: "Space Grotesk", sans-serif;
font-weight: 700;
font-size: 88px;
text-transform: uppercase;
color: rgba(180,230,255,0.45);
display: inline-block; letter-spacing: 0.05em; line-height: 1;
color: rgba(180, 230, 255, 0.45);
display: inline-block;
letter-spacing: 0.05em;
line-height: 1;
will-change: transform, text-shadow, color;
}
</style>
@@ -64,124 +103,190 @@
data-width="1920"
data-height="1080"
>
<video id="gl-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="gl-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="gl-overlay"></div>
<div class="gl-scanlines"></div>
<div id="gl-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ 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.
// Keywords get white + glow on activation
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var BASE_FONT = 88;
var container = document.getElementById('gl-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 = 'gl-group';
grp.id = 'gl-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'gl-word';
span.id = 'gl-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = BASE_FONT + 'px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
var BASE_FONT = 88;
var container = document.getElementById("gl-container");
var tl = gsap.timeline({ paused: true });
tl.set(grp, { visibility: 'visible' }, g.start);
tl.fromTo(grp,
{ opacity: 0, x: -8 },
{ opacity: 1, x: 0, duration: 0.18, ease: 'power3.out' },
g.start
);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "gl-group";
grp.id = "gl-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('gl-w-' + wi);
var isKW = KEYWORDS.has(wi);
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 sm = shadowMag.toFixed(1);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "gl-word";
span.id = "gl-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = BASE_FONT + "px";
grp.appendChild(span);
});
tl.to(wordEl, { x: j1, color: '#ffffff', textShadow: sm + 'px 0 #ff003c, -' + sm + 'px 0 #00e5ff', duration: 0.045, 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' }, w.start + 0.113);
tl.to(wordEl, { color: 'rgba(180,230,255,0.4)', textShadow: 'none', duration: 0.12 }, w.end);
container.appendChild(grp);
tl.set(grp, { visibility: "visible" }, g.start);
tl.fromTo(
grp,
{ opacity: 0, x: -8 },
{ opacity: 1, x: 0, duration: 0.18, ease: "power3.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 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 sm = shadowMag.toFixed(1);
tl.to(
wordEl,
{
x: j1,
color: "#ffffff",
textShadow: sm + "px 0 #ff003c, -" + sm + "px 0 #00e5ff",
duration: 0.045,
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",
},
w.start + 0.113,
);
tl.to(
wordEl,
{ color: "rgba(180,230,255,0.4)", textShadow: "none", duration: 0.12 },
w.end,
);
});
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.to(grp, { opacity: 0, x: 8, duration: 0.15 }, g.end - 0.15);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
tl.seek(0);
window.__timelines['glitch-rgb'] = tl;
})();
tl.seek(0);
window.__timelines["glitch-rgb"] = tl;
})();
</script>
</body>
</html>
@@ -6,40 +6,74 @@
<title>Gradient Fill</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=Nunito:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#gradient-fill {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#gr-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.gr-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.42); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.42);
z-index: 1;
pointer-events: none;
}
#gr-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.gr-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.gr-word {
font-family: 'Nunito', sans-serif;
font-weight: 900; font-size: 100px;
display: inline-block; letter-spacing: 0.04em; line-height: 1;
font-family: "Nunito", sans-serif;
font-weight: 900;
font-size: 100px;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -57,131 +91,139 @@
data-width="1920"
data-height="1080"
>
<video id="gr-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="gr-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="gr-overlay"></div>
<div id="gr-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
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},
];
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 },
];
// Enhanced gradient palette with accent for keywords
var GRADS = [
"linear-gradient(135deg,#FF6B6B,#FFD700)",
"linear-gradient(135deg,#4ADE80,#22D3EE)",
"linear-gradient(135deg,#818CF8,#E879F9)",
"linear-gradient(135deg,#FFD700,#FF6B35)",
"linear-gradient(135deg,#22D3EE,#4ADE80)",
"linear-gradient(135deg,#E879F9,#818CF8)",
"linear-gradient(135deg,#FF3366,#FF6B35)"
];
var KEYWORD_GRADS = {
8: "linear-gradient(135deg,#FF6B6B,#FFD700,#FF6B6B)", // HyperFrames
12: "linear-gradient(135deg,#22D3EE,#ffffff,#22D3EE)", // HTML
15: "linear-gradient(135deg,#818CF8,#E879F9,#818CF8)", // professional
24: "linear-gradient(135deg,#00F5D4,#22D3EE,#00F5D4)", // code
27: "linear-gradient(135deg,#FFD700,#FF6B35,#FFD700)" // cinema.
};
// Enhanced gradient palette with accent for keywords
var GRADS = [
"linear-gradient(135deg,#FF6B6B,#FFD700)",
"linear-gradient(135deg,#4ADE80,#22D3EE)",
"linear-gradient(135deg,#818CF8,#E879F9)",
"linear-gradient(135deg,#FFD700,#FF6B35)",
"linear-gradient(135deg,#22D3EE,#4ADE80)",
"linear-gradient(135deg,#E879F9,#818CF8)",
"linear-gradient(135deg,#FF3366,#FF6B35)",
];
var KEYWORD_GRADS = {
8: "linear-gradient(135deg,#FF6B6B,#FFD700,#FF6B6B)", // HyperFrames
12: "linear-gradient(135deg,#22D3EE,#ffffff,#22D3EE)", // HTML
15: "linear-gradient(135deg,#818CF8,#E879F9,#818CF8)", // professional
24: "linear-gradient(135deg,#00F5D4,#22D3EE,#00F5D4)", // code
27: "linear-gradient(135deg,#FFD700,#FF6B35,#FFD700)", // cinema.
};
var container = document.getElementById('gr-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("gr-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 = 'gr-group';
grp.id = 'gr-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "gr-group";
grp.id = "gr-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'gr-word';
span.id = 'gr-w-' + wi;
span.textContent = w.text;
span.style.fontSize = '100px';
var grad = KEYWORD_GRADS[wi] || GRADS[wi % 7];
span.style.background = grad;
span.style.webkitBackgroundClip = 'text';
span.style.backgroundClip = 'text';
span.style.color = 'transparent';
grp.appendChild(span);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "gr-word";
span.id = "gr-w-" + wi;
span.textContent = w.text;
span.style.fontSize = "100px";
var grad = KEYWORD_GRADS[wi] || GRADS[wi % 7];
span.style.background = grad;
span.style.webkitBackgroundClip = "text";
span.style.backgroundClip = "text";
span.style.color = "transparent";
grp.appendChild(span);
});
container.appendChild(grp);
var gs = g.start;
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var el = document.getElementById("gr-w-" + wi);
tl.set(el, { opacity: 0, y: 55, scale: 0.35 }, gs);
tl.fromTo(
el,
{ y: 55, scale: 0.35, opacity: 0 },
{ y: 0, scale: 1, opacity: 0.35, duration: 0.55, ease: "elastic.out(1.6,0.4)" },
gs + i * 0.05,
);
});
tl.set(grp, { visibility: "visible", opacity: 1 }, gs);
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(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
var gs = g.start;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var el = document.getElementById('gr-w-' + wi);
tl.set(el, { opacity: 0, y: 55, scale: 0.35 }, gs);
tl.fromTo(el,
{ y: 55, scale: 0.35, opacity: 0 },
{ y: 0, scale: 1, opacity: 0.35, duration: 0.55, ease: 'elastic.out(1.6,0.4)' },
gs + i * 0.05
);
});
tl.set(grp, { visibility: 'visible', opacity: 1 }, gs);
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(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['gradient-fill'] = tl;
})();
window.__timelines["gradient-fill"] = tl;
})();
</script>
</body>
</html>
+173 -131
View File
@@ -6,40 +6,74 @@
<title>Gradient Fill</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=Nunito:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#gradient-fill {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#gr-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.gr-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.42); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.42);
z-index: 1;
pointer-events: none;
}
#gr-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.gr-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.gr-word {
font-family: 'Nunito', sans-serif;
font-weight: 900; font-size: 100px;
display: inline-block; letter-spacing: 0.04em; line-height: 1;
font-family: "Nunito", sans-serif;
font-weight: 900;
font-size: 100px;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -57,131 +91,139 @@
data-width="1920"
data-height="1080"
>
<video id="gr-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="gr-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="gr-overlay"></div>
<div id="gr-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
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},
];
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 },
];
// Enhanced gradient palette with accent for keywords
var GRADS = [
"linear-gradient(135deg,#FF6B6B,#FFD700)",
"linear-gradient(135deg,#4ADE80,#22D3EE)",
"linear-gradient(135deg,#818CF8,#E879F9)",
"linear-gradient(135deg,#FFD700,#FF6B35)",
"linear-gradient(135deg,#22D3EE,#4ADE80)",
"linear-gradient(135deg,#E879F9,#818CF8)",
"linear-gradient(135deg,#FF3366,#FF6B35)"
];
var KEYWORD_GRADS = {
8: "linear-gradient(135deg,#FF6B6B,#FFD700,#FF6B6B)", // HyperFrames
12: "linear-gradient(135deg,#22D3EE,#ffffff,#22D3EE)", // HTML
15: "linear-gradient(135deg,#818CF8,#E879F9,#818CF8)", // professional
24: "linear-gradient(135deg,#00F5D4,#22D3EE,#00F5D4)", // code
27: "linear-gradient(135deg,#FFD700,#FF6B35,#FFD700)" // cinema.
};
// Enhanced gradient palette with accent for keywords
var GRADS = [
"linear-gradient(135deg,#FF6B6B,#FFD700)",
"linear-gradient(135deg,#4ADE80,#22D3EE)",
"linear-gradient(135deg,#818CF8,#E879F9)",
"linear-gradient(135deg,#FFD700,#FF6B35)",
"linear-gradient(135deg,#22D3EE,#4ADE80)",
"linear-gradient(135deg,#E879F9,#818CF8)",
"linear-gradient(135deg,#FF3366,#FF6B35)",
];
var KEYWORD_GRADS = {
8: "linear-gradient(135deg,#FF6B6B,#FFD700,#FF6B6B)", // HyperFrames
12: "linear-gradient(135deg,#22D3EE,#ffffff,#22D3EE)", // HTML
15: "linear-gradient(135deg,#818CF8,#E879F9,#818CF8)", // professional
24: "linear-gradient(135deg,#00F5D4,#22D3EE,#00F5D4)", // code
27: "linear-gradient(135deg,#FFD700,#FF6B35,#FFD700)", // cinema.
};
var container = document.getElementById('gr-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("gr-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 = 'gr-group';
grp.id = 'gr-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "gr-group";
grp.id = "gr-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'gr-word';
span.id = 'gr-w-' + wi;
span.textContent = w.text;
span.style.fontSize = '100px';
var grad = KEYWORD_GRADS[wi] || GRADS[wi % 7];
span.style.background = grad;
span.style.webkitBackgroundClip = 'text';
span.style.backgroundClip = 'text';
span.style.color = 'transparent';
grp.appendChild(span);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "gr-word";
span.id = "gr-w-" + wi;
span.textContent = w.text;
span.style.fontSize = "100px";
var grad = KEYWORD_GRADS[wi] || GRADS[wi % 7];
span.style.background = grad;
span.style.webkitBackgroundClip = "text";
span.style.backgroundClip = "text";
span.style.color = "transparent";
grp.appendChild(span);
});
container.appendChild(grp);
var gs = g.start;
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var el = document.getElementById("gr-w-" + wi);
tl.set(el, { opacity: 0, y: 55, scale: 0.35 }, gs);
tl.fromTo(
el,
{ y: 55, scale: 0.35, opacity: 0 },
{ y: 0, scale: 1, opacity: 0.35, duration: 0.55, ease: "elastic.out(1.6,0.4)" },
gs + i * 0.05,
);
});
tl.set(grp, { visibility: "visible", opacity: 1 }, gs);
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(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
var gs = g.start;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var el = document.getElementById('gr-w-' + wi);
tl.set(el, { opacity: 0, y: 55, scale: 0.35 }, gs);
tl.fromTo(el,
{ y: 55, scale: 0.35, opacity: 0 },
{ y: 0, scale: 1, opacity: 0.35, duration: 0.55, ease: 'elastic.out(1.6,0.4)' },
gs + i * 0.05
);
});
tl.set(grp, { visibility: 'visible', opacity: 1 }, gs);
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(grp, { y: -26, opacity: 0, duration: 0.18 }, g.end - 0.18);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['gradient-fill'] = tl;
})();
window.__timelines["gradient-fill"] = tl;
})();
</script>
</body>
</html>
@@ -9,35 +9,61 @@
<link href="https://fonts.googleapis.com/css2?family=Anton&display=swap" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#kinetic-slam {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#kt-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.kt-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#kt-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.kt-word {
font-family: 'Anton', sans-serif;
font-family: "Anton", sans-serif;
font-weight: 400;
text-transform: uppercase;
color: #ffffff;
position: absolute; left: 0; width: 100%;
text-align: center; top: 50%;
letter-spacing: 0.04em; line-height: 1;
opacity: 0; visibility: hidden;
position: absolute;
left: 0;
width: 100%;
text-align: center;
top: 50%;
letter-spacing: 0.04em;
line-height: 1;
opacity: 0;
visibility: hidden;
}
</style>
</head>
@@ -51,107 +77,119 @@
data-width="1920"
data-height="1080"
>
<video id="kt-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="kt-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="kt-overlay"></div>
<div id="kt-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('kt-container');
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function(w, wi) {
var el = document.createElement('div');
el.className = 'kt-word';
el.id = 'kt-w-' + wi;
el.textContent = w.text.toUpperCase();
el.style.fontSize = '220px';
if (KEYWORDS.has(wi)) el.style.color = '#FFD700';
container.appendChild(el);
gsap.set(el, { yPercent: -50 });
var entranceMode = wi % 4;
tl.set(el, { visibility: 'visible' }, w.start);
if (entranceMode === 0) {
tl.fromTo(el,
{ y: -120, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.22, ease: 'back.out(1.7)' },
w.start
);
} else if (entranceMode === 1) {
tl.fromTo(el,
{ x: -300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: 'expo.out' },
w.start
);
} else if (entranceMode === 2) {
tl.fromTo(el,
{ x: 300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: 'expo.out' },
w.start
);
} else {
tl.fromTo(el,
{ scale: 0.4, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.24, ease: 'back.out(2.2)' },
w.start
);
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;
};
}
tl.to(el, { opacity: 0, duration: 0.1, ease: 'power2.in' }, w.end);
tl.set(el, { opacity: 0, visibility: 'hidden' }, w.end + 0.1);
});
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
tl.seek(0);
window.__timelines['kinetic-slam'] = tl;
})();
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById("kt-container");
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function (w, wi) {
var el = document.createElement("div");
el.className = "kt-word";
el.id = "kt-w-" + wi;
el.textContent = w.text.toUpperCase();
el.style.fontSize = "220px";
if (KEYWORDS.has(wi)) el.style.color = "#FFD700";
container.appendChild(el);
gsap.set(el, { yPercent: -50 });
var entranceMode = wi % 4;
tl.set(el, { visibility: "visible" }, w.start);
if (entranceMode === 0) {
tl.fromTo(
el,
{ y: -120, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.22, ease: "back.out(1.7)" },
w.start,
);
} else if (entranceMode === 1) {
tl.fromTo(
el,
{ x: -300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: "expo.out" },
w.start,
);
} else if (entranceMode === 2) {
tl.fromTo(
el,
{ x: 300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: "expo.out" },
w.start,
);
} else {
tl.fromTo(
el,
{ scale: 0.4, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.24, ease: "back.out(2.2)" },
w.start,
);
}
tl.to(el, { opacity: 0, duration: 0.1, ease: "power2.in" }, w.end);
tl.set(el, { opacity: 0, visibility: "hidden" }, w.end + 0.1);
});
tl.seek(0);
window.__timelines["kinetic-slam"] = tl;
})();
</script>
</body>
</html>
+146 -108
View File
@@ -9,35 +9,61 @@
<link href="https://fonts.googleapis.com/css2?family=Anton&display=swap" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#kinetic-slam {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#kt-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.kt-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#kt-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.kt-word {
font-family: 'Anton', sans-serif;
font-family: "Anton", sans-serif;
font-weight: 400;
text-transform: uppercase;
color: #ffffff;
position: absolute; left: 0; width: 100%;
text-align: center; top: 50%;
letter-spacing: 0.04em; line-height: 1;
opacity: 0; visibility: hidden;
position: absolute;
left: 0;
width: 100%;
text-align: center;
top: 50%;
letter-spacing: 0.04em;
line-height: 1;
opacity: 0;
visibility: hidden;
}
</style>
</head>
@@ -51,107 +77,119 @@
data-width="1920"
data-height="1080"
>
<video id="kt-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="kt-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="kt-overlay"></div>
<div id="kt-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('kt-container');
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function(w, wi) {
var el = document.createElement('div');
el.className = 'kt-word';
el.id = 'kt-w-' + wi;
el.textContent = w.text.toUpperCase();
el.style.fontSize = '220px';
if (KEYWORDS.has(wi)) el.style.color = '#FFD700';
container.appendChild(el);
gsap.set(el, { yPercent: -50 });
var entranceMode = wi % 4;
tl.set(el, { visibility: 'visible' }, w.start);
if (entranceMode === 0) {
tl.fromTo(el,
{ y: -120, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.22, ease: 'back.out(1.7)' },
w.start
);
} else if (entranceMode === 1) {
tl.fromTo(el,
{ x: -300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: 'expo.out' },
w.start
);
} else if (entranceMode === 2) {
tl.fromTo(el,
{ x: 300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: 'expo.out' },
w.start
);
} else {
tl.fromTo(el,
{ scale: 0.4, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.24, ease: 'back.out(2.2)' },
w.start
);
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;
};
}
tl.to(el, { opacity: 0, duration: 0.1, ease: 'power2.in' }, w.end);
tl.set(el, { opacity: 0, visibility: 'hidden' }, w.end + 0.1);
});
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
tl.seek(0);
window.__timelines['kinetic-slam'] = tl;
})();
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById("kt-container");
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function (w, wi) {
var el = document.createElement("div");
el.className = "kt-word";
el.id = "kt-w-" + wi;
el.textContent = w.text.toUpperCase();
el.style.fontSize = "220px";
if (KEYWORDS.has(wi)) el.style.color = "#FFD700";
container.appendChild(el);
gsap.set(el, { yPercent: -50 });
var entranceMode = wi % 4;
tl.set(el, { visibility: "visible" }, w.start);
if (entranceMode === 0) {
tl.fromTo(
el,
{ y: -120, opacity: 0 },
{ y: 0, opacity: 1, duration: 0.22, ease: "back.out(1.7)" },
w.start,
);
} else if (entranceMode === 1) {
tl.fromTo(
el,
{ x: -300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: "expo.out" },
w.start,
);
} else if (entranceMode === 2) {
tl.fromTo(
el,
{ x: 300, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.2, ease: "expo.out" },
w.start,
);
} else {
tl.fromTo(
el,
{ scale: 0.4, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.24, ease: "back.out(2.2)" },
w.start,
);
}
tl.to(el, { opacity: 0, duration: 0.1, ease: "power2.in" }, w.end);
tl.set(el, { opacity: 0, visibility: "hidden" }, w.end + 0.1);
});
tl.seek(0);
window.__timelines["kinetic-slam"] = tl;
})();
</script>
</body>
</html>
@@ -6,45 +6,86 @@
<title>Matrix Decode</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=Space+Grotesk:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#matrix-decode {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#sc-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.sc-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.85); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.85);
z-index: 1;
pointer-events: none;
}
#sc-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.sc-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.sc-word-wrap {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700; font-size: 96px;
color: #00FF41;
display: inline-block; letter-spacing: 0.04em; line-height: 1; position: relative;
font-family: "Space Grotesk", sans-serif;
font-weight: 700;
font-size: 96px;
color: #00ff41;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
position: relative;
}
.sc-real {
display: none;
}
.sc-scr0 {
display: none;
}
.sc-scr1 {
display: none;
}
.sc-real { display: none; }
.sc-scr0 { display: none; }
.sc-scr1 { display: none; }
</style>
</head>
<body>
@@ -57,141 +98,149 @@
data-width="1920"
data-height="1080"
>
<video id="sc-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="sc-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="sc-overlay"></div>
<div id="sc-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 ALPHANUM = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function scrambleChars(seed) {
var rng = mulberry32(seed);
var result = '';
for (var i = 0; i < 4; i++) {
result += ALPHANUM[Math.floor(rng() * ALPHANUM.length)];
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;
};
}
return result;
}
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
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},
];
function scrambleChars(seed) {
var rng = mulberry32(seed);
var result = "";
for (var i = 0; i < 4; i++) {
result += ALPHANUM[Math.floor(rng() * ALPHANUM.length)];
}
return result;
}
var container = document.getElementById('sc-container');
var tl = gsap.timeline({ paused: true });
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
GROUPS.forEach(function(g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement('div');
grp.className = 'sc-group';
grp.id = 'sc-grp-' + gi;
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 },
];
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordWrap = document.createElement('span');
wordWrap.className = 'sc-word-wrap';
wordWrap.id = 'sc-ww-' + wi;
wordWrap.style.fontSize = '96px';
var container = document.getElementById("sc-container");
var tl = gsap.timeline({ paused: true });
var real = document.createElement('span');
real.className = 'sc-real';
real.id = 'sc-real-' + wi;
real.textContent = w.text;
wordWrap.appendChild(real);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "sc-group";
grp.id = "sc-grp-" + gi;
var scr0 = document.createElement('span');
scr0.className = 'sc-scr0';
scr0.id = 'sc-scr0-' + wi;
scr0.textContent = scrambleChars(wi * 1000 + 0);
wordWrap.appendChild(scr0);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordWrap = document.createElement("span");
wordWrap.className = "sc-word-wrap";
wordWrap.id = "sc-ww-" + wi;
wordWrap.style.fontSize = "96px";
var scr1 = document.createElement('span');
scr1.className = 'sc-scr1';
scr1.id = 'sc-scr1-' + wi;
scr1.textContent = scrambleChars(wi * 1000 + 1);
wordWrap.appendChild(scr1);
var real = document.createElement("span");
real.className = "sc-real";
real.id = "sc-real-" + wi;
real.textContent = w.text;
wordWrap.appendChild(real);
grp.appendChild(wordWrap);
var scr0 = document.createElement("span");
scr0.className = "sc-scr0";
scr0.id = "sc-scr0-" + wi;
scr0.textContent = scrambleChars(wi * 1000 + 0);
wordWrap.appendChild(scr0);
var scr1 = document.createElement("span");
scr1.className = "sc-scr1";
scr1.id = "sc-scr1-" + wi;
scr1.textContent = scrambleChars(wi * 1000 + 1);
wordWrap.appendChild(scr1);
grp.appendChild(wordWrap);
});
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.1 }, g.start);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var realEl = document.getElementById("sc-real-" + wi);
var scr0El = document.getElementById("sc-scr0-" + wi);
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.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
tl.set(grp, { visibility: 'visible', opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.1 }, g.start);
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var realEl = document.getElementById('sc-real-' + wi);
var scr0El = document.getElementById('sc-scr0-' + wi);
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.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['matrix-decode'] = tl;
})();
window.__timelines["matrix-decode"] = tl;
})();
</script>
</body>
</html>
+189 -140
View File
@@ -6,45 +6,86 @@
<title>Matrix Decode</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=Space+Grotesk:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#matrix-decode {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#sc-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.sc-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.85); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.85);
z-index: 1;
pointer-events: none;
}
#sc-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.sc-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.sc-word-wrap {
font-family: 'Space Grotesk', sans-serif;
font-weight: 700; font-size: 96px;
color: #00FF41;
display: inline-block; letter-spacing: 0.04em; line-height: 1; position: relative;
font-family: "Space Grotesk", sans-serif;
font-weight: 700;
font-size: 96px;
color: #00ff41;
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
position: relative;
}
.sc-real {
display: none;
}
.sc-scr0 {
display: none;
}
.sc-scr1 {
display: none;
}
.sc-real { display: none; }
.sc-scr0 { display: none; }
.sc-scr1 { display: none; }
</style>
</head>
<body>
@@ -57,141 +98,149 @@
data-width="1920"
data-height="1080"
>
<video id="sc-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="sc-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="sc-overlay"></div>
<div id="sc-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 ALPHANUM = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function scrambleChars(seed) {
var rng = mulberry32(seed);
var result = '';
for (var i = 0; i < 4; i++) {
result += ALPHANUM[Math.floor(rng() * ALPHANUM.length)];
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;
};
}
return result;
}
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var ALPHANUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
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},
];
function scrambleChars(seed) {
var rng = mulberry32(seed);
var result = "";
for (var i = 0; i < 4; i++) {
result += ALPHANUM[Math.floor(rng() * ALPHANUM.length)];
}
return result;
}
var container = document.getElementById('sc-container');
var tl = gsap.timeline({ paused: true });
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
GROUPS.forEach(function(g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement('div');
grp.className = 'sc-group';
grp.id = 'sc-grp-' + gi;
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 },
];
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordWrap = document.createElement('span');
wordWrap.className = 'sc-word-wrap';
wordWrap.id = 'sc-ww-' + wi;
wordWrap.style.fontSize = '96px';
var container = document.getElementById("sc-container");
var tl = gsap.timeline({ paused: true });
var real = document.createElement('span');
real.className = 'sc-real';
real.id = 'sc-real-' + wi;
real.textContent = w.text;
wordWrap.appendChild(real);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "sc-group";
grp.id = "sc-grp-" + gi;
var scr0 = document.createElement('span');
scr0.className = 'sc-scr0';
scr0.id = 'sc-scr0-' + wi;
scr0.textContent = scrambleChars(wi * 1000 + 0);
wordWrap.appendChild(scr0);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordWrap = document.createElement("span");
wordWrap.className = "sc-word-wrap";
wordWrap.id = "sc-ww-" + wi;
wordWrap.style.fontSize = "96px";
var scr1 = document.createElement('span');
scr1.className = 'sc-scr1';
scr1.id = 'sc-scr1-' + wi;
scr1.textContent = scrambleChars(wi * 1000 + 1);
wordWrap.appendChild(scr1);
var real = document.createElement("span");
real.className = "sc-real";
real.id = "sc-real-" + wi;
real.textContent = w.text;
wordWrap.appendChild(real);
grp.appendChild(wordWrap);
var scr0 = document.createElement("span");
scr0.className = "sc-scr0";
scr0.id = "sc-scr0-" + wi;
scr0.textContent = scrambleChars(wi * 1000 + 0);
wordWrap.appendChild(scr0);
var scr1 = document.createElement("span");
scr1.className = "sc-scr1";
scr1.id = "sc-scr1-" + wi;
scr1.textContent = scrambleChars(wi * 1000 + 1);
wordWrap.appendChild(scr1);
grp.appendChild(wordWrap);
});
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.1 }, g.start);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var realEl = document.getElementById("sc-real-" + wi);
var scr0El = document.getElementById("sc-scr0-" + wi);
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.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
tl.set(grp, { visibility: 'visible', opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.1 }, g.start);
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var realEl = document.getElementById('sc-real-' + wi);
var scr0El = document.getElementById('sc-scr0-' + wi);
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.to(grp, { opacity: 0, duration: 0.12 }, g.end - 0.12);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['matrix-decode'] = tl;
})();
window.__timelines["matrix-decode"] = tl;
})();
</script>
</body>
</html>
@@ -6,7 +6,10 @@
<title>Neon Accent</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=Montserrat:wght@800&display=swap" rel="stylesheet" />
<link
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>
<style>
*,
@@ -154,44 +157,94 @@
var PRIMARY_COLOR = "#FFFFFF";
var ACCENT_COLORS = ["#53FF01", "#FF0002", "#FCFF00"];
var TRANSITION_WORDS = new Set([
"the", "a", "an", "and", "or", "but", "is", "are", "was", "were",
"to", "of", "in", "on", "at", "for", "with", "by", "from", "as",
"it", "its", "this", "that", "these", "those", "be", "been",
"have", "has", "had", "do", "does", "did", "will", "would", "could",
"should", "may", "might", "must", "can", "if", "then", "so", "just",
"not", "no", "yes", "up", "out", "about", "lets", "you", "write", "render"
"the",
"a",
"an",
"and",
"or",
"but",
"is",
"are",
"was",
"were",
"to",
"of",
"in",
"on",
"at",
"for",
"with",
"by",
"from",
"as",
"it",
"its",
"this",
"that",
"these",
"those",
"be",
"been",
"have",
"has",
"had",
"do",
"does",
"did",
"will",
"would",
"could",
"should",
"may",
"might",
"must",
"can",
"if",
"then",
"so",
"just",
"not",
"no",
"yes",
"up",
"out",
"about",
"lets",
"you",
"write",
"render",
]);
var KEYWORDS = new Set(["hyperframes", "html", "professional", "code", "cinema"]);
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
gsap.registerPlugin && gsap.registerPlugin();
@@ -201,13 +254,17 @@
}
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
return {
text: cleanText(item.word || item.text),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
return {
text: cleanText(item.word || item.text),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -247,24 +304,42 @@
function measureLineWidth(words, colors, fontSize) {
return words.reduce(function (total, word, index) {
return total + measureWord(word, colors[index] || PRIMARY_COLOR, fontSize) + (index ? WORD_SPACING : 0);
return (
total +
measureWord(word, colors[index] || PRIMARY_COLOR, fontSize) +
(index ? WORD_SPACING : 0)
);
}, 0);
}
function splitLinesForGroup(words, colors, fontSize) {
var maxLineWidth = SAFE_ZONE_WIDTH;
if (words.some(function (word, i) { return measureWord(word, colors[i] || PRIMARY_COLOR, fontSize) > maxLineWidth; })) return null;
if (measureLineWidth(words, colors, fontSize) <= maxLineWidth) return [{ words: words, colors: colors }];
if (
words.some(function (word, i) {
return measureWord(word, colors[i] || PRIMARY_COLOR, fontSize) > maxLineWidth;
})
)
return null;
if (measureLineWidth(words, colors, fontSize) <= maxLineWidth)
return [{ words: words, colors: colors }];
var best = null;
var bestDiff = Infinity;
for (var split = 1; split < words.length; split++) {
var fw = words.slice(0, split), sw = words.slice(split);
var fc = colors.slice(0, split), sc = colors.slice(split);
var fw = words.slice(0, split),
sw = words.slice(split);
var fc = colors.slice(0, split),
sc = colors.slice(split);
var fW = measureLineWidth(fw, fc, fontSize);
var sW = measureLineWidth(sw, sc, fontSize);
if (fW <= maxLineWidth && sW <= maxLineWidth) {
var diff = Math.abs(fW - sW);
if (diff < bestDiff) { best = [{ words: fw, colors: fc }, { words: sw, colors: sc }]; bestDiff = diff; }
if (diff < bestDiff) {
best = [
{ words: fw, colors: fc },
{ words: sw, colors: sc },
];
bestDiff = diff;
}
}
}
return best;
@@ -287,7 +362,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current, groups.length));
current = [];
}
@@ -299,11 +379,16 @@
function makeGroup(words, groupIndex) {
var colors = assignWordColors(words, groupIndex);
var fontSize = BASE_FONT_SIZE;
while (fontSize > MIN_FONT_SIZE && !splitLinesForGroup(words, colors, fontSize)) { fontSize -= 2; }
while (fontSize > MIN_FONT_SIZE && !splitLinesForGroup(words, colors, fontSize)) {
fontSize -= 2;
}
return {
words: words.slice(), colors: colors, fontSize: fontSize,
words: words.slice(),
colors: colors,
fontSize: fontSize,
lines: splitLinesForGroup(words, colors, fontSize) || [{ words: words, colors: colors }],
start: words[0].start, end: words[words.length - 1].end,
start: words[0].start,
end: words[words.length - 1].end,
};
}
@@ -312,7 +397,32 @@
var r = parseInt(hex.slice(0, 2), 16);
var g = parseInt(hex.slice(2, 4), 16);
var b = parseInt(hex.slice(4, 6), 16);
var glow = "0 0 4px rgba(" + r + "," + g + "," + b + ",1), 0 0 10px rgba(" + r + "," + g + "," + b + ",0.9), 0 0 20px rgba(" + r + "," + g + "," + b + ",0.7), 0 0 40px rgba(" + r + "," + g + "," + b + ",0.4)";
var glow =
"0 0 4px rgba(" +
r +
"," +
g +
"," +
b +
",1), 0 0 10px rgba(" +
r +
"," +
g +
"," +
b +
",0.9), 0 0 20px rgba(" +
r +
"," +
g +
"," +
b +
",0.7), 0 0 40px rgba(" +
r +
"," +
g +
"," +
b +
",0.4)";
return "0 8px 16px rgba(0,0,0,0.8), 0 16px 40px rgba(0,0,0,0.6), " + glow;
}
@@ -333,7 +443,8 @@
wordEl.className = color === PRIMARY_COLOR ? "caption-word" : "caption-word accent";
wordEl.textContent = word.text.toUpperCase();
wordEl.style.color = color;
wordEl.style.fontSize = color === PRIMARY_COLOR ? group.fontSize + "px" : group.fontSize * 1.2 + "px";
wordEl.style.fontSize =
color === PRIMARY_COLOR ? group.fontSize + "px" : group.fontSize * 1.2 + "px";
wordEl.style.textShadow = shadowForColor(color);
lineEl.appendChild(wordEl);
});
@@ -358,7 +469,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -373,8 +486,24 @@
});
tl.set(groupEl, { opacity: 0, scale: 0.65, x: 0, y: 0 }, visibleStart);
tl.to(groupEl, { opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(groupEl, { x: D, y: D, duration: WIGGLE_CYCLE / 2, ease: "sine.inOut", yoyo: true, repeat: Math.max(0, wiggleCycles * 2 - 1), force3D: true }, visibleStart);
tl.to(
groupEl,
{ opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
tl.to(
groupEl,
{
x: D,
y: D,
duration: WIGGLE_CYCLE / 2,
ease: "sine.inOut",
yoyo: true,
repeat: Math.max(0, wiggleCycles * 2 - 1),
force3D: true,
},
visibleStart,
);
tl.set(groupEl, { opacity: 0 }, visibleEnd);
});
+186 -57
View File
@@ -6,7 +6,10 @@
<title>Neon Accent</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=Montserrat:wght@800&display=swap" rel="stylesheet" />
<link
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>
<style>
*,
@@ -154,44 +157,94 @@
var PRIMARY_COLOR = "#FFFFFF";
var ACCENT_COLORS = ["#53FF01", "#FF0002", "#FCFF00"];
var TRANSITION_WORDS = new Set([
"the", "a", "an", "and", "or", "but", "is", "are", "was", "were",
"to", "of", "in", "on", "at", "for", "with", "by", "from", "as",
"it", "its", "this", "that", "these", "those", "be", "been",
"have", "has", "had", "do", "does", "did", "will", "would", "could",
"should", "may", "might", "must", "can", "if", "then", "so", "just",
"not", "no", "yes", "up", "out", "about", "lets", "you", "write", "render"
"the",
"a",
"an",
"and",
"or",
"but",
"is",
"are",
"was",
"were",
"to",
"of",
"in",
"on",
"at",
"for",
"with",
"by",
"from",
"as",
"it",
"its",
"this",
"that",
"these",
"those",
"be",
"been",
"have",
"has",
"had",
"do",
"does",
"did",
"will",
"would",
"could",
"should",
"may",
"might",
"must",
"can",
"if",
"then",
"so",
"just",
"not",
"no",
"yes",
"up",
"out",
"about",
"lets",
"you",
"write",
"render",
]);
var KEYWORDS = new Set(["hyperframes", "html", "professional", "code", "cinema"]);
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
gsap.registerPlugin && gsap.registerPlugin();
@@ -201,13 +254,17 @@
}
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
return {
text: cleanText(item.word || item.text),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
return {
text: cleanText(item.word || item.text),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -247,24 +304,42 @@
function measureLineWidth(words, colors, fontSize) {
return words.reduce(function (total, word, index) {
return total + measureWord(word, colors[index] || PRIMARY_COLOR, fontSize) + (index ? WORD_SPACING : 0);
return (
total +
measureWord(word, colors[index] || PRIMARY_COLOR, fontSize) +
(index ? WORD_SPACING : 0)
);
}, 0);
}
function splitLinesForGroup(words, colors, fontSize) {
var maxLineWidth = SAFE_ZONE_WIDTH;
if (words.some(function (word, i) { return measureWord(word, colors[i] || PRIMARY_COLOR, fontSize) > maxLineWidth; })) return null;
if (measureLineWidth(words, colors, fontSize) <= maxLineWidth) return [{ words: words, colors: colors }];
if (
words.some(function (word, i) {
return measureWord(word, colors[i] || PRIMARY_COLOR, fontSize) > maxLineWidth;
})
)
return null;
if (measureLineWidth(words, colors, fontSize) <= maxLineWidth)
return [{ words: words, colors: colors }];
var best = null;
var bestDiff = Infinity;
for (var split = 1; split < words.length; split++) {
var fw = words.slice(0, split), sw = words.slice(split);
var fc = colors.slice(0, split), sc = colors.slice(split);
var fw = words.slice(0, split),
sw = words.slice(split);
var fc = colors.slice(0, split),
sc = colors.slice(split);
var fW = measureLineWidth(fw, fc, fontSize);
var sW = measureLineWidth(sw, sc, fontSize);
if (fW <= maxLineWidth && sW <= maxLineWidth) {
var diff = Math.abs(fW - sW);
if (diff < bestDiff) { best = [{ words: fw, colors: fc }, { words: sw, colors: sc }]; bestDiff = diff; }
if (diff < bestDiff) {
best = [
{ words: fw, colors: fc },
{ words: sw, colors: sc },
];
bestDiff = diff;
}
}
}
return best;
@@ -287,7 +362,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current, groups.length));
current = [];
}
@@ -299,11 +379,16 @@
function makeGroup(words, groupIndex) {
var colors = assignWordColors(words, groupIndex);
var fontSize = BASE_FONT_SIZE;
while (fontSize > MIN_FONT_SIZE && !splitLinesForGroup(words, colors, fontSize)) { fontSize -= 2; }
while (fontSize > MIN_FONT_SIZE && !splitLinesForGroup(words, colors, fontSize)) {
fontSize -= 2;
}
return {
words: words.slice(), colors: colors, fontSize: fontSize,
words: words.slice(),
colors: colors,
fontSize: fontSize,
lines: splitLinesForGroup(words, colors, fontSize) || [{ words: words, colors: colors }],
start: words[0].start, end: words[words.length - 1].end,
start: words[0].start,
end: words[words.length - 1].end,
};
}
@@ -312,7 +397,32 @@
var r = parseInt(hex.slice(0, 2), 16);
var g = parseInt(hex.slice(2, 4), 16);
var b = parseInt(hex.slice(4, 6), 16);
var glow = "0 0 4px rgba(" + r + "," + g + "," + b + ",1), 0 0 10px rgba(" + r + "," + g + "," + b + ",0.9), 0 0 20px rgba(" + r + "," + g + "," + b + ",0.7), 0 0 40px rgba(" + r + "," + g + "," + b + ",0.4)";
var glow =
"0 0 4px rgba(" +
r +
"," +
g +
"," +
b +
",1), 0 0 10px rgba(" +
r +
"," +
g +
"," +
b +
",0.9), 0 0 20px rgba(" +
r +
"," +
g +
"," +
b +
",0.7), 0 0 40px rgba(" +
r +
"," +
g +
"," +
b +
",0.4)";
return "0 8px 16px rgba(0,0,0,0.8), 0 16px 40px rgba(0,0,0,0.6), " + glow;
}
@@ -333,7 +443,8 @@
wordEl.className = color === PRIMARY_COLOR ? "caption-word" : "caption-word accent";
wordEl.textContent = word.text.toUpperCase();
wordEl.style.color = color;
wordEl.style.fontSize = color === PRIMARY_COLOR ? group.fontSize + "px" : group.fontSize * 1.2 + "px";
wordEl.style.fontSize =
color === PRIMARY_COLOR ? group.fontSize + "px" : group.fontSize * 1.2 + "px";
wordEl.style.textShadow = shadowForColor(color);
lineEl.appendChild(wordEl);
});
@@ -358,7 +469,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -373,8 +486,24 @@
});
tl.set(groupEl, { opacity: 0, scale: 0.65, x: 0, y: 0 }, visibleStart);
tl.to(groupEl, { opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(groupEl, { x: D, y: D, duration: WIGGLE_CYCLE / 2, ease: "sine.inOut", yoyo: true, repeat: Math.max(0, wiggleCycles * 2 - 1), force3D: true }, visibleStart);
tl.to(
groupEl,
{ opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
tl.to(
groupEl,
{
x: D,
y: D,
duration: WIGGLE_CYCLE / 2,
ease: "sine.inOut",
yoyo: true,
repeat: Math.max(0, wiggleCycles * 2 - 1),
force3D: true,
},
visibleStart,
);
tl.set(groupEl, { opacity: 0 }, visibleEnd);
});
+159 -108
View File
@@ -6,42 +6,76 @@
<title>Neon Glow</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=Outfit:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#neon-glow {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#ne-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.ne-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.75); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.75);
z-index: 1;
pointer-events: none;
}
#ne-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.ne-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.ne-word {
font-family: 'Outfit', sans-serif;
font-weight: 900; font-size: 96px;
font-family: "Outfit", sans-serif;
font-weight: 900;
font-size: 96px;
text-transform: uppercase;
color: rgba(0,255,240,0.14);
display: inline-block; letter-spacing: 0.04em; line-height: 1;
color: rgba(0, 255, 240, 0.14);
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
}
</style>
</head>
@@ -55,107 +89,124 @@
data-width="1920"
data-height="1080"
>
<video id="ne-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="ne-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="ne-overlay"></div>
<div id="ne-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
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},
];
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 },
];
// Keywords get pink glow; others get cyan glow
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
// Keywords get pink glow; others get cyan glow
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('ne-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("ne-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 = 'ne-group';
grp.id = 'ne-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "ne-group";
grp.id = "ne-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'ne-word';
span.id = 'ne-w-' + wi;
span.textContent = w.text;
span.style.fontSize = '96px';
grp.appendChild(span);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "ne-word";
span.id = "ne-w-" + wi;
span.textContent = w.text;
span.style.fontSize = "96px";
grp.appendChild(span);
});
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.05, ease: "steps(1)" }, g.start);
tl.fromTo(grp, { x: -8 }, { x: 0, duration: 0.14, ease: "power3.out" }, g.start + 0.05);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var el = document.getElementById("ne-w-" + wi);
var isKW = KEYWORDS.has(wi);
var activeColor = isKW ? "#FF0099" : "#00FFF0";
tl.to(
el,
{
color: activeColor,
textShadow:
"0 0 10px " +
activeColor +
", 0 0 35px " +
activeColor +
", 0 0 90px " +
activeColor,
duration: 0.06,
},
w.start,
);
tl.to(el, { color: "rgba(0,255,240,0.14)", textShadow: "none", duration: 0.06 }, w.end);
});
tl.to(grp, { opacity: 0, x: 6, duration: 0.1, ease: "steps(1)" }, g.end - 0.1);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
tl.set(grp, { visibility: 'visible', opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.05, ease: 'steps(1)' }, g.start);
tl.fromTo(grp, { x: -8 }, { x: 0, duration: 0.14, ease: 'power3.out' }, g.start + 0.05);
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var el = document.getElementById('ne-w-' + wi);
var isKW = KEYWORDS.has(wi);
var activeColor = isKW ? '#FF0099' : '#00FFF0';
tl.to(el, {
color: activeColor,
textShadow: '0 0 10px ' + activeColor + ', 0 0 35px ' + activeColor + ', 0 0 90px ' + activeColor,
duration: 0.06
}, w.start);
tl.to(el, { color: 'rgba(0,255,240,0.14)', textShadow: 'none', duration: 0.06 }, w.end);
});
tl.to(grp, { opacity: 0, x: 6, duration: 0.1, ease: 'steps(1)' }, g.end - 0.1);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['neon-glow'] = tl;
})();
window.__timelines["neon-glow"] = tl;
})();
</script>
</body>
</html>
+159 -108
View File
@@ -6,42 +6,76 @@
<title>Neon Glow</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=Outfit:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#neon-glow {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#ne-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.ne-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.75); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.75);
z-index: 1;
pointer-events: none;
}
#ne-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.ne-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
opacity: 0;
visibility: hidden;
}
.ne-word {
font-family: 'Outfit', sans-serif;
font-weight: 900; font-size: 96px;
font-family: "Outfit", sans-serif;
font-weight: 900;
font-size: 96px;
text-transform: uppercase;
color: rgba(0,255,240,0.14);
display: inline-block; letter-spacing: 0.04em; line-height: 1;
color: rgba(0, 255, 240, 0.14);
display: inline-block;
letter-spacing: 0.04em;
line-height: 1;
}
</style>
</head>
@@ -55,107 +89,124 @@
data-width="1920"
data-height="1080"
>
<video id="ne-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="ne-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="ne-overlay"></div>
<div id="ne-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
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},
];
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 },
];
// Keywords get pink glow; others get cyan glow
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
// Keywords get pink glow; others get cyan glow
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('ne-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("ne-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 = 'ne-group';
grp.id = 'ne-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "ne-group";
grp.id = "ne-grp-" + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'ne-word';
span.id = 'ne-w-' + wi;
span.textContent = w.text;
span.style.fontSize = '96px';
grp.appendChild(span);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "ne-word";
span.id = "ne-w-" + wi;
span.textContent = w.text;
span.style.fontSize = "96px";
grp.appendChild(span);
});
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.05, ease: "steps(1)" }, g.start);
tl.fromTo(grp, { x: -8 }, { x: 0, duration: 0.14, ease: "power3.out" }, g.start + 0.05);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var el = document.getElementById("ne-w-" + wi);
var isKW = KEYWORDS.has(wi);
var activeColor = isKW ? "#FF0099" : "#00FFF0";
tl.to(
el,
{
color: activeColor,
textShadow:
"0 0 10px " +
activeColor +
", 0 0 35px " +
activeColor +
", 0 0 90px " +
activeColor,
duration: 0.06,
},
w.start,
);
tl.to(el, { color: "rgba(0,255,240,0.14)", textShadow: "none", duration: 0.06 }, w.end);
});
tl.to(grp, { opacity: 0, x: 6, duration: 0.1, ease: "steps(1)" }, g.end - 0.1);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
container.appendChild(grp);
tl.set(grp, { visibility: 'visible', opacity: 0 }, g.start);
tl.fromTo(grp, { opacity: 0 }, { opacity: 1, duration: 0.05, ease: 'steps(1)' }, g.start);
tl.fromTo(grp, { x: -8 }, { x: 0, duration: 0.14, ease: 'power3.out' }, g.start + 0.05);
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var el = document.getElementById('ne-w-' + wi);
var isKW = KEYWORDS.has(wi);
var activeColor = isKW ? '#FF0099' : '#00FFF0';
tl.to(el, {
color: activeColor,
textShadow: '0 0 10px ' + activeColor + ', 0 0 35px ' + activeColor + ', 0 0 90px ' + activeColor,
duration: 0.06
}, w.start);
tl.to(el, { color: 'rgba(0,255,240,0.14)', textShadow: 'none', duration: 0.06 }, w.end);
});
tl.to(grp, { opacity: 0, x: 6, duration: 0.1, ease: 'steps(1)' }, g.end - 0.1);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['neon-glow'] = tl;
})();
window.__timelines["neon-glow"] = tl;
})();
</script>
</body>
</html>
@@ -6,7 +6,10 @@
<title>Parallax Layers</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=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -113,9 +116,9 @@
font-weight: 400;
font-style: normal;
line-height: 0.9;
color: #E50914;
-webkit-text-stroke: 5px #E50914;
text-shadow: 2px 4px 4px #A30610;
color: #e50914;
-webkit-text-stroke: 5px #e50914;
text-shadow: 2px 4px 4px #a30610;
}
.word--front-normal {
@@ -123,8 +126,10 @@
font-size: 130px;
font-weight: 400;
font-style: normal;
color: #EEEEEE;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #eeeeee;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
}
.word--front-italic {
@@ -132,8 +137,10 @@
font-size: 130px;
font-weight: 400;
font-style: italic;
color: #EEEEEE;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #eeeeee;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
}
</style>
</head>
@@ -175,48 +182,48 @@
var SLIDE_DUR = 0.2;
var W = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// behind=red 3D emphasis words, front=normal white words
var BLOCKS = [
{ behind: null, front: [[0],[1],[2]] },
{ behind: [[3]], front: [[4],[5]] },
{ behind: [[6]], front: [[7]] },
{ behind: [[8]], front: [[9],[10],[11]] },
{ behind: [[12]], front: [[13],[14]] },
{ behind: [[15]], front: [[16]] },
{ behind: null, front: [[17],[18]] },
{ behind: null, front: [[19],[20],[21],[22]] },
{ behind: [[24]], front: [[23],[25],[26]] },
{ behind: [[27]], front: null },
{ behind: null, front: [[0], [1], [2]] },
{ behind: [[3]], front: [[4], [5]] },
{ behind: [[6]], front: [[7]] },
{ behind: [[8]], front: [[9], [10], [11]] },
{ behind: [[12]], front: [[13], [14]] },
{ behind: [[15]], front: [[16]] },
{ behind: null, front: [[17], [18]] },
{ behind: null, front: [[19], [20], [21], [22]] },
{ behind: [[24]], front: [[23], [25], [26]] },
{ behind: [[27]], front: null },
];
var behindStage = document.getElementById("behind-stage");
@@ -259,8 +266,12 @@
frontStage.appendChild(fEl);
});
var allBehind = BLOCKS.map(function (_, i) { return document.getElementById("bb" + i); });
var allFront = BLOCKS.map(function (_, i) { return document.getElementById("fb" + i); });
var allBehind = BLOCKS.map(function (_, i) {
return document.getElementById("bb" + i);
});
var allFront = BLOCKS.map(function (_, i) {
return document.getElementById("fb" + i);
});
function applyBehindScales() {
BLOCKS.forEach(function (block, bi) {
@@ -293,8 +304,12 @@
var bEl = allBehind[bi];
var fEl = allFront[bi];
allBehind.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allFront.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allBehind.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
allFront.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
if (block.behind) {
tl.set(bEl, { opacity: 1 }, start);
@@ -323,7 +338,9 @@
tl.to({}, { duration: DURATION }, 0);
window.__timelines["parallax-layers"] = tl;
document.fonts.ready.then(function () { applyBehindScales(); });
document.fonts.ready.then(function () {
applyBehindScales();
});
</script>
</body>
</html>
+68 -51
View File
@@ -6,7 +6,10 @@
<title>Parallax Layers</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=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -113,9 +116,9 @@
font-weight: 400;
font-style: normal;
line-height: 0.9;
color: #E50914;
-webkit-text-stroke: 5px #E50914;
text-shadow: 2px 4px 4px #A30610;
color: #e50914;
-webkit-text-stroke: 5px #e50914;
text-shadow: 2px 4px 4px #a30610;
}
.word--front-normal {
@@ -123,8 +126,10 @@
font-size: 130px;
font-weight: 400;
font-style: normal;
color: #EEEEEE;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #eeeeee;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
}
.word--front-italic {
@@ -132,8 +137,10 @@
font-size: 130px;
font-weight: 400;
font-style: italic;
color: #EEEEEE;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6), 0 4px 24px rgba(0, 0, 0, 0.35);
color: #eeeeee;
text-shadow:
0 2px 12px rgba(0, 0, 0, 0.6),
0 4px 24px rgba(0, 0, 0, 0.35);
}
</style>
</head>
@@ -175,48 +182,48 @@
var SLIDE_DUR = 0.2;
var W = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// behind=red 3D emphasis words, front=normal white words
var BLOCKS = [
{ behind: null, front: [[0],[1],[2]] },
{ behind: [[3]], front: [[4],[5]] },
{ behind: [[6]], front: [[7]] },
{ behind: [[8]], front: [[9],[10],[11]] },
{ behind: [[12]], front: [[13],[14]] },
{ behind: [[15]], front: [[16]] },
{ behind: null, front: [[17],[18]] },
{ behind: null, front: [[19],[20],[21],[22]] },
{ behind: [[24]], front: [[23],[25],[26]] },
{ behind: [[27]], front: null },
{ behind: null, front: [[0], [1], [2]] },
{ behind: [[3]], front: [[4], [5]] },
{ behind: [[6]], front: [[7]] },
{ behind: [[8]], front: [[9], [10], [11]] },
{ behind: [[12]], front: [[13], [14]] },
{ behind: [[15]], front: [[16]] },
{ behind: null, front: [[17], [18]] },
{ behind: null, front: [[19], [20], [21], [22]] },
{ behind: [[24]], front: [[23], [25], [26]] },
{ behind: [[27]], front: null },
];
var behindStage = document.getElementById("behind-stage");
@@ -259,8 +266,12 @@
frontStage.appendChild(fEl);
});
var allBehind = BLOCKS.map(function (_, i) { return document.getElementById("bb" + i); });
var allFront = BLOCKS.map(function (_, i) { return document.getElementById("fb" + i); });
var allBehind = BLOCKS.map(function (_, i) {
return document.getElementById("bb" + i);
});
var allFront = BLOCKS.map(function (_, i) {
return document.getElementById("fb" + i);
});
function applyBehindScales() {
BLOCKS.forEach(function (block, bi) {
@@ -293,8 +304,12 @@
var bEl = allBehind[bi];
var fEl = allFront[bi];
allBehind.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allFront.forEach(function (other, oi) { if (oi !== bi) tl.set(other, { opacity: 0 }, start); });
allBehind.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
allFront.forEach(function (other, oi) {
if (oi !== bi) tl.set(other, { opacity: 0 }, start);
});
if (block.behind) {
tl.set(bEl, { opacity: 1 }, start);
@@ -323,7 +338,9 @@
tl.to({}, { duration: DURATION }, 0);
window.__timelines["parallax-layers"] = tl;
document.fonts.ready.then(function () { applyBehindScales(); });
document.fonts.ready.then(function () {
applyBehindScales();
});
</script>
</body>
</html>
@@ -6,47 +6,87 @@
<title>Particle Burst</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=Outfit:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#particle-burst {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#bs-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.bs-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#bs-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.bs-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
opacity: 0;
visibility: hidden;
}
.bs-word {
font-family: 'Outfit', sans-serif;
font-weight: 900; font-size: 88px;
font-family: "Outfit", sans-serif;
font-weight: 900;
font-size: 88px;
text-transform: uppercase;
color: rgba(255,255,255,0.45);
display: inline-block; letter-spacing: 0.05em; line-height: 1;
color: rgba(255, 255, 255, 0.45);
display: inline-block;
letter-spacing: 0.05em;
line-height: 1;
}
.bs-particle {
position: absolute; width: 10px; height: 10px;
border-radius: 50%; opacity: 0; pointer-events: none; z-index: 20;
left: 960px; bottom: 180px;
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
opacity: 0;
pointer-events: none;
z-index: 20;
left: 960px;
bottom: 180px;
}
</style>
</head>
@@ -60,153 +100,193 @@
data-width="1920"
data-height="1080"
>
<video id="bs-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="bs-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="bs-overlay"></div>
<div id="bs-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// Keywords get particle burst + gold color
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
// Keywords get particle burst + gold color
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var PARTICLE_COLORS = ['#FFD700','#FF6B35','#FF3C78','#9B5DE5','#00BBF9','#00F5D4','#ffffff','#F15BB5'];
var NUM_PARTICLES = 10;
var container = document.getElementById('bs-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 = 'bs-group';
grp.id = 'bs-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'bs-word';
span.id = 'bs-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = '88px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
});
var PARTICLE_COLORS = [
"#FFD700",
"#FF6B35",
"#FF3C78",
"#9B5DE5",
"#00BBF9",
"#00F5D4",
"#ffffff",
"#F15BB5",
];
var NUM_PARTICLES = 10;
// Create particles for keyword words
var particleData = {};
WORDS.forEach(function(w, wi) {
if (!KEYWORDS.has(wi)) return;
var rng = mulberry32(wi * 137 + 99);
particleData[wi] = [];
for (var p = 0; p < NUM_PARTICLES; p++) {
var angle = (p / NUM_PARTICLES) * Math.PI * 2 + rng() * 0.6;
var dist = 120 + rng() * 200;
var sz = 4 + rng() * 8;
var dx = Math.cos(angle) * dist;
var dy = -Math.sin(angle) * dist;
var dot = document.createElement('div');
dot.className = 'bs-particle';
dot.id = 'bs-p-' + wi + '-' + p;
dot.style.backgroundColor = PARTICLE_COLORS[p % PARTICLE_COLORS.length];
dot.style.width = sz.toFixed(1) + 'px';
dot.style.height = sz.toFixed(1) + 'px';
container.appendChild(dot);
particleData[wi].push({ el: dot, dx: dx, dy: dy });
}
});
var container = document.getElementById("bs-container");
var tl = gsap.timeline({ paused: true });
GROUPS.forEach(function(g, gi) {
var grp = document.getElementById('bs-grp-' + gi);
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "bs-group";
grp.id = "bs-grp-" + gi;
tl.set(grp, { visibility: 'visible' }, g.start);
tl.fromTo(grp,
{ opacity: 0, scale: 0.92 },
{ opacity: 1, scale: 1, duration: 0.2, ease: 'back.out(1.5)' },
g.start
);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "bs-word";
span.id = "bs-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = "88px";
grp.appendChild(span);
});
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('bs-w-' + wi);
var isKW = KEYWORDS.has(wi);
container.appendChild(grp);
});
tl.to(wordEl, { color: isKW ? '#FFD700' : '#ffffff', scale: isKW ? 1.12 : 1.05, duration: 0.08 }, w.start);
tl.to(wordEl, { color: 'rgba(255,255,255,0.4)', scale: 1.0, duration: 0.1 }, w.end);
if (isKW && particleData[wi]) {
particleData[wi].forEach(function(pd, pi) {
tl.set(pd.el, { x: 0, y: 0, opacity: 0 }, w.start);
tl.to(pd.el, { x: pd.dx, y: pd.dy, opacity: 1, duration: 0.12, ease: 'power3.out' }, w.start + pi * 0.018);
tl.to(pd.el, { opacity: 0, duration: 0.45, ease: 'power1.in' }, w.start + 0.12 + pi * 0.018);
tl.set(pd.el, { opacity: 0, x: 0, y: 0 }, w.start + 0.7);
});
// Create particles for keyword words
var particleData = {};
WORDS.forEach(function (w, wi) {
if (!KEYWORDS.has(wi)) return;
var rng = mulberry32(wi * 137 + 99);
particleData[wi] = [];
for (var p = 0; p < NUM_PARTICLES; p++) {
var angle = (p / NUM_PARTICLES) * Math.PI * 2 + rng() * 0.6;
var dist = 120 + rng() * 200;
var sz = 4 + rng() * 8;
var dx = Math.cos(angle) * dist;
var dy = -Math.sin(angle) * dist;
var dot = document.createElement("div");
dot.className = "bs-particle";
dot.id = "bs-p-" + wi + "-" + p;
dot.style.backgroundColor = PARTICLE_COLORS[p % PARTICLE_COLORS.length];
dot.style.width = sz.toFixed(1) + "px";
dot.style.height = sz.toFixed(1) + "px";
container.appendChild(dot);
particleData[wi].push({ el: dot, dx: dx, dy: dy });
}
});
tl.to(grp, { opacity: 0, duration: 0.14, ease: 'power2.in' }, g.end - 0.14);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
GROUPS.forEach(function (g, gi) {
var grp = document.getElementById("bs-grp-" + gi);
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
tl.seek(0);
window.__timelines['particle-burst'] = tl;
})();
tl.set(grp, { visibility: "visible" }, g.start);
tl.fromTo(
grp,
{ opacity: 0, scale: 0.92 },
{ opacity: 1, scale: 1, duration: 0.2, ease: "back.out(1.5)" },
g.start,
);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById("bs-w-" + wi);
var isKW = KEYWORDS.has(wi);
tl.to(
wordEl,
{ color: isKW ? "#FFD700" : "#ffffff", scale: isKW ? 1.12 : 1.05, duration: 0.08 },
w.start,
);
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", scale: 1.0, duration: 0.1 }, w.end);
if (isKW && particleData[wi]) {
particleData[wi].forEach(function (pd, pi) {
tl.set(pd.el, { x: 0, y: 0, opacity: 0 }, w.start);
tl.to(
pd.el,
{ x: pd.dx, y: pd.dy, opacity: 1, duration: 0.12, ease: "power3.out" },
w.start + pi * 0.018,
);
tl.to(
pd.el,
{ opacity: 0, duration: 0.45, ease: "power1.in" },
w.start + 0.12 + pi * 0.018,
);
tl.set(pd.el, { opacity: 0, x: 0, y: 0 }, w.start + 0.7);
});
}
});
tl.to(grp, { opacity: 0, duration: 0.14, ease: "power2.in" }, g.end - 0.14);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.seek(0);
window.__timelines["particle-burst"] = tl;
})();
</script>
</body>
</html>
+230 -150
View File
@@ -6,47 +6,87 @@
<title>Particle Burst</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=Outfit:wght@900&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@900&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0a0a;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0a0a;
}
#particle-burst {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0a0a;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0a;
}
#bs-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.bs-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.45); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.45);
z-index: 1;
pointer-events: none;
}
#bs-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.bs-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 100px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 100px;
opacity: 0;
visibility: hidden;
}
.bs-word {
font-family: 'Outfit', sans-serif;
font-weight: 900; font-size: 88px;
font-family: "Outfit", sans-serif;
font-weight: 900;
font-size: 88px;
text-transform: uppercase;
color: rgba(255,255,255,0.45);
display: inline-block; letter-spacing: 0.05em; line-height: 1;
color: rgba(255, 255, 255, 0.45);
display: inline-block;
letter-spacing: 0.05em;
line-height: 1;
}
.bs-particle {
position: absolute; width: 10px; height: 10px;
border-radius: 50%; opacity: 0; pointer-events: none; z-index: 20;
left: 960px; bottom: 180px;
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
opacity: 0;
pointer-events: none;
z-index: 20;
left: 960px;
bottom: 180px;
}
</style>
</head>
@@ -60,153 +100,193 @@
data-width="1920"
data-height="1080"
>
<video id="bs-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="bs-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="bs-overlay"></div>
<div id="bs-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
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 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 = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
// Keywords get particle burst + gold color
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
// Keywords get particle burst + gold color
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
var PARTICLE_COLORS = ['#FFD700','#FF6B35','#FF3C78','#9B5DE5','#00BBF9','#00F5D4','#ffffff','#F15BB5'];
var NUM_PARTICLES = 10;
var container = document.getElementById('bs-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 = 'bs-group';
grp.id = 'bs-grp-' + gi;
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var span = document.createElement('span');
span.className = 'bs-word';
span.id = 'bs-w-' + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = '88px';
grp.appendChild(span);
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.35, nextStart - 0.05);
return { wordStart: ws, wordEnd: we, start: WORDS[ws].start, end: gEnd };
});
container.appendChild(grp);
});
var PARTICLE_COLORS = [
"#FFD700",
"#FF6B35",
"#FF3C78",
"#9B5DE5",
"#00BBF9",
"#00F5D4",
"#ffffff",
"#F15BB5",
];
var NUM_PARTICLES = 10;
// Create particles for keyword words
var particleData = {};
WORDS.forEach(function(w, wi) {
if (!KEYWORDS.has(wi)) return;
var rng = mulberry32(wi * 137 + 99);
particleData[wi] = [];
for (var p = 0; p < NUM_PARTICLES; p++) {
var angle = (p / NUM_PARTICLES) * Math.PI * 2 + rng() * 0.6;
var dist = 120 + rng() * 200;
var sz = 4 + rng() * 8;
var dx = Math.cos(angle) * dist;
var dy = -Math.sin(angle) * dist;
var dot = document.createElement('div');
dot.className = 'bs-particle';
dot.id = 'bs-p-' + wi + '-' + p;
dot.style.backgroundColor = PARTICLE_COLORS[p % PARTICLE_COLORS.length];
dot.style.width = sz.toFixed(1) + 'px';
dot.style.height = sz.toFixed(1) + 'px';
container.appendChild(dot);
particleData[wi].push({ el: dot, dx: dx, dy: dy });
}
});
var container = document.getElementById("bs-container");
var tl = gsap.timeline({ paused: true });
GROUPS.forEach(function(g, gi) {
var grp = document.getElementById('bs-grp-' + gi);
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var grp = document.createElement("div");
grp.className = "bs-group";
grp.id = "bs-grp-" + gi;
tl.set(grp, { visibility: 'visible' }, g.start);
tl.fromTo(grp,
{ opacity: 0, scale: 0.92 },
{ opacity: 1, scale: 1, duration: 0.2, ease: 'back.out(1.5)' },
g.start
);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var span = document.createElement("span");
span.className = "bs-word";
span.id = "bs-w-" + wi;
span.textContent = w.text.toUpperCase();
span.style.fontSize = "88px";
grp.appendChild(span);
});
groupWords.forEach(function(w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById('bs-w-' + wi);
var isKW = KEYWORDS.has(wi);
container.appendChild(grp);
});
tl.to(wordEl, { color: isKW ? '#FFD700' : '#ffffff', scale: isKW ? 1.12 : 1.05, duration: 0.08 }, w.start);
tl.to(wordEl, { color: 'rgba(255,255,255,0.4)', scale: 1.0, duration: 0.1 }, w.end);
if (isKW && particleData[wi]) {
particleData[wi].forEach(function(pd, pi) {
tl.set(pd.el, { x: 0, y: 0, opacity: 0 }, w.start);
tl.to(pd.el, { x: pd.dx, y: pd.dy, opacity: 1, duration: 0.12, ease: 'power3.out' }, w.start + pi * 0.018);
tl.to(pd.el, { opacity: 0, duration: 0.45, ease: 'power1.in' }, w.start + 0.12 + pi * 0.018);
tl.set(pd.el, { opacity: 0, x: 0, y: 0 }, w.start + 0.7);
});
// Create particles for keyword words
var particleData = {};
WORDS.forEach(function (w, wi) {
if (!KEYWORDS.has(wi)) return;
var rng = mulberry32(wi * 137 + 99);
particleData[wi] = [];
for (var p = 0; p < NUM_PARTICLES; p++) {
var angle = (p / NUM_PARTICLES) * Math.PI * 2 + rng() * 0.6;
var dist = 120 + rng() * 200;
var sz = 4 + rng() * 8;
var dx = Math.cos(angle) * dist;
var dy = -Math.sin(angle) * dist;
var dot = document.createElement("div");
dot.className = "bs-particle";
dot.id = "bs-p-" + wi + "-" + p;
dot.style.backgroundColor = PARTICLE_COLORS[p % PARTICLE_COLORS.length];
dot.style.width = sz.toFixed(1) + "px";
dot.style.height = sz.toFixed(1) + "px";
container.appendChild(dot);
particleData[wi].push({ el: dot, dx: dx, dy: dy });
}
});
tl.to(grp, { opacity: 0, duration: 0.14, ease: 'power2.in' }, g.end - 0.14);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
GROUPS.forEach(function (g, gi) {
var grp = document.getElementById("bs-grp-" + gi);
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
tl.seek(0);
window.__timelines['particle-burst'] = tl;
})();
tl.set(grp, { visibility: "visible" }, g.start);
tl.fromTo(
grp,
{ opacity: 0, scale: 0.92 },
{ opacity: 1, scale: 1, duration: 0.2, ease: "back.out(1.5)" },
g.start,
);
groupWords.forEach(function (w, i) {
var wi = g.wordStart + i;
var wordEl = document.getElementById("bs-w-" + wi);
var isKW = KEYWORDS.has(wi);
tl.to(
wordEl,
{ color: isKW ? "#FFD700" : "#ffffff", scale: isKW ? 1.12 : 1.05, duration: 0.08 },
w.start,
);
tl.to(wordEl, { color: "rgba(255,255,255,0.4)", scale: 1.0, duration: 0.1 }, w.end);
if (isKW && particleData[wi]) {
particleData[wi].forEach(function (pd, pi) {
tl.set(pd.el, { x: 0, y: 0, opacity: 0 }, w.start);
tl.to(
pd.el,
{ x: pd.dx, y: pd.dy, opacity: 1, duration: 0.12, ease: "power3.out" },
w.start + pi * 0.018,
);
tl.to(
pd.el,
{ opacity: 0, duration: 0.45, ease: "power1.in" },
w.start + 0.12 + pi * 0.018,
);
tl.set(pd.el, { opacity: 0, x: 0, y: 0 }, w.start + 0.7);
});
}
});
tl.to(grp, { opacity: 0, duration: 0.14, ease: "power2.in" }, g.end - 0.14);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.seek(0);
window.__timelines["particle-burst"] = tl;
})();
</script>
</body>
</html>
@@ -6,7 +6,10 @@
<title>Pill Karaoke</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=Poppins:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -165,45 +168,49 @@
var WORD_FADE_LEAD = 0.05;
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
var text = String(item.word || item.text || "").trim();
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (w) { return w.text.length > 0; });
return rawWords
.map(function (item) {
var text = String(item.word || item.text || "").trim();
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (w) {
return w.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -216,13 +223,19 @@
function measureLineWidth(words, fontSize) {
return words.reduce(function (total, word, index) {
return total + measureWordWidth(word.text.toLowerCase(), fontSize) + (index ? WORD_SPACING : 0);
return (
total + measureWordWidth(word.text.toLowerCase(), fontSize) + (index ? WORD_SPACING : 0)
);
}, 0);
}
function splitLinesForGroup(words, fontSize) {
var maxLineWidth = PILL_MAX_WIDTH - PILL_MIN_PADDING_X * 2;
if (words.some(function (w) { return measureWordWidth(w.text.toLowerCase(), fontSize) > maxLineWidth; })) {
if (
words.some(function (w) {
return measureWordWidth(w.text.toLowerCase(), fontSize) > maxLineWidth;
})
) {
return null;
}
if (measureLineWidth(words, fontSize) <= maxLineWidth) return [words];
@@ -269,7 +282,11 @@
var wouldExceedTwoLines = !fitsInTwoLinesAtSize(testGroup, BASE_FONT_SIZE);
if (wouldExceedMaxWords || wouldExceedTwoLines) {
if (current.length) {
groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
}
current = [word];
return;
@@ -280,17 +297,28 @@
var hasNaturalPause = pauseDuration >= PAUSE_THRESHOLD;
var maxWordsReached = current.length >= MAX_WORDS_PER_GROUP;
if (maxWordsReached || !nextWord || hasPunctuation || hasNaturalPause) {
groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
current = [];
}
});
if (current.length) groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
if (current.length)
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
return groups;
}
function fontSizeForGroup(words) {
var size = BASE_FONT_SIZE;
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) { size -= 2; }
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) {
size -= 2;
}
return size;
}
@@ -342,7 +370,9 @@
var groupEl = document.getElementById("caption-group-" + groupIndex);
var nextGroup = GROUPS[groupIndex + 1];
var isLastGroup = groupIndex === GROUPS.length - 1;
var effectiveEnd = isLastGroup ? DURATION : Math.min(nextGroup.start, group.end + GROUP_END_BUFFER);
var effectiveEnd = isLastGroup
? DURATION
: Math.min(nextGroup.start, group.end + GROUP_END_BUFFER);
var visibleStart = Math.max(0, group.start);
var visibleEnd = Math.max(visibleStart + 0.01, effectiveEnd);
@@ -355,7 +385,11 @@
var wordStart = Math.max(visibleStart, word.start - WORD_FADE_LEAD);
tl.set(wordEl, { color: isFirstWord ? COLOR_ACTIVE : COLOR_INACTIVE }, visibleStart);
if (isFirstWord) return;
tl.to(wordEl, { color: COLOR_ACTIVE, duration: COLOR_FADE_DURATION, ease: "none" }, wordStart);
tl.to(
wordEl,
{ color: COLOR_ACTIVE, duration: COLOR_FADE_DURATION, ease: "none" },
wordStart,
);
});
});
+79 -45
View File
@@ -6,7 +6,10 @@
<title>Pill Karaoke</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=Poppins:wght@700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -165,45 +168,49 @@
var WORD_FADE_LEAD = 0.05;
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
var text = String(item.word || item.text || "").trim();
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (w) { return w.text.length > 0; });
return rawWords
.map(function (item) {
var text = String(item.word || item.text || "").trim();
return {
text: text,
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (w) {
return w.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -216,13 +223,19 @@
function measureLineWidth(words, fontSize) {
return words.reduce(function (total, word, index) {
return total + measureWordWidth(word.text.toLowerCase(), fontSize) + (index ? WORD_SPACING : 0);
return (
total + measureWordWidth(word.text.toLowerCase(), fontSize) + (index ? WORD_SPACING : 0)
);
}, 0);
}
function splitLinesForGroup(words, fontSize) {
var maxLineWidth = PILL_MAX_WIDTH - PILL_MIN_PADDING_X * 2;
if (words.some(function (w) { return measureWordWidth(w.text.toLowerCase(), fontSize) > maxLineWidth; })) {
if (
words.some(function (w) {
return measureWordWidth(w.text.toLowerCase(), fontSize) > maxLineWidth;
})
) {
return null;
}
if (measureLineWidth(words, fontSize) <= maxLineWidth) return [words];
@@ -269,7 +282,11 @@
var wouldExceedTwoLines = !fitsInTwoLinesAtSize(testGroup, BASE_FONT_SIZE);
if (wouldExceedMaxWords || wouldExceedTwoLines) {
if (current.length) {
groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
}
current = [word];
return;
@@ -280,17 +297,28 @@
var hasNaturalPause = pauseDuration >= PAUSE_THRESHOLD;
var maxWordsReached = current.length >= MAX_WORDS_PER_GROUP;
if (maxWordsReached || !nextWord || hasPunctuation || hasNaturalPause) {
groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
current = [];
}
});
if (current.length) groups.push({ words: current.slice(), start: current[0].start, end: current[current.length - 1].end });
if (current.length)
groups.push({
words: current.slice(),
start: current[0].start,
end: current[current.length - 1].end,
});
return groups;
}
function fontSizeForGroup(words) {
var size = BASE_FONT_SIZE;
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) { size -= 2; }
while (size > MIN_FONT_SIZE && !fitsInTwoLinesAtSize(words, size)) {
size -= 2;
}
return size;
}
@@ -342,7 +370,9 @@
var groupEl = document.getElementById("caption-group-" + groupIndex);
var nextGroup = GROUPS[groupIndex + 1];
var isLastGroup = groupIndex === GROUPS.length - 1;
var effectiveEnd = isLastGroup ? DURATION : Math.min(nextGroup.start, group.end + GROUP_END_BUFFER);
var effectiveEnd = isLastGroup
? DURATION
: Math.min(nextGroup.start, group.end + GROUP_END_BUFFER);
var visibleStart = Math.max(0, group.start);
var visibleEnd = Math.max(visibleStart + 0.01, effectiveEnd);
@@ -355,7 +385,11 @@
var wordStart = Math.max(visibleStart, word.start - WORD_FADE_LEAD);
tl.set(wordEl, { color: isFirstWord ? COLOR_ACTIVE : COLOR_INACTIVE }, visibleStart);
if (isFirstWord) return;
tl.to(wordEl, { color: COLOR_ACTIVE, duration: COLOR_FADE_DURATION, ease: "none" }, wordStart);
tl.to(
wordEl,
{ color: COLOR_ACTIVE, duration: COLOR_FADE_DURATION, ease: "none" },
wordStart,
);
});
});
@@ -25,25 +25,46 @@
mask-image: url("/assets/texture-mask-text/masks/lava.png");
}
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0805;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0805;
}
#texture-lava {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0805;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0805;
}
#lv-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.lv-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.55); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 1;
pointer-events: none;
}
#lv-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
/* Lava-specific overrides for texture mask */
@@ -59,18 +80,22 @@
.lv-shadow {
position: absolute;
left: 0; width: 100%; text-align: center;
left: 0;
width: 100%;
text-align: center;
top: 50%;
filter: drop-shadow(0 4px 24px rgba(255,100,20,0.55));
opacity: 0; visibility: hidden;
filter: drop-shadow(0 4px 24px rgba(255, 100, 20, 0.55));
opacity: 0;
visibility: hidden;
}
.lv-word {
font-family: 'Anton', sans-serif;
font-family: "Anton", sans-serif;
font-weight: 400;
text-transform: uppercase;
color: #FFD0A0;
color: #ffd0a0;
display: inline-block;
letter-spacing: 0.04em; line-height: 1;
letter-spacing: 0.04em;
line-height: 1;
}
</style>
</head>
@@ -84,89 +109,101 @@
data-width="1920"
data-height="1080"
>
<video id="lv-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="lv-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="lv-overlay"></div>
<div id="lv-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('lv-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("lv-container");
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function(w, wi) {
var txt = w.text.toUpperCase();
var fontSize = 200;
WORDS.forEach(function (w, wi) {
var txt = w.text.toUpperCase();
var fontSize = 200;
var shadow = document.createElement('div');
shadow.className = 'lv-shadow';
shadow.id = 'lv-shadow-' + wi;
gsap.set(shadow, { yPercent: -50 });
var shadow = document.createElement("div");
shadow.className = "lv-shadow";
shadow.id = "lv-shadow-" + wi;
gsap.set(shadow, { yPercent: -50 });
var wordEl = document.createElement('div');
wordEl.className = 'hf-texture-text hf-texture-lava lv-texture-override lv-word';
wordEl.id = 'lv-word-' + wi;
wordEl.textContent = txt;
wordEl.style.fontSize = fontSize + 'px';
if (KEYWORDS.has(wi)) wordEl.style.color = '#FFAA44';
var wordEl = document.createElement("div");
wordEl.className = "hf-texture-text hf-texture-lava lv-texture-override lv-word";
wordEl.id = "lv-word-" + wi;
wordEl.textContent = txt;
wordEl.style.fontSize = fontSize + "px";
if (KEYWORDS.has(wi)) wordEl.style.color = "#FFAA44";
shadow.appendChild(wordEl);
container.appendChild(shadow);
shadow.appendChild(wordEl);
container.appendChild(shadow);
var dur = Math.max(w.end - w.start + 0.3, 0.4);
var dur = Math.max(w.end - w.start + 0.3, 0.4);
tl.set(shadow, { visibility: 'visible', opacity: 0 }, w.start);
tl.fromTo(shadow,
{ opacity: 0, scale: 0.88 },
{ opacity: 1, scale: 1, duration: 0.18, ease: 'power3.out' },
w.start
);
tl.set(wordEl, { '--mask-position': '0% 50%' }, w.start);
tl.to(wordEl, { '--mask-position': '100% 50%', duration: dur, ease: 'sine.inOut' }, w.start);
tl.set(shadow, { visibility: "visible", opacity: 0 }, w.start);
tl.fromTo(
shadow,
{ opacity: 0, scale: 0.88 },
{ opacity: 1, scale: 1, duration: 0.18, ease: "power3.out" },
w.start,
);
tl.set(wordEl, { "--mask-position": "0% 50%" }, w.start);
tl.to(
wordEl,
{ "--mask-position": "100% 50%", duration: dur, ease: "sine.inOut" },
w.start,
);
tl.to(shadow, { opacity: 0, scale: 1.08, duration: 0.1, ease: 'power2.in' }, w.end);
tl.set(shadow, { opacity: 0, visibility: 'hidden' }, w.end + 0.1);
});
tl.to(shadow, { opacity: 0, scale: 1.08, duration: 0.1, ease: "power2.in" }, w.end);
tl.set(shadow, { opacity: 0, visibility: "hidden" }, w.end + 0.1);
});
tl.seek(0);
window.__timelines['texture-lava'] = tl;
})();
tl.seek(0);
window.__timelines["texture-lava"] = tl;
})();
</script>
</body>
</html>
+121 -84
View File
@@ -25,25 +25,46 @@
mask-image: url("/assets/texture-mask-text/masks/lava.png");
}
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #0a0805;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #0a0805;
}
#texture-lava {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #0a0805;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0805;
}
#lv-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.lv-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.55); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
z-index: 1;
pointer-events: none;
}
#lv-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
/* Lava-specific overrides for texture mask */
@@ -59,18 +80,22 @@
.lv-shadow {
position: absolute;
left: 0; width: 100%; text-align: center;
left: 0;
width: 100%;
text-align: center;
top: 50%;
filter: drop-shadow(0 4px 24px rgba(255,100,20,0.55));
opacity: 0; visibility: hidden;
filter: drop-shadow(0 4px 24px rgba(255, 100, 20, 0.55));
opacity: 0;
visibility: hidden;
}
.lv-word {
font-family: 'Anton', sans-serif;
font-family: "Anton", sans-serif;
font-weight: 400;
text-transform: uppercase;
color: #FFD0A0;
color: #ffd0a0;
display: inline-block;
letter-spacing: 0.04em; line-height: 1;
letter-spacing: 0.04em;
line-height: 1;
}
</style>
</head>
@@ -84,89 +109,101 @@
data-width="1920"
data-height="1080"
>
<video id="lv-video" muted playsinline
data-start="0" data-duration="8" data-track-index="0" data-has-audio="false"></video>
<video
id="lv-video"
muted
playsinline
data-start="0"
data-duration="8"
data-track-index="0"
data-has-audio="false"
></video>
<div class="lv-overlay"></div>
<div id="lv-container"></div>
</div>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var KEYWORDS = new Set([8, 12, 15, 24, 27]); // HyperFrames, HTML, professional, code, cinema.
var container = document.getElementById('lv-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("lv-container");
var tl = gsap.timeline({ paused: true });
WORDS.forEach(function(w, wi) {
var txt = w.text.toUpperCase();
var fontSize = 200;
WORDS.forEach(function (w, wi) {
var txt = w.text.toUpperCase();
var fontSize = 200;
var shadow = document.createElement('div');
shadow.className = 'lv-shadow';
shadow.id = 'lv-shadow-' + wi;
gsap.set(shadow, { yPercent: -50 });
var shadow = document.createElement("div");
shadow.className = "lv-shadow";
shadow.id = "lv-shadow-" + wi;
gsap.set(shadow, { yPercent: -50 });
var wordEl = document.createElement('div');
wordEl.className = 'hf-texture-text hf-texture-lava lv-texture-override lv-word';
wordEl.id = 'lv-word-' + wi;
wordEl.textContent = txt;
wordEl.style.fontSize = fontSize + 'px';
if (KEYWORDS.has(wi)) wordEl.style.color = '#FFAA44';
var wordEl = document.createElement("div");
wordEl.className = "hf-texture-text hf-texture-lava lv-texture-override lv-word";
wordEl.id = "lv-word-" + wi;
wordEl.textContent = txt;
wordEl.style.fontSize = fontSize + "px";
if (KEYWORDS.has(wi)) wordEl.style.color = "#FFAA44";
shadow.appendChild(wordEl);
container.appendChild(shadow);
shadow.appendChild(wordEl);
container.appendChild(shadow);
var dur = Math.max(w.end - w.start + 0.3, 0.4);
var dur = Math.max(w.end - w.start + 0.3, 0.4);
tl.set(shadow, { visibility: 'visible', opacity: 0 }, w.start);
tl.fromTo(shadow,
{ opacity: 0, scale: 0.88 },
{ opacity: 1, scale: 1, duration: 0.18, ease: 'power3.out' },
w.start
);
tl.set(wordEl, { '--mask-position': '0% 50%' }, w.start);
tl.to(wordEl, { '--mask-position': '100% 50%', duration: dur, ease: 'sine.inOut' }, w.start);
tl.set(shadow, { visibility: "visible", opacity: 0 }, w.start);
tl.fromTo(
shadow,
{ opacity: 0, scale: 0.88 },
{ opacity: 1, scale: 1, duration: 0.18, ease: "power3.out" },
w.start,
);
tl.set(wordEl, { "--mask-position": "0% 50%" }, w.start);
tl.to(
wordEl,
{ "--mask-position": "100% 50%", duration: dur, ease: "sine.inOut" },
w.start,
);
tl.to(shadow, { opacity: 0, scale: 1.08, duration: 0.1, ease: 'power2.in' }, w.end);
tl.set(shadow, { opacity: 0, visibility: 'hidden' }, w.end + 0.1);
});
tl.to(shadow, { opacity: 0, scale: 1.08, duration: 0.1, ease: "power2.in" }, w.end);
tl.set(shadow, { opacity: 0, visibility: "hidden" }, w.end + 0.1);
});
tl.seek(0);
window.__timelines['texture-lava'] = tl;
})();
tl.seek(0);
window.__timelines["texture-lava"] = tl;
})();
</script>
</body>
</html>
+165 -120
View File
@@ -6,49 +6,87 @@
<title>Typewriter</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" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#typewriter {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#tw-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.tw-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.85); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.85);
z-index: 1;
pointer-events: none;
}
#tw-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.tw-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
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);
display: inline-block; letter-spacing: 0.04em; line-height: 1; white-space: nowrap;
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: inline-block;
letter-spacing: 0.04em;
line-height: 1;
white-space: nowrap;
}
.tw-char {
display: none;
}
.tw-char { display: none; }
.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);
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;
}
</style>
@@ -63,119 +101,126 @@
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>
<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>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ 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 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 container = document.getElementById('tw-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("tw-container");
var tl = gsap.timeline({ paused: true });
GROUPS.forEach(function(g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var fontSize = 76;
var grp = document.createElement('div');
grp.className = 'tw-group';
grp.id = 'tw-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var fontSize = 76;
var grp = document.createElement("div");
grp.className = "tw-group";
grp.id = "tw-grp-" + gi;
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';
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";
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);
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 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 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);
});
container.appendChild(grp);
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 1 }, g.start);
tl.set(grp, { visibility: 'visible', opacity: 1 }, 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);
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);
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: "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.set(cursorEl, { display: 'none' }, w.end);
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['typewriter'] = tl;
})();
window.__timelines["typewriter"] = tl;
})();
</script>
</body>
</html>
+165 -120
View File
@@ -6,49 +6,87 @@
<title>Typewriter</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" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body {
width: 1920px; height: 1080px; margin: 0;
overflow: hidden; background: #000;
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 1920px;
height: 1080px;
margin: 0;
overflow: hidden;
background: #000;
}
#typewriter {
position: relative; width: 1920px; height: 1080px;
overflow: hidden; background: #000;
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #000;
}
#tw-video {
position: absolute; inset: 0; z-index: 0;
width: 100%; height: 100%; object-fit: cover;
position: absolute;
inset: 0;
z-index: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.tw-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.85); z-index: 1; pointer-events: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.85);
z-index: 1;
pointer-events: none;
}
#tw-container {
position: absolute; inset: 0; z-index: 10; pointer-events: none;
position: absolute;
inset: 0;
z-index: 10;
pointer-events: none;
}
.tw-group {
position: absolute;
bottom: 120px; left: 0; width: 100%;
display: flex; flex-wrap: wrap; align-items: flex-end;
justify-content: center; gap: 24px; padding: 0 80px;
opacity: 0; visibility: hidden;
bottom: 120px;
left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: center;
gap: 24px;
padding: 0 80px;
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);
display: inline-block; letter-spacing: 0.04em; line-height: 1; white-space: nowrap;
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: inline-block;
letter-spacing: 0.04em;
line-height: 1;
white-space: nowrap;
}
.tw-char {
display: none;
}
.tw-char { display: none; }
.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);
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;
}
</style>
@@ -63,119 +101,126 @@
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>
<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>
<script>
(function () {
window.__timelines = window.__timelines || {};
(function () {
window.__timelines = window.__timelines || {};
var WORDS = [
{text:"Every", start:0.0, end:0.3},
{text:"great", start:0.3, end:0.55},
{text:"video", start:0.55, end:0.85},
{text:"starts", start:0.85, end:1.1},
{text:"with", start:1.1, end:1.25},
{text:"a", start:1.25, end:1.35},
{text:"single", start:1.35, end:1.65},
{text:"frame.", start:1.65, end:2.0},
{text:"HyperFrames", start:2.1, end:2.65},
{text:"lets", start:2.65, end:2.85},
{text:"you", start:2.85, end:2.95},
{text:"write", start:2.95, end:3.15},
{text:"HTML", start:3.15, end:3.55},
{text:"and", start:3.55, end:3.65},
{text:"render", start:3.65, end:3.95},
{text:"professional",start:3.95, end:4.45},
{text:"video.", start:4.45, end:4.8},
{text:"No", start:4.9, end:5.05},
{text:"timeline.", start:5.05, end:5.45},
{text:"No", start:5.5, end:5.65},
{text:"drag", start:5.65, end:5.85},
{text:"and", start:5.85, end:5.95},
{text:"drop.", start:5.95, end:6.25},
{text:"Just", start:6.35, end:6.55},
{text:"code", start:6.55, end:6.8},
{text:"that", start:6.8, end:6.95},
{text:"becomes", start:6.95, end:7.3},
{text:"cinema.", start:7.3, end:7.7}
];
var WORDS = [
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ 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 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 container = document.getElementById('tw-container');
var tl = gsap.timeline({ paused: true });
var container = document.getElementById("tw-container");
var tl = gsap.timeline({ paused: true });
GROUPS.forEach(function(g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var fontSize = 76;
var grp = document.createElement('div');
grp.className = 'tw-group';
grp.id = 'tw-grp-' + gi;
GROUPS.forEach(function (g, gi) {
var groupWords = WORDS.slice(g.wordStart, g.wordEnd + 1);
var fontSize = 76;
var grp = document.createElement("div");
grp.className = "tw-group";
grp.id = "tw-grp-" + gi;
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';
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";
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);
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 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 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);
});
container.appendChild(grp);
container.appendChild(grp);
tl.set(grp, { visibility: "visible", opacity: 1 }, g.start);
tl.set(grp, { visibility: 'visible', opacity: 1 }, 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);
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);
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: "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.set(cursorEl, { display: 'none' }, w.end);
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
tl.set(grp, { opacity: 0, visibility: "hidden" }, g.end);
});
tl.to(grp, { opacity: 0, duration: 0.2 }, g.end - 0.2);
tl.set(grp, { opacity: 0, visibility: 'hidden' }, g.end);
});
window.__timelines['typewriter'] = tl;
})();
window.__timelines["typewriter"] = tl;
})();
</script>
</body>
</html>
@@ -6,7 +6,10 @@
<title>Weight Shift</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=Montserrat:wght@300;700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -145,44 +148,48 @@
var FONT_WEIGHT_BOLD = 700;
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
return {
text: String(item.word || item.text || "").trim(),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
return {
text: String(item.word || item.text || "").trim(),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -214,7 +221,10 @@
var w2 = measureLineWidth(words.slice(s));
if (w1 <= MAX_LINE_WIDTH && w2 <= MAX_LINE_WIDTH) {
var diff = Math.abs(w1 - w2);
if (diff < bestDiff) { bestDiff = diff; bestSplit = s; }
if (diff < bestDiff) {
bestDiff = diff;
bestSplit = s;
}
}
}
var result = [];
@@ -239,7 +249,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current));
current = [];
}
@@ -249,7 +264,12 @@
}
function makeGroup(words) {
return { words: words.slice(), lines: splitLines(words), start: words[0].start, end: words[words.length - 1].end };
return {
words: words.slice(),
lines: splitLines(words),
start: words[0].start,
end: words[words.length - 1].end,
};
}
function buildCaptions(groups) {
@@ -291,7 +311,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -303,15 +325,27 @@
});
tl.set(groupEl, { opacity: 0, scale: 0.85 }, visibleStart);
tl.to(groupEl, { opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(
groupEl,
{ opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
if (group.lines.length === 2) {
var line1El = document.getElementById("caption-group-" + groupIndex + "-line-0");
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" }, switchTime);
tl.to(line2El, { fontWeight: FONT_WEIGHT_BOLD, duration: WEIGHT_TRANSITION, ease: "power2.out" }, switchTime);
tl.to(
line1El,
{ fontWeight: FONT_WEIGHT_LIGHT, duration: WEIGHT_TRANSITION, ease: "power2.out" },
switchTime,
);
tl.to(
line2El,
{ fontWeight: FONT_WEIGHT_BOLD, duration: WEIGHT_TRANSITION, ease: "power2.out" },
switchTime,
);
}
tl.set(groupEl, { opacity: 0 }, visibleEnd);
+77 -43
View File
@@ -6,7 +6,10 @@
<title>Weight Shift</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=Montserrat:wght@300;700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;700&display=swap"
rel="stylesheet"
/>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
*,
@@ -145,44 +148,48 @@
var FONT_WEIGHT_BOLD = 700;
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},
{"text": "starts", "start": 0.85, "end": 1.1},
{"text": "with", "start": 1.1, "end": 1.25},
{"text": "a", "start": 1.25, "end": 1.35},
{"text": "single", "start": 1.35, "end": 1.65},
{"text": "frame.", "start": 1.65, "end": 2.0},
{"text": "HyperFrames", "start": 2.1, "end": 2.65},
{"text": "lets", "start": 2.65, "end": 2.85},
{"text": "you", "start": 2.85, "end": 2.95},
{"text": "write", "start": 2.95, "end": 3.15},
{"text": "HTML", "start": 3.15, "end": 3.55},
{"text": "and", "start": 3.55, "end": 3.65},
{"text": "render", "start": 3.65, "end": 3.95},
{"text": "professional", "start": 3.95, "end": 4.45},
{"text": "video.", "start": 4.45, "end": 4.8},
{"text": "No", "start": 4.9, "end": 5.05},
{"text": "timeline.", "start": 5.05, "end": 5.45},
{"text": "No", "start": 5.5, "end": 5.65},
{"text": "drag", "start": 5.65, "end": 5.85},
{"text": "and", "start": 5.85, "end": 5.95},
{"text": "drop.", "start": 5.95, "end": 6.25},
{"text": "Just", "start": 6.35, "end": 6.55},
{"text": "code", "start": 6.55, "end": 6.8},
{"text": "that", "start": 6.8, "end": 6.95},
{"text": "becomes", "start": 6.95, "end": 7.3},
{"text": "cinema.", "start": 7.3, "end": 7.7}
{ text: "Every", start: 0.0, end: 0.3 },
{ text: "great", start: 0.3, end: 0.55 },
{ text: "video", start: 0.55, end: 0.85 },
{ text: "starts", start: 0.85, end: 1.1 },
{ text: "with", start: 1.1, end: 1.25 },
{ text: "a", start: 1.25, end: 1.35 },
{ text: "single", start: 1.35, end: 1.65 },
{ text: "frame.", start: 1.65, end: 2.0 },
{ text: "HyperFrames", start: 2.1, end: 2.65 },
{ text: "lets", start: 2.65, end: 2.85 },
{ text: "you", start: 2.85, end: 2.95 },
{ text: "write", start: 2.95, end: 3.15 },
{ text: "HTML", start: 3.15, end: 3.55 },
{ text: "and", start: 3.55, end: 3.65 },
{ text: "render", start: 3.65, end: 3.95 },
{ text: "professional", start: 3.95, end: 4.45 },
{ text: "video.", start: 4.45, end: 4.8 },
{ text: "No", start: 4.9, end: 5.05 },
{ text: "timeline.", start: 5.05, end: 5.45 },
{ text: "No", start: 5.5, end: 5.65 },
{ text: "drag", start: 5.65, end: 5.85 },
{ text: "and", start: 5.85, end: 5.95 },
{ text: "drop.", start: 5.95, end: 6.25 },
{ text: "Just", start: 6.35, end: 6.55 },
{ text: "code", start: 6.55, end: 6.8 },
{ text: "that", start: 6.8, end: 6.95 },
{ text: "becomes", start: 6.95, end: 7.3 },
{ text: "cinema.", start: 7.3, end: 7.7 },
];
function normalizeWords(rawWords) {
return rawWords.map(function (item) {
return {
text: String(item.word || item.text || "").trim(),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
}).filter(function (word) { return word.text.length > 0; });
return rawWords
.map(function (item) {
return {
text: String(item.word || item.text || "").trim(),
start: Math.max(0, Number(item.start) || 0),
end: Math.min(DURATION, Math.max(Number(item.start) || 0, Number(item.end) || 0)),
};
})
.filter(function (word) {
return word.text.length > 0;
});
}
var measureCanvas = document.createElement("canvas");
@@ -214,7 +221,10 @@
var w2 = measureLineWidth(words.slice(s));
if (w1 <= MAX_LINE_WIDTH && w2 <= MAX_LINE_WIDTH) {
var diff = Math.abs(w1 - w2);
if (diff < bestDiff) { bestDiff = diff; bestSplit = s; }
if (diff < bestDiff) {
bestDiff = diff;
bestSplit = s;
}
}
}
var result = [];
@@ -239,7 +249,12 @@
current.push(word);
var punctuation = /[,.:!?]$/.test(word.text);
var pause = nextWord ? nextWord.start - word.end : 0;
if (!nextWord || punctuation || pause >= PAUSE_THRESHOLD || current.length >= MAX_WORDS_PER_GROUP) {
if (
!nextWord ||
punctuation ||
pause >= PAUSE_THRESHOLD ||
current.length >= MAX_WORDS_PER_GROUP
) {
groups.push(makeGroup(current));
current = [];
}
@@ -249,7 +264,12 @@
}
function makeGroup(words) {
return { words: words.slice(), lines: splitLines(words), start: words[0].start, end: words[words.length - 1].end };
return {
words: words.slice(),
lines: splitLines(words),
start: words[0].start,
end: words[words.length - 1].end,
};
}
function buildCaptions(groups) {
@@ -291,7 +311,9 @@
return Math.max(0, group.start - entryLead);
});
var allGroupEls = GROUPS.map(function (_, i) { return document.getElementById("caption-group-" + i); });
var allGroupEls = GROUPS.map(function (_, i) {
return document.getElementById("caption-group-" + i);
});
GROUPS.forEach(function (group, groupIndex) {
var groupEl = allGroupEls[groupIndex];
@@ -303,15 +325,27 @@
});
tl.set(groupEl, { opacity: 0, scale: 0.85 }, visibleStart);
tl.to(groupEl, { opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true }, visibleStart);
tl.to(
groupEl,
{ opacity: 1, scale: 1, duration: ENTRY_DURATION, ease: "power3.out", force3D: true },
visibleStart,
);
if (group.lines.length === 2) {
var line1El = document.getElementById("caption-group-" + groupIndex + "-line-0");
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" }, switchTime);
tl.to(line2El, { fontWeight: FONT_WEIGHT_BOLD, duration: WEIGHT_TRANSITION, ease: "power2.out" }, switchTime);
tl.to(
line1El,
{ fontWeight: FONT_WEIGHT_LIGHT, duration: WEIGHT_TRANSITION, ease: "power2.out" },
switchTime,
);
tl.to(
line2El,
{ fontWeight: FONT_WEIGHT_BOLD, duration: WEIGHT_TRANSITION, ease: "power2.out" },
switchTime,
);
}
tl.set(groupEl, { opacity: 0 }, visibleEnd);