style: apply oxfmt baseline formatting across all source files (#25)

## Summary
- Run `oxfmt .` across the entire codebase to establish formatted baseline
- 299 files changed — mechanical formatting only, no logic changes
- Double quotes, semicolons, 2-space indent, trailing commas, 100 print width

Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits)

## Test plan
- [x] `pnpm format:check` — all 426 files pass
- [x] `pnpm -r typecheck` — all packages pass
- [x] `pnpm build` — all packages build
- [x] All 348 tests pass
This commit is contained in:
Vance Ingalls
2026-03-23 17:15:14 -07:00
committed by GitHub
parent 323ff8f860
commit 20be2ea1c2
299 changed files with 27750 additions and 16792 deletions
@@ -23,11 +23,11 @@
.caption-box {
position: absolute; /* Stacked in the same place */
background-color: #FF2D8A;
background-color: #ff2d8a;
color: white;
padding: 20px 40px;
border-radius: 16px;
font-family: 'Nunito', sans-serif;
font-family: "Nunito", sans-serif;
font-weight: 900; /* Nunito Black */
font-size: 64px;
text-align: center;
@@ -41,9 +41,56 @@
</style>
<script>
(function() {
const TRANSCRIPT = [{'text': 'We', 'start': 0.119, 'end': 0.259}, {'text': 'asked', 'start': 0.319, 'end': 0.479}, {'text': 'what', 'start': 0.519, 'end': 0.659}, {'text': 'you', 'start': 0.699, 'end': 0.819}, {'text': 'needed.', 'start': 0.859, 'end': 1.819}, {'text': 'Forty-seven', 'start': 1.839, 'end': 2.299}, {'text': 'percent', 'start': 2.399, 'end': 2.679}, {'text': 'of', 'start': 2.7, 'end': 2.799}, {'text': 'you', 'start': 2.839, 'end': 2.939}, {'text': 'said', 'start': 3.039, 'end': 3.179}, {'text': 'motion', 'start': 3.24, 'end': 3.559}, {'text': 'graphics.', 'start': 3.579, 'end': 4.639}, {'text': 'Sixty-two', 'start': 4.659, 'end': 5.179}, {'text': 'percent', 'start': 5.299, 'end': 5.759}, {'text': 'said', 'start': 5.859, 'end': 5.98}, {'text': 'static', 'start': 6.099, 'end': 6.399}, {'text': 'content', 'start': 6.46, 'end': 6.879}, {'text': 'was', 'start': 6.92, 'end': 7.079}, {'text': 'costing', 'start': 7.099, 'end': 7.48}, {'text': 'you', 'start': 7.5, 'end': 7.579}, {'text': 'attention,', 'start': 7.679, 'end': 8.659}, {'text': 'and', 'start': 8.699, 'end': 8.86}, {'text': 'three', 'start': 8.88, 'end': 9.06}, {'text': 'out', 'start': 9.079, 'end': 9.18}, {'text': 'of', 'start': 9.199, 'end': 9.34}, {'text': 'four', 'start': 9.38, 'end': 9.799}, {'text': 'said', 'start': 9.84, 'end': 10.0}, {'text': 'you', 'start': 10.019, 'end': 10.159}, {'text': 'know', 'start': 10.179, 'end': 10.36}, {'text': 'the', 'start': 10.38, 'end': 10.479}, {'text': 'look', 'start': 10.52, 'end': 10.699}, {'text': 'you', 'start': 10.739, 'end': 10.859}, {'text': 'want', 'start': 10.98, 'end': 11.34}, {'text': 'but', 'start': 11.359, 'end': 11.52}, {'text': "don't", 'start': 11.56, 'end': 11.779}, {'text': 'have', 'start': 11.819, 'end': 11.94}, {'text': 'the', 'start': 11.96, 'end': 12.06}, {'text': 'editing', 'start': 12.079, 'end': 12.4}, {'text': 'skills', 'start': 12.52, 'end': 12.86}, {'text': 'to', 'start': 12.88, 'end': 13.0}, {'text': 'get', 'start': 13.019, 'end': 13.18}, {'text': 'there.', 'start': 13.22, 'end': 14.22}, {'text': 'So', 'start': 14.239, 'end': 14.399}, {'text': 'we', 'start': 14.42, 'end': 14.52}, {'text': 'built', 'start': 14.619, 'end': 14.88}, {'text': 'Hyperframes', 'start': 15.079, 'end': 15.42}];
const container = document.getElementById('captions-container');
(function () {
const TRANSCRIPT = [
{ text: "We", start: 0.119, end: 0.259 },
{ text: "asked", start: 0.319, end: 0.479 },
{ text: "what", start: 0.519, end: 0.659 },
{ text: "you", start: 0.699, end: 0.819 },
{ text: "needed.", start: 0.859, end: 1.819 },
{ text: "Forty-seven", start: 1.839, end: 2.299 },
{ text: "percent", start: 2.399, end: 2.679 },
{ text: "of", start: 2.7, end: 2.799 },
{ text: "you", start: 2.839, end: 2.939 },
{ text: "said", start: 3.039, end: 3.179 },
{ text: "motion", start: 3.24, end: 3.559 },
{ text: "graphics.", start: 3.579, end: 4.639 },
{ text: "Sixty-two", start: 4.659, end: 5.179 },
{ text: "percent", start: 5.299, end: 5.759 },
{ text: "said", start: 5.859, end: 5.98 },
{ text: "static", start: 6.099, end: 6.399 },
{ text: "content", start: 6.46, end: 6.879 },
{ text: "was", start: 6.92, end: 7.079 },
{ text: "costing", start: 7.099, end: 7.48 },
{ text: "you", start: 7.5, end: 7.579 },
{ text: "attention,", start: 7.679, end: 8.659 },
{ text: "and", start: 8.699, end: 8.86 },
{ text: "three", start: 8.88, end: 9.06 },
{ text: "out", start: 9.079, end: 9.18 },
{ text: "of", start: 9.199, end: 9.34 },
{ text: "four", start: 9.38, end: 9.799 },
{ text: "said", start: 9.84, end: 10.0 },
{ text: "you", start: 10.019, end: 10.159 },
{ text: "know", start: 10.179, end: 10.36 },
{ text: "the", start: 10.38, end: 10.479 },
{ text: "look", start: 10.52, end: 10.699 },
{ text: "you", start: 10.739, end: 10.859 },
{ text: "want", start: 10.98, end: 11.34 },
{ text: "but", start: 11.359, end: 11.52 },
{ text: "don't", start: 11.56, end: 11.779 },
{ text: "have", start: 11.819, end: 11.94 },
{ text: "the", start: 11.96, end: 12.06 },
{ text: "editing", start: 12.079, end: 12.4 },
{ text: "skills", start: 12.52, end: 12.86 },
{ text: "to", start: 12.88, end: 13.0 },
{ text: "get", start: 13.019, end: 13.18 },
{ text: "there.", start: 13.22, end: 14.22 },
{ text: "So", start: 14.239, end: 14.399 },
{ text: "we", start: 14.42, end: 14.52 },
{ text: "built", start: 14.619, end: 14.88 },
{ text: "Hyperframes", start: 15.079, end: 15.42 },
];
const container = document.getElementById("captions-container");
const tl = gsap.timeline({ paused: true });
// Group transcript into lines (max 5 words)
@@ -53,41 +100,54 @@
}
lines.forEach((lineWords, index) => {
const lineText = lineWords.map(w => w.text).join(' ');
const lineText = lineWords.map((w) => w.text).join(" ");
const startTime = lineWords[0].start;
const endTime = lineWords[lineWords.length - 1].end;
// Create element
const el = document.createElement('div');
el.className = 'caption-box';
const el = document.createElement("div");
el.className = "caption-box";
el.textContent = lineText;
el.id = `caption-line-${index}`;
container.appendChild(el);
// Animation: Pop in with scale-up bounce (0% to 110% to 100%)
tl.to(el, {
autoAlpha: 1,
scale: 1.1,
duration: 0.2,
ease: "power2.out"
}, startTime);
tl.to(el, {
scale: 1,
duration: 0.1,
ease: "power2.inOut"
}, startTime + 0.2);
tl.to(
el,
{
autoAlpha: 1,
scale: 1.1,
duration: 0.2,
ease: "power2.out",
},
startTime,
);
tl.to(
el,
{
scale: 1,
duration: 0.1,
ease: "power2.inOut",
},
startTime + 0.2,
);
// Stay visible until next line or end of its duration
// We hide it when the next line starts or at its own end time
const hideTime = (index < lines.length - 1) ? Math.min(endTime, lines[index+1][0].start) : endTime;
tl.to(el, {
autoAlpha: 0,
scale: 0,
duration: 0.15,
ease: "power2.in"
}, hideTime);
const hideTime =
index < lines.length - 1 ? Math.min(endTime, lines[index + 1][0].start) : endTime;
tl.to(
el,
{
autoAlpha: 0,
scale: 0,
duration: 0.15,
ease: "power2.in",
},
hideTime,
);
});
window.__timelines["captions"] = tl;
@@ -1,88 +1,106 @@
<template id="intro-template">
<div id="intro-comp" data-composition-id="intro" data-start="0" data-duration="16.04" data-width="1920" data-height="1080">
<div class="intro-container">
<h1 class="title">HYPERFRAMES</h1>
</div>
<div
id="intro-comp"
data-composition-id="intro"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
>
<div class="intro-container">
<h1 class="title">HYPERFRAMES</h1>
</div>
<style>
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap');
<style>
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap");
[data-composition-id="intro"] .intro-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
[data-composition-id="intro"] .intro-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
[data-composition-id="intro"] .title {
font-family: 'Nunito', sans-serif;
font-weight: 900;
font-size: 180px;
color: #FF2D8A; /* Hot Pink */
text-transform: uppercase;
transform: rotate(-5deg); /* Tilted 5 degrees */
margin: 0;
padding: 20px;
/* Layered offset shadow for depth without suffocating letterforms */
filter: drop-shadow(8px 8px 0 #FFFFFF) drop-shadow(15px 15px 0 rgba(0,0,0,0.1));
opacity: 0;
scale: 0;
}
</style>
[data-composition-id="intro"] .title {
font-family: "Nunito", sans-serif;
font-weight: 900;
font-size: 180px;
color: #ff2d8a; /* Hot Pink */
text-transform: uppercase;
transform: rotate(-5deg); /* Tilted 5 degrees */
margin: 0;
padding: 20px;
/* Layered offset shadow for depth without suffocating letterforms */
filter: drop-shadow(8px 8px 0 #ffffff) drop-shadow(15px 15px 0 rgba(0, 0, 0, 0.1));
opacity: 0;
scale: 0;
}
</style>
<script>
(function() {
const tl = gsap.timeline({ paused: true });
// --- INTRO SEQUENCE ---
// Animation: Scale-up bounce (0% to 110% to 100%) with elastic overshoot
// Starts at 0.5s, lasts until 3s
tl.to('[data-composition-id="intro"] .title', {
<script>
(function () {
const tl = gsap.timeline({ paused: true });
// --- INTRO SEQUENCE ---
// Animation: Scale-up bounce (0% to 110% to 100%) with elastic overshoot
// Starts at 0.5s, lasts until 3s
tl.to('[data-composition-id="intro"] .title', {
opacity: 1,
scale: 1.1,
duration: 0.6,
ease: "back.out(1.7)",
delay: 0.5,
})
.to('[data-composition-id="intro"] .title', {
scale: 1,
duration: 0.4,
ease: "elastic.out(1, 0.3)",
})
// Ambient motion
.to(
'[data-composition-id="intro"] .title',
{
rotation: "-3deg",
duration: 1,
repeat: 1,
yoyo: true,
ease: "sine.inOut",
},
"-=0.5",
)
// Exit intro
.to(
'[data-composition-id="intro"] .title',
{
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "power2.in",
},
1.4,
);
// --- END CARD SEQUENCE ---
// Appears at 14.619s (after Moment 3 finishes exiting at 14.239 + 0.3)
tl.to(
'[data-composition-id="intro"] .title',
{
opacity: 1,
scale: 1.1,
duration: 0.6,
ease: "back.out(1.7)",
delay: 0.5
})
.to('[data-composition-id="intro"] .title', {
scale: 1,
duration: 0.4,
ease: "elastic.out(1, 0.3)"
})
// Ambient motion
.to('[data-composition-id="intro"] .title', {
rotation: "-3deg",
duration: 1,
repeat: 1,
yoyo: true,
ease: "sine.inOut"
}, "-=0.5")
// Exit intro
.to('[data-composition-id="intro"] .title', {
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "power2.in"
}, 1.4);
},
14.619,
).to('[data-composition-id="intro"] .title', {
scale: 1,
duration: 0.4,
ease: "elastic.out(1, 0.3)",
});
// --- END CARD SEQUENCE ---
// Appears at 14.619s (after Moment 3 finishes exiting at 14.239 + 0.3)
tl.to('[data-composition-id="intro"] .title', {
opacity: 1,
scale: 1.1,
duration: 0.6,
ease: "back.out(1.7)"
}, 14.619)
.to('[data-composition-id="intro"] .title', {
scale: 1,
duration: 0.4,
ease: "elastic.out(1, 0.3)"
});
window.__timelines["intro"] = tl;
})();
</script>
</div>
window.__timelines["intro"] = tl;
})();
</script>
</div>
</template>
@@ -2,7 +2,7 @@
<div data-composition-id="stats" data-width="1920" data-height="1080" data-duration="16.04">
<div id="stats-container">
<!-- Moment 1: 47% NEED MOTION GRAPHICS -->
<div id="moment-1" class="moment" style="opacity: 0; transform: scale(0) rotate(8deg);">
<div id="moment-1" class="moment" style="opacity: 0; transform: scale(0) rotate(8deg)">
<div class="sticker-stack">
<div class="sticker-bg blue-bg"></div>
<div class="sticker-content white-bg blue-border">
@@ -11,12 +11,18 @@
</div>
</div>
<!-- Decorative shapes -->
<div class="shape circle pink-bg" style="top: -40px; left: -40px; width: 80px; height: 80px;"></div>
<div class="shape pill lime-bg" style="bottom: -30px; right: -50px; width: 120px; height: 40px; transform: rotate(-15deg);"></div>
<div
class="shape circle pink-bg"
style="top: -40px; left: -40px; width: 80px; height: 80px"
></div>
<div
class="shape pill lime-bg"
style="bottom: -30px; right: -50px; width: 120px; height: 40px; transform: rotate(-15deg)"
></div>
</div>
<!-- Moment 2: 62% STRUGGLE WITH STATIC CONTENT -->
<div id="moment-2" class="moment" style="opacity: 0; transform: scale(0) rotate(-5deg);">
<div id="moment-2" class="moment" style="opacity: 0; transform: scale(0) rotate(-5deg)">
<div class="sticker-stack">
<div class="sticker-bg white-bg"></div>
<div class="sticker-content blue-bg white-border">
@@ -25,12 +31,24 @@
</div>
</div>
<!-- Decorative shapes -->
<div class="shape blob yellow-bg" style="top: -50px; right: -30px; width: 100px; height: 100px; border-radius: 40% 60% 70% 30% / 40% 50% 60% 50%;"></div>
<div class="shape circle pink-bg" style="bottom: -20px; left: -40px; width: 60px; height: 60px;"></div>
<div
class="shape blob yellow-bg"
style="
top: -50px;
right: -30px;
width: 100px;
height: 100px;
border-radius: 40% 60% 70% 30% / 40% 50% 60% 50%;
"
></div>
<div
class="shape circle pink-bg"
style="bottom: -20px; left: -40px; width: 60px; height: 60px"
></div>
</div>
<!-- Moment 3: 75% LACK EDITING SKILLS -->
<div id="moment-3" class="moment" style="opacity: 0; transform: scale(0) rotate(3deg);">
<div id="moment-3" class="moment" style="opacity: 0; transform: scale(0) rotate(3deg)">
<div class="sticker-stack">
<div class="sticker-bg pink-bg"></div>
<div class="sticker-content white-bg pink-border">
@@ -39,8 +57,20 @@
</div>
</div>
<!-- Decorative shapes -->
<div class="shape pill blue-bg" style="top: -30px; left: 50%; transform: translateX(-50%) rotate(5deg); width: 150px; height: 45px;"></div>
<div class="shape circle yellow-bg" style="bottom: -40px; right: -20px; width: 90px; height: 90px;"></div>
<div
class="shape pill blue-bg"
style="
top: -30px;
left: 50%;
transform: translateX(-50%) rotate(5deg);
width: 150px;
height: 45px;
"
></div>
<div
class="shape circle yellow-bg"
style="bottom: -40px; right: -20px; width: 90px; height: 90px"
></div>
</div>
</div>
@@ -49,7 +79,7 @@
width: 1920px;
height: 1080px;
position: relative;
font-family: 'Nunito', sans-serif;
font-family: "Nunito", sans-serif;
overflow: hidden;
}
@@ -120,19 +150,41 @@
}
/* Colors */
[data-composition-id="stats"] .blue-bg { background-color: #0057FF; }
[data-composition-id="stats"] .pink-bg { background-color: #FF2D8A; }
[data-composition-id="stats"] .lime-bg { background-color: #7FFF00; }
[data-composition-id="stats"] .yellow-bg { background-color: #FFE500; }
[data-composition-id="stats"] .white-bg { background-color: #FFFFFF; }
[data-composition-id="stats"] .blue-bg {
background-color: #0057ff;
}
[data-composition-id="stats"] .pink-bg {
background-color: #ff2d8a;
}
[data-composition-id="stats"] .lime-bg {
background-color: #7fff00;
}
[data-composition-id="stats"] .yellow-bg {
background-color: #ffe500;
}
[data-composition-id="stats"] .white-bg {
background-color: #ffffff;
}
[data-composition-id="stats"] .blue-text { color: #0057FF; }
[data-composition-id="stats"] .white-text { color: #FFFFFF; }
[data-composition-id="stats"] .pink-text { color: #FF2D8A; }
[data-composition-id="stats"] .blue-text {
color: #0057ff;
}
[data-composition-id="stats"] .white-text {
color: #ffffff;
}
[data-composition-id="stats"] .pink-text {
color: #ff2d8a;
}
[data-composition-id="stats"] .blue-border { border-color: #0057FF; }
[data-composition-id="stats"] .white-border { border-color: #FFFFFF; }
[data-composition-id="stats"] .pink-border { border-color: #FF2D8A; }
[data-composition-id="stats"] .blue-border {
border-color: #0057ff;
}
[data-composition-id="stats"] .white-border {
border-color: #ffffff;
}
[data-composition-id="stats"] .pink-border {
border-color: #ff2d8a;
}
/* Typography */
[data-composition-id="stats"] .stat-number {
@@ -161,14 +213,64 @@
</style>
<script>
(function() {
const TRANSCRIPT = [{'text': 'We', 'start': 0.119, 'end': 0.259}, {'text': 'asked', 'start': 0.319, 'end': 0.479}, {'text': 'what', 'start': 0.519, 'end': 0.659}, {'text': 'you', 'start': 0.699, 'end': 0.819}, {'text': 'needed.', 'start': 0.859, 'end': 1.819}, {'text': 'Forty-seven', 'start': 1.839, 'end': 2.299}, {'text': 'percent', 'start': 2.399, 'end': 2.679}, {'text': 'of', 'start': 2.7, 'end': 2.799}, {'text': 'you', 'start': 2.839, 'end': 2.939}, {'text': 'said', 'start': 3.039, 'end': 3.179}, {'text': 'motion', 'start': 3.24, 'end': 3.559}, {'text': 'graphics.', 'start': 3.579, 'end': 4.639}, {'text': 'Sixty-two', 'start': 4.659, 'end': 5.179}, {'text': 'percent', 'start': 5.299, 'end': 5.759}, {'text': 'said', 'start': 5.859, 'end': 5.98}, {'text': 'static', 'start': 6.099, 'end': 6.399}, {'text': 'content', 'start': 6.46, 'end': 6.879}, {'text': 'was', 'start': 6.92, 'end': 7.079}, {'text': 'costing', 'start': 7.099, 'end': 7.48}, {'text': 'you', 'start': 7.5, 'end': 7.579}, {'text': 'attention,', 'start': 7.679, 'end': 8.659}, {'text': 'and', 'start': 8.699, 'end': 8.86}, {'text': 'three', 'start': 8.88, 'end': 9.06}, {'text': 'out', 'start': 9.079, 'end': 9.18}, {'text': 'of', 'start': 9.199, 'end': 9.34}, {'text': 'four', 'start': 9.38, 'end': 9.799}, {'text': 'said', 'start': 9.84, 'end': 10.0}, {'text': 'you', 'start': 10.019, 'end': 10.159}, {'text': 'know', 'start': 10.179, 'end': 10.36}, {'text': 'the', 'start': 10.38, 'end': 10.479}, {'text': 'look', 'start': 10.52, 'end': 10.699}, {'text': 'you', 'start': 10.739, 'end': 10.859}, {'text': 'want', 'start': 10.98, 'end': 11.34}, {'text': 'but', 'start': 11.359, 'end': 11.52}, {'text': "don't", 'start': 11.56, 'end': 11.779}, {'text': 'have', 'start': 11.819, 'end': 11.94}, {'text': 'the', 'start': 11.96, 'end': 12.06}, {'text': 'editing', 'start': 12.079, 'end': 12.4}, {'text': 'skills', 'start': 12.52, 'end': 12.86}, {'text': 'to', 'start': 12.88, 'end': 13.0}, {'text': 'get', 'start': 13.019, 'end': 13.18}, {'text': 'there.', 'start': 13.22, 'end': 14.22}, {'text': 'So', 'start': 14.239, 'end': 14.399}, {'text': 'we', 'start': 14.42, 'end': 14.52}, {'text': 'built', 'start': 14.619, 'end': 14.88}, {'text': 'Hyperframes', 'start': 15.079, 'end': 15.42}];
(function () {
const TRANSCRIPT = [
{ text: "We", start: 0.119, end: 0.259 },
{ text: "asked", start: 0.319, end: 0.479 },
{ text: "what", start: 0.519, end: 0.659 },
{ text: "you", start: 0.699, end: 0.819 },
{ text: "needed.", start: 0.859, end: 1.819 },
{ text: "Forty-seven", start: 1.839, end: 2.299 },
{ text: "percent", start: 2.399, end: 2.679 },
{ text: "of", start: 2.7, end: 2.799 },
{ text: "you", start: 2.839, end: 2.939 },
{ text: "said", start: 3.039, end: 3.179 },
{ text: "motion", start: 3.24, end: 3.559 },
{ text: "graphics.", start: 3.579, end: 4.639 },
{ text: "Sixty-two", start: 4.659, end: 5.179 },
{ text: "percent", start: 5.299, end: 5.759 },
{ text: "said", start: 5.859, end: 5.98 },
{ text: "static", start: 6.099, end: 6.399 },
{ text: "content", start: 6.46, end: 6.879 },
{ text: "was", start: 6.92, end: 7.079 },
{ text: "costing", start: 7.099, end: 7.48 },
{ text: "you", start: 7.5, end: 7.579 },
{ text: "attention,", start: 7.679, end: 8.659 },
{ text: "and", start: 8.699, end: 8.86 },
{ text: "three", start: 8.88, end: 9.06 },
{ text: "out", start: 9.079, end: 9.18 },
{ text: "of", start: 9.199, end: 9.34 },
{ text: "four", start: 9.38, end: 9.799 },
{ text: "said", start: 9.84, end: 10.0 },
{ text: "you", start: 10.019, end: 10.159 },
{ text: "know", start: 10.179, end: 10.36 },
{ text: "the", start: 10.38, end: 10.479 },
{ text: "look", start: 10.52, end: 10.699 },
{ text: "you", start: 10.739, end: 10.859 },
{ text: "want", start: 10.98, end: 11.34 },
{ text: "but", start: 11.359, end: 11.52 },
{ text: "don't", start: 11.56, end: 11.779 },
{ text: "have", start: 11.819, end: 11.94 },
{ text: "the", start: 11.96, end: 12.06 },
{ text: "editing", start: 12.079, end: 12.4 },
{ text: "skills", start: 12.52, end: 12.86 },
{ text: "to", start: 12.88, end: 13.0 },
{ text: "get", start: 13.019, end: 13.18 },
{ text: "there.", start: 13.22, end: 14.22 },
{ text: "So", start: 14.239, end: 14.399 },
{ text: "we", start: 14.42, end: 14.52 },
{ text: "built", start: 14.619, end: 14.88 },
{ text: "Hyperframes", start: 15.079, end: 15.42 },
];
const tl = gsap.timeline({ paused: true });
// Helper to find word timing
function getWordTime(wordText) {
const word = TRANSCRIPT.find(w =>
w.text.toLowerCase().replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g,"").startsWith(wordText.toLowerCase())
const word = TRANSCRIPT.find((w) =>
w.text
.toLowerCase()
.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "")
.startsWith(wordText.toLowerCase()),
);
return word ? word.start : null;
}
@@ -179,69 +281,97 @@
const t3 = getWordTime("three") || 8.88;
// Moment 1 Animation (approx 5s)
tl.to('#moment-1', {
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set('#moment-1', { transformOrigin: "center center" })
}, t1);
tl.to(
"#moment-1",
{
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set("#moment-1", { transformOrigin: "center center" }),
},
t1,
);
// Moment 1 Exit (before Moment 2)
tl.to('#moment-1', {
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)"
}, t2 - 0.4);
tl.to(
"#moment-1",
{
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)",
},
t2 - 0.4,
);
// Moment 2 Animation (approx 9s)
tl.to('#moment-2', {
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set('#moment-2', { transformOrigin: "center center" })
}, t2);
tl.to(
"#moment-2",
{
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set("#moment-2", { transformOrigin: "center center" }),
},
t2,
);
// Moment 2 Exit (before Moment 3)
tl.to('#moment-2', {
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)"
}, t3 - 0.4);
tl.to(
"#moment-2",
{
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)",
},
t3 - 0.4,
);
// Moment 3 Animation (approx 13s)
tl.to('#moment-3', {
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set('#moment-3', { transformOrigin: "center center" })
}, t3);
tl.to(
"#moment-3",
{
opacity: 1,
scale: 1,
duration: 0.8,
ease: "elastic.out(1, 0.6)",
onStart: () => gsap.set("#moment-3", { transformOrigin: "center center" }),
},
t3,
);
// Moment 3 Exit: 3 words before 'Hyperframes'
// 'Editor' is at 15.079. 3 words before is 'So' at 14.239.
tl.to('#moment-3', {
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)"
}, 14.239);
tl.to(
"#moment-3",
{
opacity: 0,
scale: 0.5,
duration: 0.3,
ease: "back.in(1.7)",
},
14.239,
);
// Ambient Motion (Finite)
const totalDuration = 16.04;
gsap.utils.toArray('.shape').forEach((shape, i) => {
const stepDuration = 2 + (i * 0.2);
gsap.utils.toArray(".shape").forEach((shape, i) => {
const stepDuration = 2 + i * 0.2;
const steps = Math.ceil(totalDuration / stepDuration);
for(let s = 0; s < steps; s++) {
tl.to(shape, {
y: (s % 2 === 0 ? 15 : -15),
rotation: (s % 2 === 0 ? 5 : -5),
duration: stepDuration,
ease: "sine.inOut"
}, s * stepDuration);
for (let s = 0; s < steps; s++) {
tl.to(
shape,
{
y: s % 2 === 0 ? 15 : -15,
rotation: s % 2 === 0 ? 5 : -5,
duration: stepDuration,
ease: "sine.inOut",
},
s * stepDuration,
);
}
});
+206 -150
View File
@@ -1,173 +1,229 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hyperframes - Play Mode</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #FFFFFF;
font-family: 'Nunito', sans-serif;
}
body,
html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #ffffff;
font-family: "Nunito", sans-serif;
}
#main-composition {
width: 1920px;
height: 1080px;
position: relative;
}
#main-composition {
width: 1920px;
height: 1080px;
position: relative;
}
#bg-comp,
#aroll-comp,
#intro-comp,
#stats-comp,
#captions-comp {
#bg-comp,
#aroll-comp,
#intro-comp,
#stats-comp,
#captions-comp {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#bg-comp {
z-index: 1;
}
#aroll-comp {
z-index: 10;
}
#intro-comp {
z-index: 100;
}
#stats-comp {
z-index: 150;
}
#captions-comp {
z-index: 200;
}
#aroll-container {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 0;
}
#short_mag_cut {
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
border: 8px solid #ffffff;
}
#background-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #ffffff;
z-index: 0;
}
</style>
<link
href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div
id="main-composition"
data-composition-id="main-video"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
>
<!-- Background Layer Composition -->
<div
id="bg-comp"
data-composition-id="background"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
data-track-index="1"
>
<div id="background-layer"></div>
<style>
#background-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
background-color: #ffffff;
}
</style>
<script>
(function () {
const tl = gsap.timeline({ paused: true });
const bg = document.getElementById("background-layer");
// Sync with A-roll framing 3 (4.659s)
tl.to(bg, { backgroundColor: "#0057FF", duration: 0.5 }, 4.659);
// Sync with A-roll framing 4 (8.88s)
tl.to(bg, { backgroundColor: "#FFFFFF", duration: 0.5 }, 8.88);
window.__timelines["background"] = tl;
})();
</script>
</div>
#bg-comp {
z-index: 1;
}
#aroll-comp {
z-index: 10;
}
#intro-comp {
z-index: 100;
}
#stats-comp {
z-index: 150;
}
#captions-comp {
z-index: 200;
}
#aroll-container {
<!-- A-roll Layer Composition -->
<div
id="aroll-comp"
data-composition-id="aroll-layer"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
data-track-index="10"
>
<div id="aroll-container">
<video
id="short_mag_cut"
src="__VIDEO_SRC__"
data-start="0"
data-duration="16.04"
data-track-index="1"
style="width: 100%; height: auto"
></video>
</div>
<style>
#aroll-container {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 0;
}
#short_mag_cut {
}
#short_mag_cut {
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
border: 8px solid #FFFFFF;
}
#background-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #FFFFFF;
z-index: 0;
}
</style>
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap" rel="stylesheet">
</head>
<body>
<div id="main-composition" data-composition-id="main-video" data-start="0" data-duration="16.04" data-width="1920" data-height="1080">
<!-- Background Layer Composition -->
<div id="bg-comp" data-composition-id="background" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="1">
<div id="background-layer"></div>
<style>
#background-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #FFFFFF;
}
</style>
<script>
(function() {
const tl = gsap.timeline({ paused: true });
const bg = document.getElementById('background-layer');
// Sync with A-roll framing 3 (4.659s)
tl.to(bg, { backgroundColor: "#0057FF", duration: 0.5 }, 4.659);
// Sync with A-roll framing 4 (8.88s)
tl.to(bg, { backgroundColor: "#FFFFFF", duration: 0.5 }, 8.88);
window.__timelines["background"] = tl;
})();
</script>
</div>
<!-- A-roll Layer Composition -->
<div id="aroll-comp" data-composition-id="aroll-layer" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="10">
<div id="aroll-container">
<video id="short_mag_cut"
src="__VIDEO_SRC__"
data-start="0"
data-duration="16.04"
data-track-index="1"
style="width: 100%; height: auto;"></video>
</div>
<style>
#aroll-container {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
#short_mag_cut {
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
border: 8px solid #FFFFFF;
}
</style>
<script>
(function() {
const tl = gsap.timeline({ paused: true });
const container = document.getElementById('aroll-container');
gsap.set(container, { y: -1100, scale: 0.8 });
tl.to(container, { y: 0, duration: 1.2, ease: "elastic.out(1, 0.6)" }, 0);
tl.to(container, { scale: 1.4, x: -300, duration: 1, ease: "back.out(1.7)" }, 1.839);
tl.to(container, { scale: 0.7, x: 400, duration: 1, ease: "back.out(1.7)" }, 4.659);
tl.to(container, { scale: 0.9, x: 0, duration: 1, ease: "back.out(1.7)" }, 8.88);
window.__timelines["aroll-layer"] = tl;
})();
</script>
</div>
<!-- Compositions -->
<div id="intro-comp" data-composition-id="intro" data-composition-src="compositions/intro.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="100"></div>
<div id="captions-comp" data-composition-id="captions" data-composition-src="compositions/captions.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="200"></div>
<div id="stats-comp" data-composition-id="stats" data-composition-src="compositions/stats.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="150"></div>
<!-- Audio Clips -->
<audio id="sfx-bounce-0" src="" data-start="0" data-track-index="5"></audio>
<audio id="sfx-whoosh-1" src="" data-start="1.839" data-track-index="6"></audio>
<audio id="sfx-pop-1" src="" data-start="2.039" data-track-index="7"></audio>
<audio id="sfx-whoosh-2" src="" data-start="4.659" data-track-index="6"></audio>
<audio id="sfx-pop-2" src="" data-start="4.859" data-track-index="7"></audio>
<audio id="sfx-whoosh-3" src="" data-start="8.88" data-track-index="6"></audio>
<audio id="sfx-pop-3" src="" data-start="9.08" data-track-index="7"></audio>
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
border: 8px solid #ffffff;
}
</style>
<script>
window.__timelines = window.__timelines || {};
(function () {
const tl = gsap.timeline({ paused: true });
window.__timelines["main-video"] = tl;
const container = document.getElementById("aroll-container");
gsap.set(container, { y: -1100, scale: 0.8 });
tl.to(container, { y: 0, duration: 1.2, ease: "elastic.out(1, 0.6)" }, 0);
tl.to(container, { scale: 1.4, x: -300, duration: 1, ease: "back.out(1.7)" }, 1.839);
tl.to(container, { scale: 0.7, x: 400, duration: 1, ease: "back.out(1.7)" }, 4.659);
tl.to(container, { scale: 0.9, x: 0, duration: 1, ease: "back.out(1.7)" }, 8.88);
window.__timelines["aroll-layer"] = tl;
})();
</script>
</div>
<!-- Compositions -->
<div
id="intro-comp"
data-composition-id="intro"
data-composition-src="compositions/intro.html"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
data-track-index="100"
></div>
<div
id="captions-comp"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
data-track-index="200"
></div>
<div
id="stats-comp"
data-composition-id="stats"
data-composition-src="compositions/stats.html"
data-start="0"
data-duration="16.04"
data-width="1920"
data-height="1080"
data-track-index="150"
></div>
<!-- Audio Clips -->
<audio id="sfx-bounce-0" src="" data-start="0" data-track-index="5"></audio>
<audio id="sfx-whoosh-1" src="" data-start="1.839" data-track-index="6"></audio>
<audio id="sfx-pop-1" src="" data-start="2.039" data-track-index="7"></audio>
<audio id="sfx-whoosh-2" src="" data-start="4.659" data-track-index="6"></audio>
<audio id="sfx-pop-2" src="" data-start="4.859" data-track-index="7"></audio>
<audio id="sfx-whoosh-3" src="" data-start="8.88" data-track-index="6"></audio>
<audio id="sfx-pop-3" src="" data-start="9.08" data-track-index="7"></audio>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
window.__timelines["main-video"] = tl;
</script>
</div>
</body>
</html>
</body>
</html>
@@ -7,7 +7,7 @@
width: 1920px;
height: 1080px;
position: relative;
font-family: 'Helvetica', 'Arial', sans-serif;
font-family: "Helvetica", "Arial", sans-serif;
font-weight: bold;
overflow: hidden;
}
@@ -24,7 +24,7 @@
}
[data-composition-id="captions"] .caption-box {
background-color: #0A1E3D; /* Solid navy */
background-color: #0a1e3d; /* Solid navy */
padding: 20px 40px;
display: none; /* Hidden by default, shown via GSAP */
justify-content: center;
@@ -33,7 +33,7 @@
}
[data-composition-id="captions"] .caption-text {
color: #F2F2F2; /* Off-white */
color: #f2f2f2; /* Off-white */
font-size: 72px;
text-transform: uppercase; /* Swiss style often uses uppercase for impact */
letter-spacing: -2px;
@@ -44,9 +44,56 @@
</style>
<script>
(function() {
const TRANSCRIPT = [{'text': 'We', 'start': 0.119, 'end': 0.259}, {'text': 'asked', 'start': 0.319, 'end': 0.479}, {'text': 'what', 'start': 0.519, 'end': 0.659}, {'text': 'you', 'start': 0.699, 'end': 0.819}, {'text': 'needed.', 'start': 0.859, 'end': 1.819}, {'text': 'Forty-seven', 'start': 1.86, 'end': 2.299}, {'text': 'percent', 'start': 2.399, 'end': 2.679}, {'text': 'of', 'start': 2.7, 'end': 2.799}, {'text': 'you', 'start': 2.839, 'end': 2.939}, {'text': 'said', 'start': 3.039, 'end': 3.179}, {'text': 'motion', 'start': 3.24, 'end': 3.559}, {'text': 'graphics,', 'start': 3.579, 'end': 4.599}, {'text': 'sixty-two', 'start': 4.679, 'end': 5.179}, {'text': 'percent', 'start': 5.299, 'end': 5.759}, {'text': 'said', 'start': 5.859, 'end': 5.98}, {'text': 'static', 'start': 6.079, 'end': 6.399}, {'text': 'content', 'start': 6.46, 'end': 6.879}, {'text': 'was', 'start': 6.92, 'end': 7.079}, {'text': 'costing', 'start': 7.099, 'end': 7.48}, {'text': 'you', 'start': 7.5, 'end': 7.579}, {'text': 'attention,', 'start': 7.679, 'end': 8.659}, {'text': 'and', 'start': 8.699, 'end': 8.86}, {'text': 'three', 'start': 8.88, 'end': 9.06}, {'text': 'out', 'start': 9.079, 'end': 9.18}, {'text': 'of', 'start': 9.199, 'end': 9.34}, {'text': 'four', 'start': 9.38, 'end': 9.799}, {'text': 'said', 'start': 9.84, 'end': 10.0}, {'text': 'you', 'start': 10.019, 'end': 10.159}, {'text': 'know', 'start': 10.179, 'end': 10.36}, {'text': 'the', 'start': 10.38, 'end': 10.42}, {'text': 'look', 'start': 10.519, 'end': 10.699}, {'text': 'you', 'start': 10.739, 'end': 10.859}, {'text': 'want', 'start': 10.98, 'end': 11.34}, {'text': 'but', 'start': 11.359, 'end': 11.52}, {'text': "don't", 'start': 11.56, 'end': 11.779}, {'text': 'have', 'start': 11.819, 'end': 11.94}, {'text': 'the', 'start': 11.96, 'end': 12.06}, {'text': 'editing', 'start': 12.079, 'end': 12.4}, {'text': 'skills', 'start': 12.52, 'end': 12.86}, {'text': 'to', 'start': 12.88, 'end': 13.0}, {'text': 'get', 'start': 13.019, 'end': 13.18}, {'text': 'there.', 'start': 13.22, 'end': 14.22}, {'text': 'So', 'start': 14.239, 'end': 14.399}, {'text': 'we', 'start': 14.42, 'end': 14.52}, {'text': 'built', 'start': 14.619, 'end': 14.88}, {'text': 'Hyperframes', 'start': 15.079, 'end': 15.42}];
const container = document.getElementById('caption-container');
(function () {
const TRANSCRIPT = [
{ text: "We", start: 0.119, end: 0.259 },
{ text: "asked", start: 0.319, end: 0.479 },
{ text: "what", start: 0.519, end: 0.659 },
{ text: "you", start: 0.699, end: 0.819 },
{ text: "needed.", start: 0.859, end: 1.819 },
{ text: "Forty-seven", start: 1.86, end: 2.299 },
{ text: "percent", start: 2.399, end: 2.679 },
{ text: "of", start: 2.7, end: 2.799 },
{ text: "you", start: 2.839, end: 2.939 },
{ text: "said", start: 3.039, end: 3.179 },
{ text: "motion", start: 3.24, end: 3.559 },
{ text: "graphics,", start: 3.579, end: 4.599 },
{ text: "sixty-two", start: 4.679, end: 5.179 },
{ text: "percent", start: 5.299, end: 5.759 },
{ text: "said", start: 5.859, end: 5.98 },
{ text: "static", start: 6.079, end: 6.399 },
{ text: "content", start: 6.46, end: 6.879 },
{ text: "was", start: 6.92, end: 7.079 },
{ text: "costing", start: 7.099, end: 7.48 },
{ text: "you", start: 7.5, end: 7.579 },
{ text: "attention,", start: 7.679, end: 8.659 },
{ text: "and", start: 8.699, end: 8.86 },
{ text: "three", start: 8.88, end: 9.06 },
{ text: "out", start: 9.079, end: 9.18 },
{ text: "of", start: 9.199, end: 9.34 },
{ text: "four", start: 9.38, end: 9.799 },
{ text: "said", start: 9.84, end: 10.0 },
{ text: "you", start: 10.019, end: 10.159 },
{ text: "know", start: 10.179, end: 10.36 },
{ text: "the", start: 10.38, end: 10.42 },
{ text: "look", start: 10.519, end: 10.699 },
{ text: "you", start: 10.739, end: 10.859 },
{ text: "want", start: 10.98, end: 11.34 },
{ text: "but", start: 11.359, end: 11.52 },
{ text: "don't", start: 11.56, end: 11.779 },
{ text: "have", start: 11.819, end: 11.94 },
{ text: "the", start: 11.96, end: 12.06 },
{ text: "editing", start: 12.079, end: 12.4 },
{ text: "skills", start: 12.52, end: 12.86 },
{ text: "to", start: 12.88, end: 13.0 },
{ text: "get", start: 13.019, end: 13.18 },
{ text: "there.", start: 13.22, end: 14.22 },
{ text: "So", start: 14.239, end: 14.399 },
{ text: "we", start: 14.42, end: 14.52 },
{ text: "built", start: 14.619, end: 14.88 },
{ text: "Hyperframes", start: 15.079, end: 15.42 },
];
const container = document.getElementById("caption-container");
const tl = gsap.timeline({ paused: true });
if (!TRANSCRIPT || TRANSCRIPT.length === 0) {
@@ -57,7 +104,7 @@
// Group transcript into max 5 words per group
const groups = [];
let currentGroup = [];
TRANSCRIPT.forEach((word, index) => {
currentGroup.push(word);
// Group by 5 words OR if it's the last word
@@ -69,14 +116,14 @@
// Create DOM elements and timeline for each group
groups.forEach((group, i) => {
const box = document.createElement('div');
box.className = 'caption-box';
const box = document.createElement("div");
box.className = "caption-box";
box.id = `group-${i}`;
const text = document.createElement('div');
text.className = 'caption-text';
text.textContent = group.map(w => w.text).join(' ');
const text = document.createElement("div");
text.className = "caption-text";
text.textContent = group.map((w) => w.text).join(" ");
box.appendChild(text);
container.appendChild(box);
@@ -84,8 +131,8 @@
const endTime = group[group.length - 1].end;
// Hard cut animation (no fades) as requested
tl.set(box, { display: 'flex' }, startTime);
tl.set(box, { display: 'none' }, endTime);
tl.set(box, { display: "flex" }, startTime);
tl.set(box, { display: "none" }, endTime);
});
window.__timelines["captions"] = tl;
@@ -31,8 +31,8 @@
<style>
[data-composition-id="graphics"] {
font-family: 'Helvetica', Arial, sans-serif;
color: #0A1E3D;
font-family: "Helvetica", Arial, sans-serif;
color: #0a1e3d;
background: transparent;
width: 1920px;
height: 1080px;
@@ -56,9 +56,9 @@
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
background: #F2F2F2;
background: #f2f2f2;
padding: 40px;
border-left: 10px solid #D4A017;
border-left: 10px solid #d4a017;
box-shadow: 20px 20px 0px rgba(10, 30, 61, 0.1);
}
@@ -81,7 +81,7 @@
[data-composition-id="graphics"] .stat-value {
font-size: 140px;
font-weight: 900;
color: #D4A017;
color: #d4a017;
line-height: 0.8;
margin-bottom: 15px;
}
@@ -89,7 +89,7 @@
[data-composition-id="graphics"] .stat-label {
font-size: 24px;
font-weight: 300; /* Lighter weight */
color: #0A1E3D;
color: #0a1e3d;
letter-spacing: 2px;
text-transform: uppercase;
}
@@ -98,16 +98,16 @@
[data-composition-id="graphics"] .progress-container {
width: 100%;
height: 24px;
background: #E0E0E0;
background: #e0e0e0;
margin-top: 30px;
border: 2px solid #0A1E3D;
border: 2px solid #0a1e3d;
position: relative;
}
[data-composition-id="graphics"] .progress-bar {
width: 0%;
height: 100%;
background: #D4A017;
background: #d4a017;
}
/* Grid Blocks for Stat 3 */
@@ -120,23 +120,23 @@
[data-composition-id="graphics"] .block {
width: 80px;
height: 80px;
border: 3px solid #0A1E3D;
border: 3px solid #0a1e3d;
}
[data-composition-id="graphics"] .block.gold {
background: #D4A017;
background: #d4a017;
}
[data-composition-id="graphics"] .block.navy {
background: #0A1E3D;
background: #0a1e3d;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<script>
(function() {
(function () {
const tl = gsap.timeline({ paused: true });
// Timing Constants
const S1_START = 1.86;
const S1_END = 4.5;
@@ -144,55 +144,63 @@
const S2_END = 8.6;
const S3_START = 8.88;
const S3_END = 14.2;
const SLIDE_DUR = 0.25; // 250ms
const SHARP_EASE = "power2.out";
// Stat 1 Animation
tl.fromTo('#stat1',
{ x: -200, opacity: 0 },
{ x: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S1_START
tl.fromTo(
"#stat1",
{ x: -200, opacity: 0 },
{ x: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S1_START,
);
tl.to('#stat1',
{ x: 200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S1_END - SLIDE_DUR
tl.to(
"#stat1",
{ x: 200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S1_END - SLIDE_DUR,
);
// Stat 2 Animation
tl.fromTo('#stat2',
{ y: 200, opacity: 0 },
{ y: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S2_START
tl.fromTo(
"#stat2",
{ y: 200, opacity: 0 },
{ y: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S2_START,
);
// Progress bar fill
tl.to('#stat2 .progress-bar',
{ width: '62%', duration: S2_END - S2_START - (SLIDE_DUR * 2), ease: "none" },
S2_START + SLIDE_DUR
tl.to(
"#stat2 .progress-bar",
{ width: "62%", duration: S2_END - S2_START - SLIDE_DUR * 2, ease: "none" },
S2_START + SLIDE_DUR,
);
tl.to('#stat2',
{ y: -200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S2_END - SLIDE_DUR
tl.to(
"#stat2",
{ y: -200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S2_END - SLIDE_DUR,
);
// Stat 3 Animation
tl.fromTo('#stat3',
{ x: 200, opacity: 0 },
{ x: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S3_START
tl.fromTo(
"#stat3",
{ x: 200, opacity: 0 },
{ x: 0, opacity: 1, duration: SLIDE_DUR, ease: SHARP_EASE },
S3_START,
);
// Stagger blocks
tl.from('#stat3 .block',
{ scale: 0, duration: 0.3, stagger: 0.1, ease: "back.out(1.7)" },
S3_START + SLIDE_DUR
tl.from(
"#stat3 .block",
{ scale: 0, duration: 0.3, stagger: 0.1, ease: "back.out(1.7)" },
S3_START + SLIDE_DUR,
);
tl.to('#stat3',
{ x: -200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S3_END - SLIDE_DUR
tl.to(
"#stat3",
{ x: -200, opacity: 0, duration: SLIDE_DUR, ease: "power2.in" },
S3_END - SLIDE_DUR,
);
window.__timelines["graphics"] = tl;
})();
</script>
</div>
</template>
</template>
@@ -10,7 +10,7 @@
<style>
[data-composition-id="intro"] {
background-color: #F5F5F5; /* Off-white */
background-color: #f5f5f5; /* Off-white */
width: 1920px;
height: 1080px;
display: flex;
@@ -36,7 +36,7 @@
top: 50%;
width: 0px;
height: 12px;
background-color: #0A1E3D; /* Navy */
background-color: #0a1e3d; /* Navy */
transform: translateY(-180px); /* Positioned above the text */
}
@@ -48,7 +48,7 @@
}
[data-composition-id="intro"] .title {
color: #0A1E3D;
color: #0a1e3d;
font-size: 180px;
font-weight: 900; /* Black weight */
line-height: 0.9;
@@ -59,7 +59,7 @@
}
[data-composition-id="intro"] .subtitle {
color: #0A1E3D;
color: #0a1e3d;
font-size: 64px;
font-weight: 300; /* Lighter weight for contrast */
line-height: 1.2;
@@ -72,7 +72,7 @@
</style>
<script>
(function() {
(function () {
const tl = gsap.timeline({ paused: true });
// Mechanical timing: 200ms (0.2s)
@@ -80,32 +80,48 @@
const STAGGER = 0.1;
// 1. Animate the grid line first
tl.to('.grid-line', {
width: '1200px',
duration: 0.4,
ease: 'power4.out'
}, 0.2);
tl.to(
".grid-line",
{
width: "1200px",
duration: 0.4,
ease: "power4.out",
},
0.2,
);
// 2. Slide in the title
tl.to('.title', {
x: 0,
duration: MECHANICAL_DURATION,
ease: 'power2.inOut'
}, 0.5);
tl.to(
".title",
{
x: 0,
duration: MECHANICAL_DURATION,
ease: "power2.inOut",
},
0.5,
);
// 3. Slide in the subtitle with a slight stagger
tl.to('.subtitle', {
x: 0,
duration: MECHANICAL_DURATION,
ease: 'power2.inOut'
}, 0.5 + STAGGER);
tl.to(
".subtitle",
{
x: 0,
duration: MECHANICAL_DURATION,
ease: "power2.inOut",
},
0.5 + STAGGER,
);
// 4. Subtle ambient motion (slow drift) to keep it alive
tl.to('.text-wrapper', {
x: 30,
duration: 1.16, // Adjusted to fit 1.86s total
ease: 'none'
}, 0.7);
tl.to(
".text-wrapper",
{
x: 30,
duration: 1.16, // Adjusted to fit 1.86s total
ease: "none",
},
0.7,
);
window.__timelines["intro"] = tl;
})();
+198 -147
View File
@@ -1,172 +1,223 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Swiss Grid - Hyperframes</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
background-color: #F2F2F2;
overflow: hidden;
font-family: 'Helvetica', Arial, sans-serif;
}
body,
html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
background-color: #f2f2f2;
overflow: hidden;
font-family: "Helvetica", Arial, sans-serif;
}
#master-root {
width: 1920px;
height: 1080px;
position: relative;
}
#master-root {
width: 1920px;
height: 1080px;
position: relative;
}
.background-grid {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
.background-grid {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
/* A-roll styling */
#short_mag_cut_frame {
position: absolute;
border-radius: 8px; /* Required */
z-index: 1;
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
overflow: hidden;
background: #000;
}
/* A-roll styling */
#short_mag_cut_frame {
position: absolute;
border-radius: 8px; /* Required */
z-index: 1;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
overflow: hidden;
background: #000;
}
#short_mag_cut,
#short_mag_cut_frame > img.__render_frame__,
#short_mag_cut_frame > img.__preview_render_frame__ {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
display: block;
}
#short_mag_cut,
#short_mag_cut_frame > img.__render_frame__,
#short_mag_cut_frame > img.__preview_render_frame__ {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
display: block;
}
/* Overlay layers */
.overlay-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
/* Overlay layers */
.overlay-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
#intro-comp { z-index: 2; }
#graphics-comp { z-index: 3; }
#captions-comp { z-index: 4; }
#intro-comp {
z-index: 2;
}
#graphics-comp {
z-index: 3;
}
#captions-comp {
z-index: 4;
}
</style>
</head>
<body>
<div id="master-root" data-composition-id="master" data-width="1920" data-height="1080" data-duration="16.04">
<!-- Background Grid -->
<img id="bg-grid"
class="background-grid"
src="assets/swiss-grid.svg"
alt="Grid"
data-start="0"
data-duration="16.04"
data-track-index="0">
</head>
<body>
<div
id="master-root"
data-composition-id="master"
data-width="1920"
data-height="1080"
data-duration="16.04"
>
<!-- Background Grid -->
<img
id="bg-grid"
class="background-grid"
src="assets/swiss-grid.svg"
alt="Grid"
data-start="0"
data-duration="16.04"
data-track-index="0"
/>
<!-- A-roll Video -->
<div id="short_mag_cut_frame">
<video id="short_mag_cut"
src="__VIDEO_SRC__"
data-start="0"
data-duration="16.04"
data-track-index="1">
</video>
</div>
<!-- A-roll Video -->
<div id="short_mag_cut_frame">
<video
id="short_mag_cut"
src="__VIDEO_SRC__"
data-start="0"
data-duration="16.04"
data-track-index="1"
></video>
</div>
<!-- Intro Sub-composition -->
<div id="intro-comp"
class="overlay-layer"
data-composition-id="intro"
data-composition-src="compositions/intro.html"
data-start="0"
data-duration="1.86"
data-track-index="2">
</div>
<!-- Intro Sub-composition -->
<div
id="intro-comp"
class="overlay-layer"
data-composition-id="intro"
data-composition-src="compositions/intro.html"
data-start="0"
data-duration="1.86"
data-track-index="2"
></div>
<!-- Graphics Sub-composition -->
<div id="graphics-comp"
class="overlay-layer"
data-composition-id="graphics"
data-composition-src="compositions/graphics.html"
data-start="0"
data-duration="16.04"
data-track-index="3">
</div>
<!-- Graphics Sub-composition -->
<div
id="graphics-comp"
class="overlay-layer"
data-composition-id="graphics"
data-composition-src="compositions/graphics.html"
data-start="0"
data-duration="16.04"
data-track-index="3"
></div>
<!-- Captions Sub-composition -->
<div id="captions-comp"
class="overlay-layer"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="16.04"
data-track-index="4">
</div>
<!-- Captions Sub-composition -->
<div
id="captions-comp"
class="overlay-layer"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="16.04"
data-track-index="4"
></div>
<!-- Sound Effects -->
<audio id="sfx-intro" data-start="0" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat1" data-start="1.86" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat2" data-start="4.68" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat3" data-start="8.88" data-track-index="5" data-duration="1" src=""></audio>
<!-- Sound Effects -->
<audio id="sfx-intro" data-start="0" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat1" data-start="1.86" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat2" data-start="4.68" data-track-index="5" data-duration="1" src=""></audio>
<audio id="sfx-stat3" data-start="8.88" data-track-index="5" data-duration="1" src=""></audio>
<script>
window.__timelines = window.__timelines || {};
const masterTL = gsap.timeline({ paused: true });
const v = document.getElementById('short_mag_cut_frame');
<script>
window.__timelines = window.__timelines || {};
// --- A-ROLL MOVEMENT (Structured Swiss Layout) ---
// 1. Entrance (0-1.86s): Slide in from left, settle centered for Intro
masterTL.fromTo(v,
{ x: -1000, y: 120, width: 960, height: 840 },
{ x: 480, y: 120, width: 960, height: 840, duration: 0.8, ease: "power2.out" },
0
);
const masterTL = gsap.timeline({ paused: true });
const v = document.getElementById("short_mag_cut_frame");
// 2. Stat 1 (1.86s - 4.68s): Move to right side (Graphic is on left)
masterTL.to(v, {
x: 1080, y: 120, width: 720, height: 720,
duration: 0.25, ease: "expo.out"
}, 1.86);
// --- A-ROLL MOVEMENT (Structured Swiss Layout) ---
// 3. Stat 2 (4.68s - 8.88s): Stay right, zoom in slightly
masterTL.to(v, {
x: 1080, y: 60, width: 780, height: 780,
duration: 0.25, ease: "expo.out"
}, 4.68);
// 1. Entrance (0-1.86s): Slide in from left, settle centered for Intro
masterTL.fromTo(
v,
{ x: -1000, y: 120, width: 960, height: 840 },
{ x: 480, y: 120, width: 960, height: 840, duration: 0.8, ease: "power2.out" },
0,
);
// 4. Stat 3 (8.88s - 14.2s): Move to left side (Graphic is on right)
masterTL.to(v, {
x: 120, y: 120, width: 720, height: 720,
duration: 0.25, ease: "expo.out"
}, 8.88);
// 2. Stat 1 (1.86s - 4.68s): Move to right side (Graphic is on left)
masterTL.to(
v,
{
x: 1080,
y: 120,
width: 720,
height: 720,
duration: 0.25,
ease: "expo.out",
},
1.86,
);
// 5. Conclusion (14.2s - 16.04s): Center large
masterTL.to(v, {
x: 240, y: 60, width: 1440, height: 810,
duration: 0.5, ease: "expo.out"
}, 14.2);
// 3. Stat 2 (4.68s - 8.88s): Stay right, zoom in slightly
masterTL.to(
v,
{
x: 1080,
y: 60,
width: 780,
height: 780,
duration: 0.25,
ease: "expo.out",
},
4.68,
);
window.__timelines["master"] = masterTL;
</script>
// 4. Stat 3 (8.88s - 14.2s): Move to left side (Graphic is on right)
masterTL.to(
v,
{
x: 120,
y: 120,
width: 720,
height: 720,
duration: 0.25,
ease: "expo.out",
},
8.88,
);
// 5. Conclusion (14.2s - 16.04s): Center large
masterTL.to(
v,
{
x: 240,
y: 60,
width: 1440,
height: 810,
duration: 0.5,
ease: "expo.out",
},
14.2,
);
window.__timelines["master"] = masterTL;
</script>
</div>
</body>
</body>
</html>
@@ -39,9 +39,9 @@
font-size: 64px;
line-height: 1.1;
color: #000000;
background-color: #FFFFFF;
background-color: #ffffff;
padding: 15px 30px;
border-top: 8px solid #CC0000; /* Vignelli Red top border accent */
border-top: 8px solid #cc0000; /* Vignelli Red top border accent */
display: inline-block;
letter-spacing: -0.02em; /* Tight Helvetica spacing */
white-space: nowrap; /* Prevent wrapping at the element level */
@@ -49,29 +49,77 @@
</style>
<script>
(function() {
const TRANSCRIPT = [{'text': 'We', 'start': 0.14, 'end': 0.239}, {'text': 'asked', 'start': 0.28, 'end': 0.459}, {'text': 'what', 'start': 0.5, 'end': 0.619}, {'text': 'you', 'start': 0.659, 'end': 0.779}, {'text': 'needed.', 'start': 0.8, 'end': 1.179}, {'text': 'Forty-seven', 'start': 1.199, 'end': 1.619}, {'text': 'percent', 'start': 1.699, 'end': 1.96}, {'text': 'of', 'start': 1.979, 'end': 2.059}, {'text': 'you', 'start': 2.099, 'end': 2.299}, {'text': 'said', 'start': 2.319, 'end': 2.499}, {'text': 'motion', 'start': 2.559, 'end': 2.839}, {'text': 'graphics,', 'start': 2.899, 'end': 3.759}, {'text': 'sixty-two', 'start': 3.799, 'end': 4.159}, {'text': 'percent', 'start': 4.239, 'end': 4.559}, {'text': 'said', 'start': 4.639, 'end': 4.799}, {'text': 'static', 'start': 4.859, 'end': 5.199}, {'text': 'content', 'start': 5.239, 'end': 5.639}, {'text': 'was', 'start': 5.679, 'end': 5.779}, {'text': 'costing', 'start': 5.859, 'end': 6.219}, {'text': 'you', 'start': 6.259, 'end': 6.339}, {'text': 'attention,', 'start': 6.379, 'end': 7.299}, {'text': 'and', 'start': 7.319, 'end': 7.439}, {'text': 'three', 'start': 7.48, 'end': 7.599}, {'text': 'out', 'start': 7.679, 'end': 7.779}, {'text': 'of', 'start': 7.799, 'end': 7.879}, {'text': 'four', 'start': 7.94, 'end': 8.139}, {'text': 'said', 'start': 8.279, 'end': 8.46}, {'text': 'you', 'start': 8.519, 'end': 8.6}, {'text': 'know', 'start': 8.619, 'end': 8.739}, {'text': 'the', 'start': 8.8, 'end': 8.88}, {'text': 'look', 'start': 8.92, 'end': 9.079}, {'text': 'you', 'start': 9.119, 'end': 9.259}, {'text': 'want', 'start': 9.279, 'end': 9.619}, {'text': 'but', 'start': 9.779, 'end': 9.88}, {'text': "don't", 'start': 9.92, 'end': 10.1}, {'text': 'have', 'start': 10.159, 'end': 10.3}, {'text': 'the', 'start': 10.3, 'end': 10.42}, {'text': 'editing', 'start': 10.5, 'end': 10.779}, {'text': 'skills', 'start': 10.86, 'end': 11.139}, {'text': 'to', 'start': 11.159, 'end': 11.239}, {'text': 'get', 'start': 11.279, 'end': 11.439}, {'text': 'there.', 'start': 11.46, 'end': 12.239}, {'text': 'So', 'start': 12.3, 'end': 12.38}, {'text': 'we', 'start': 12.399, 'end': 12.519}, {'text': 'built', 'start': 12.539, 'end': 12.759}, {'text': 'Hyperframes', 'start': 12.84, 'end': 13.119}];
(function () {
const TRANSCRIPT = [
{ text: "We", start: 0.14, end: 0.239 },
{ text: "asked", start: 0.28, end: 0.459 },
{ text: "what", start: 0.5, end: 0.619 },
{ text: "you", start: 0.659, end: 0.779 },
{ text: "needed.", start: 0.8, end: 1.179 },
{ text: "Forty-seven", start: 1.199, end: 1.619 },
{ text: "percent", start: 1.699, end: 1.96 },
{ text: "of", start: 1.979, end: 2.059 },
{ text: "you", start: 2.099, end: 2.299 },
{ text: "said", start: 2.319, end: 2.499 },
{ text: "motion", start: 2.559, end: 2.839 },
{ text: "graphics,", start: 2.899, end: 3.759 },
{ text: "sixty-two", start: 3.799, end: 4.159 },
{ text: "percent", start: 4.239, end: 4.559 },
{ text: "said", start: 4.639, end: 4.799 },
{ text: "static", start: 4.859, end: 5.199 },
{ text: "content", start: 5.239, end: 5.639 },
{ text: "was", start: 5.679, end: 5.779 },
{ text: "costing", start: 5.859, end: 6.219 },
{ text: "you", start: 6.259, end: 6.339 },
{ text: "attention,", start: 6.379, end: 7.299 },
{ text: "and", start: 7.319, end: 7.439 },
{ text: "three", start: 7.48, end: 7.599 },
{ text: "out", start: 7.679, end: 7.779 },
{ text: "of", start: 7.799, end: 7.879 },
{ text: "four", start: 7.94, end: 8.139 },
{ text: "said", start: 8.279, end: 8.46 },
{ text: "you", start: 8.519, end: 8.6 },
{ text: "know", start: 8.619, end: 8.739 },
{ text: "the", start: 8.8, end: 8.88 },
{ text: "look", start: 8.92, end: 9.079 },
{ text: "you", start: 9.119, end: 9.259 },
{ text: "want", start: 9.279, end: 9.619 },
{ text: "but", start: 9.779, end: 9.88 },
{ text: "don't", start: 9.92, end: 10.1 },
{ text: "have", start: 10.159, end: 10.3 },
{ text: "the", start: 10.3, end: 10.42 },
{ text: "editing", start: 10.5, end: 10.779 },
{ text: "skills", start: 10.86, end: 11.139 },
{ text: "to", start: 11.159, end: 11.239 },
{ text: "get", start: 11.279, end: 11.439 },
{ text: "there.", start: 11.46, end: 12.239 },
{ text: "So", start: 12.3, end: 12.38 },
{ text: "we", start: 12.399, end: 12.519 },
{ text: "built", start: 12.539, end: 12.759 },
{ text: "Hyperframes", start: 12.84, end: 13.119 },
];
const tl = gsap.timeline({ paused: true });
const container = document.getElementById('captions-container');
const container = document.getElementById("captions-container");
// Group words into single lines (max words or based on pauses/sentence ends)
function groupTranscript(transcript, maxWords = 3) {
const groups = [];
let currentGroup = [];
transcript.forEach((word, index) => {
currentGroup.push(word);
const nextWord = transcript[index + 1];
const isPause = nextWord && (nextWord.start - word.end > 0.15);
const isSentenceEnd = word.text.includes('.') || word.text.includes('?') || word.text.includes('!');
const isPause = nextWord && nextWord.start - word.end > 0.15;
const isSentenceEnd =
word.text.includes(".") || word.text.includes("?") || word.text.includes("!");
if (currentGroup.length >= maxWords || isPause || isSentenceEnd || !nextWord) {
groups.push({
words: currentGroup,
start: currentGroup[0].start,
end: currentGroup[currentGroup.length - 1].end,
text: currentGroup.map(w => w.text).join(' ')
text: currentGroup.map((w) => w.text).join(" "),
});
currentGroup = [];
}
@@ -82,37 +130,42 @@
const captionGroups = groupTranscript(TRANSCRIPT);
captionGroups.forEach((group, index) => {
const div = document.createElement('div');
div.className = 'caption-group';
const div = document.createElement("div");
div.className = "caption-group";
div.id = `group-${index}`;
const textSpan = document.createElement('span');
textSpan.className = 'caption-text';
const textSpan = document.createElement("span");
textSpan.className = "caption-text";
textSpan.innerText = group.text;
div.appendChild(textSpan);
container.appendChild(div);
// Animation: Modern "expo.out" transitions
// Entrance
tl.fromTo(div,
tl.fromTo(
div,
{ opacity: 0, y: 20 },
{
opacity: 1,
y: 0,
duration: 0.4,
ease: "expo.out"
},
group.start
ease: "expo.out",
},
group.start,
);
// Exit
tl.to(div, {
opacity: 0,
y: -10,
duration: 0.3,
ease: "expo.out"
}, group.end - 0.3);
tl.to(
div,
{
opacity: 0,
y: -10,
duration: 0.3,
ease: "expo.out",
},
group.end - 0.3,
);
});
window.__timelines["captions"] = tl;
@@ -33,7 +33,7 @@
<div class="overlay-item editing-skills-stat" id="stat-3-4">
<div class="text-block">
<span class="highlight">3 out of 4</span>
<br>lack editing skills
<br />lack editing skills
</div>
<div class="side-bar"></div>
</div>
@@ -51,7 +51,7 @@
position: relative;
width: 1080px;
height: 1920px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #000000;
overflow: hidden;
pointer-events: none;
@@ -87,13 +87,13 @@
left: 0;
width: 540px; /* 3 columns */
height: 240px;
background: #FFFFFF;
background: #ffffff;
flex-direction: row;
align-items: stretch;
}
[data-composition-id="overlays"] #stat-47 .red-bar {
width: 20px;
background: #CC0000;
background: #cc0000;
}
[data-composition-id="overlays"] #stat-47 .stat-content {
padding: 40px;
@@ -128,7 +128,7 @@
left: 0;
width: 100%;
height: 100%;
background: #1A1A1A;
background: #1a1a1a;
}
[data-composition-id="overlays"] #stat-62 .full-content {
position: relative;
@@ -142,14 +142,14 @@
[data-composition-id="overlays"] #stat-62 .large-number {
font-size: 400px;
font-weight: 900;
color: #FFFFFF;
color: #ffffff;
line-height: 0.8;
letter-spacing: -10px;
}
[data-composition-id="overlays"] #stat-62 .large-label {
font-size: 80px;
font-weight: 700;
color: #FFFFFF;
color: #ffffff;
text-transform: uppercase;
margin-top: 20px;
max-width: 600px;
@@ -160,7 +160,7 @@
right: 0;
width: 180px; /* 1 column */
height: 100%;
background: #CC0000;
background: #cc0000;
}
/* 3. 3 out of 4 Stat Styles */
@@ -168,7 +168,7 @@
top: 400px;
right: 0;
width: 360px; /* 2 columns */
background: #FFFFFF;
background: #ffffff;
padding: 40px;
flex-direction: row-reverse;
}
@@ -179,7 +179,7 @@
text-align: right;
}
[data-composition-id="overlays"] #stat-3-4 .highlight {
color: #CC0000;
color: #cc0000;
font-size: 64px;
font-weight: 900;
}
@@ -216,7 +216,7 @@
[data-composition-id="overlays"] #branding .logo-underline {
width: 100%;
height: 8px;
background: #CC0000;
background: #cc0000;
margin-top: 10px;
transform-origin: left;
}
@@ -224,45 +224,96 @@
<script>
const tl = gsap.timeline({ paused: true });
const TRANSCRIPT = [{'text': 'We', 'start': 0.14, 'end': 0.239}, {'text': 'asked', 'start': 0.28, 'end': 0.459}, {'text': 'what', 'start': 0.5, 'end': 0.619}, {'text': 'you', 'start': 0.659, 'end': 0.779}, {'text': 'needed.', 'start': 0.8, 'end': 1.179}, {'text': 'Forty-seven', 'start': 1.199, 'end': 1.619}, {'text': 'percent', 'start': 1.699, 'end': 1.96}, {'text': 'of', 'start': 1.979, 'end': 2.059}, {'text': 'you', 'start': 2.099, 'end': 2.299}, {'text': 'said', 'start': 2.319, 'end': 2.499}, {'text': 'motion', 'start': 2.559, 'end': 2.839}, {'text': 'graphics,', 'start': 2.899, 'end': 3.759}, {'text': 'sixty-two', 'start': 3.799, 'end': 4.159}, {'text': 'percent', 'start': 4.239, 'end': 4.559}, {'text': 'said', 'start': 4.639, 'end': 4.799}, {'text': 'static', 'start': 4.859, 'end': 5.199}, {'text': 'content', 'start': 5.239, 'end': 5.639}, {'text': 'was', 'start': 5.679, 'end': 5.779}, {'text': 'costing', 'start': 5.859, 'end': 6.219}, {'text': 'you', 'start': 6.259, 'end': 6.339}, {'text': 'attention,', 'start': 6.379, 'end': 7.299}, {'text': 'and', 'start': 7.319, 'end': 7.439}, {'text': 'three', 'start': 7.48, 'end': 7.599}, {'text': 'out', 'start': 7.679, 'end': 7.779}, {'text': 'of', 'start': 7.799, 'end': 7.879}, {'text': 'four', 'start': 7.94, 'end': 8.139}, {'text': 'said', 'start': 8.279, 'end': 8.46}, {'text': 'you', 'start': 8.519, 'end': 8.6}, {'text': 'know', 'start': 8.619, 'end': 8.739}, {'text': 'the', 'start': 8.8, 'end': 8.88}, {'text': 'look', 'start': 8.92, 'end': 9.079}, {'text': 'you', 'start': 9.119, 'end': 9.259}, {'text': 'want', 'start': 9.279, 'end': 9.619}, {'text': 'but', 'start': 9.779, 'end': 9.88}, {'text': "don't", 'start': 9.92, 'end': 10.1}, {'text': 'have', 'start': 10.159, 'end': 10.3}, {'text': 'the', 'start': 10.3, 'end': 10.42}, {'text': 'editing', 'start': 10.5, 'end': 10.779}, {'text': 'skills', 'start': 10.86, 'end': 11.139}, {'text': 'to', 'start': 11.159, 'end': 11.239}, {'text': 'get', 'start': 11.279, 'end': 11.439}, {'text': 'there.', 'start': 11.46, 'end': 12.239}, {'text': 'So', 'start': 12.3, 'end': 12.38}, {'text': 'we', 'start': 12.399, 'end': 12.519}, {'text': 'built', 'start': 12.539, 'end': 12.759}, {'text': 'Hyperframes', 'start': 12.84, 'end': 13.119}];
const TRANSCRIPT = [
{ text: "We", start: 0.14, end: 0.239 },
{ text: "asked", start: 0.28, end: 0.459 },
{ text: "what", start: 0.5, end: 0.619 },
{ text: "you", start: 0.659, end: 0.779 },
{ text: "needed.", start: 0.8, end: 1.179 },
{ text: "Forty-seven", start: 1.199, end: 1.619 },
{ text: "percent", start: 1.699, end: 1.96 },
{ text: "of", start: 1.979, end: 2.059 },
{ text: "you", start: 2.099, end: 2.299 },
{ text: "said", start: 2.319, end: 2.499 },
{ text: "motion", start: 2.559, end: 2.839 },
{ text: "graphics,", start: 2.899, end: 3.759 },
{ text: "sixty-two", start: 3.799, end: 4.159 },
{ text: "percent", start: 4.239, end: 4.559 },
{ text: "said", start: 4.639, end: 4.799 },
{ text: "static", start: 4.859, end: 5.199 },
{ text: "content", start: 5.239, end: 5.639 },
{ text: "was", start: 5.679, end: 5.779 },
{ text: "costing", start: 5.859, end: 6.219 },
{ text: "you", start: 6.259, end: 6.339 },
{ text: "attention,", start: 6.379, end: 7.299 },
{ text: "and", start: 7.319, end: 7.439 },
{ text: "three", start: 7.48, end: 7.599 },
{ text: "out", start: 7.679, end: 7.779 },
{ text: "of", start: 7.799, end: 7.879 },
{ text: "four", start: 7.94, end: 8.139 },
{ text: "said", start: 8.279, end: 8.46 },
{ text: "you", start: 8.519, end: 8.6 },
{ text: "know", start: 8.619, end: 8.739 },
{ text: "the", start: 8.8, end: 8.88 },
{ text: "look", start: 8.92, end: 9.079 },
{ text: "you", start: 9.119, end: 9.259 },
{ text: "want", start: 9.279, end: 9.619 },
{ text: "but", start: 9.779, end: 9.88 },
{ text: "don't", start: 9.92, end: 10.1 },
{ text: "have", start: 10.159, end: 10.3 },
{ text: "the", start: 10.3, end: 10.42 },
{ text: "editing", start: 10.5, end: 10.779 },
{ text: "skills", start: 10.86, end: 11.139 },
{ text: "to", start: 11.159, end: 11.239 },
{ text: "get", start: 11.279, end: 11.439 },
{ text: "there.", start: 11.46, end: 12.239 },
{ text: "So", start: 12.3, end: 12.38 },
{ text: "we", start: 12.399, end: 12.519 },
{ text: "built", start: 12.539, end: 12.759 },
{ text: "Hyperframes", start: 12.84, end: 13.119 },
];
// Requirement 1: "47% Motion Graphics" (Start: 1.199, End: 3.759)
// Positioned in bottom half, columns 1-3.
tl.fromTo("#stat-47",
{ x: -540, opacity: 1 },
{ x: 0, duration: 0.8, ease: "expo.out" },
1.199
);
tl.to("#stat-47",
{ x: -540, duration: 0.6, ease: "expo.in" },
3.759 - 0.6
tl.fromTo(
"#stat-47",
{ x: -540, opacity: 1 },
{ x: 0, duration: 0.8, ease: "expo.out" },
1.199,
);
tl.to("#stat-47", { x: -540, duration: 0.6, ease: "expo.in" }, 3.759 - 0.6);
// Requirement 2: "62% Static Content" (Start: 3.799, End: 7.299)
// Full canvas moment. Large bold typography across columns.
tl.set("#stat-62", { opacity: 1 }, 3.799);
tl.from("#stat-62 .bg-charcoal", { x: "100%", duration: 0.8, ease: "expo.out" }, 3.799);
tl.from("#stat-62 .red-accent", { x: "100%", duration: 0.8, ease: "expo.out" }, 3.899);
tl.from("#stat-62 .large-number", { y: 100, opacity: 0, duration: 1, ease: "expo.out" }, 4.099);
tl.from(
"#stat-62 .large-number",
{ y: 100, opacity: 0, duration: 1, ease: "expo.out" },
4.099,
);
tl.from("#stat-62 .large-label", { y: 50, opacity: 0, duration: 1, ease: "expo.out" }, 4.299);
tl.to("#stat-62", { x: "-100%", duration: 0.8, ease: "expo.in" }, 7.299 - 0.8);
// Requirement 3: "3 out of 4 lack editing skills" (Start: 7.319, End: 12.239)
// Positioned in columns 5-6 (right side) to avoid face (x: 300-776)
tl.fromTo("#stat-3-4",
{ x: 360, opacity: 1 },
{ x: 0, duration: 0.8, ease: "expo.out" },
7.319
);
tl.to("#stat-3-4",
{ x: 360, duration: 0.6, ease: "expo.in" },
12.239 - 0.6
tl.fromTo(
"#stat-3-4",
{ x: 360, opacity: 1 },
{ x: 0, duration: 0.8, ease: "expo.out" },
7.319,
);
tl.to("#stat-3-4", { x: 360, duration: 0.6, ease: "expo.in" }, 12.239 - 0.6);
// Requirement 4: "Hyperframes" (Start: 12.84, End: 13.84)
tl.set("#branding", { opacity: 1 }, 12.84);
tl.from("#branding .logo-text", { y: 20, opacity: 0, duration: 0.6, ease: "expo.out" }, 12.84);
tl.from(
"#branding .logo-text",
{ y: 20, opacity: 0, duration: 0.6, ease: "expo.out" },
12.84,
);
tl.from("#branding .logo-underline", { scaleX: 0, duration: 0.8, ease: "expo.out" }, 13.04);
window.__timelines["overlays"] = tl;
+152 -145
View File
@@ -1,171 +1,178 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<head>
<meta charset="UTF-8" />
<title>Massimo Vignelli Video</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<style>
body,
html {
margin: 0;
padding: 0;
background: #FFFFFF;
overflow: hidden;
width: 1080px;
height: 1920px;
font-family: 'Helvetica', Arial, sans-serif;
}
body,
html {
margin: 0;
padding: 0;
background: #ffffff;
overflow: hidden;
width: 1080px;
height: 1920px;
font-family: "Helvetica", Arial, sans-serif;
}
/* 6-Column Grid System */
.grid-container {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
display: grid;
grid-template-columns: repeat(6, 1fr);
pointer-events: none;
z-index: 1000;
opacity: 0; /* Keep grid invisible but present for layout references */
}
/* 6-Column Grid System */
.grid-container {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
display: grid;
grid-template-columns: repeat(6, 1fr);
pointer-events: none;
z-index: 1000;
opacity: 0; /* Keep grid invisible but present for layout references */
}
.grid-column {
border-right: 1px solid rgba(204, 0, 0, 0.2); /* Vignelli Red accent */
}
.grid-column {
border-right: 1px solid rgba(204, 0, 0, 0.2); /* Vignelli Red accent */
}
#main-composition {
position: relative;
width: 1080px;
height: 1920px;
background: #FFFFFF;
overflow: hidden;
}
#main-composition {
position: relative;
width: 1080px;
height: 1920px;
background: #ffffff;
overflow: hidden;
}
/* Layer Hosts */
#a-roll-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
overflow: hidden;
}
/* Layer Hosts */
#a-roll-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
overflow: hidden;
}
#a-roll,
#a-roll-wrapper img.__render_frame__,
#a-roll-wrapper img.__preview_render_frame__ {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
#a-roll,
#a-roll-wrapper img.__render_frame__,
#a-roll-wrapper img.__preview_render_frame__ {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
#overlays-comp,
#captions-comp {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
pointer-events: none;
}
#overlays-comp,
#captions-comp {
position: absolute;
top: 0;
left: 0;
width: 1080px;
height: 1920px;
pointer-events: none;
}
#overlays-comp {
z-index: 20;
}
#overlays-comp {
z-index: 20;
}
#captions-comp {
z-index: 30;
}
#captions-comp {
z-index: 30;
}
/* Curtain Transition Layer */
.curtain {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: #1A1A1A;
z-index: 25;
pointer-events: none;
}
.curtain.red {
background: #CC0000;
z-index: 26;
}
/* Curtain Transition Layer */
.curtain {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: #1a1a1a;
z-index: 25;
pointer-events: none;
}
.curtain.red {
background: #cc0000;
z-index: 26;
}
</style>
</head>
<body>
<div id="main-composition" data-composition-id="main-comp" data-width="1080" data-height="1920" data-duration="13.88">
<!-- A-Roll -->
<div id="a-roll-wrapper">
<video id="a-roll"
src="__VIDEO_SRC__"
data-start="0"
data-duration="13.88"
data-track-index="0">
</video>
</div>
</head>
<body>
<div
id="main-composition"
data-composition-id="main-comp"
data-width="1080"
data-height="1920"
data-duration="13.88"
>
<!-- A-Roll -->
<div id="a-roll-wrapper">
<video
id="a-roll"
src="__VIDEO_SRC__"
data-start="0"
data-duration="13.88"
data-track-index="0"
></video>
</div>
<!-- Transitions -->
<div id="curtain-black" class="curtain"></div>
<div id="curtain-red" class="curtain red"></div>
<!-- Transitions -->
<div id="curtain-black" class="curtain"></div>
<div id="curtain-red" class="curtain red"></div>
<!-- Overlays Composition -->
<div id="overlays-comp"
data-composition-id="overlays"
data-composition-src="compositions/overlays.html"
data-start="0"
data-duration="13.88"
data-track-index="2">
</div>
<!-- Overlays Composition -->
<div
id="overlays-comp"
data-composition-id="overlays"
data-composition-src="compositions/overlays.html"
data-start="0"
data-duration="13.88"
data-track-index="2"
></div>
<!-- Captions Composition -->
<div id="captions-comp"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="13.88"
data-track-index="3">
</div>
<!-- Captions Composition -->
<div
id="captions-comp"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="13.88"
data-track-index="3"
></div>
<!-- Grid Visualization -->
<div class="grid-container">
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
</div>
<!-- Grid Visualization -->
<div class="grid-container">
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
<div class="grid-column"></div>
</div>
<script>
const tl = gsap.timeline({ paused: true });
<script>
const tl = gsap.timeline({ paused: true });
// Transition: Curtain Pull logic
// A-roll leaves the screen at least once.
// Timing: Let's do a curtain pull at 3.7s (transitioning to the 62% stat)
// and return at 7.3s (end of attention stat).
// Transition: Curtain Pull logic
// A-roll leaves the screen at least once.
// Timing: Let's do a curtain pull at 3.7s (transitioning to the 62% stat)
// and return at 7.3s (end of attention stat).
// Curtain Out (A-roll hidden)
tl.to("#curtain-black", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 3.5);
tl.to("#a-roll-wrapper", { opacity: 0, duration: 0 }, 3.7);
tl.to("#curtain-black", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 3.7);
// Curtain Out (A-roll hidden)
tl.to("#curtain-black", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 3.5);
tl.to("#a-roll-wrapper", { opacity: 0, duration: 0 }, 3.7);
tl.to("#curtain-black", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 3.7);
// Curtain In (A-roll return)
tl.set("#curtain-red", { left: "-100%" }, 7.1);
tl.to("#curtain-red", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 7.1);
tl.to("#a-roll-wrapper", { opacity: 1, duration: 0 }, 7.3);
tl.to("#curtain-red", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 7.3);
// Curtain In (A-roll return)
tl.set("#curtain-red", { left: "-100%" }, 7.1);
tl.to("#curtain-red", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 7.1);
tl.to("#a-roll-wrapper", { opacity: 1, duration: 0 }, 7.3);
tl.to("#curtain-red", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 7.3);
window.__timelines["main-comp"] = tl;
</script>
window.__timelines["main-comp"] = tl;
</script>
</div>
</body>
</body>
</html>
@@ -18,7 +18,7 @@
}
[data-composition-id="captions"] .caption-box {
background-color: #7A6248;
background-color: #7a6248;
padding: 12px 32px;
border-radius: 24px;
display: flex;
@@ -31,8 +31,8 @@
}
[data-composition-id="captions"] .caption-text {
color: #F5F0E0;
font-family: 'Outfit', sans-serif;
color: #f5f0e0;
font-family: "Outfit", sans-serif;
font-size: 48px;
font-weight: 700;
text-align: center;
@@ -42,54 +42,54 @@
</style>
<script>
(function() {
(function () {
const script = [
{"text": "We", "start": 0.119, "end": 0.259},
{"text": "asked", "start": 0.319, "end": 0.479},
{"text": "what", "start": 0.519, "end": 0.659},
{"text": "you", "start": 0.699, "end": 0.819},
{"text": "needed.", "start": 0.859, "end": 1.819},
{"text": "Forty-seven", "start": 1.86, "end": 2.299},
{"text": "percent", "start": 2.399, "end": 2.679},
{"text": "of", "start": 2.7, "end": 2.799},
{"text": "you", "start": 2.839, "end": 2.939},
{"text": "said", "start": 3.039, "end": 3.179},
{"text": "motion", "start": 3.24, "end": 3.559},
{"text": "graphics,", "start": 3.579, "end": 4.599},
{"text": "sixty-two", "start": 4.679, "end": 5.179},
{"text": "percent", "start": 5.299, "end": 5.759},
{"text": "said", "start": 5.859, "end": 5.98},
{"text": "static", "start": 6.079, "end": 6.399},
{"text": "content", "start": 6.46, "end": 6.879},
{"text": "was", "start": 6.92, "end": 7.079},
{"text": "costing", "start": 7.099, "end": 7.48},
{"text": "you", "start": 7.5, "end": 7.579},
{"text": "attention,", "start": 7.679, "end": 8.659},
{"text": "and", "start": 8.699, "end": 8.86},
{"text": "three", "start": 8.88, "end": 9.06},
{"text": "out", "start": 9.079, "end": 9.18},
{"text": "of", "start": 9.199, "end": 9.34},
{"text": "four", "start": 9.38, "end": 9.799},
{"text": "said", "start": 9.84, "end": 10.0},
{"text": "you", "start": 10.019, "end": 10.159},
{"text": "know", "start": 10.179, "end": 10.36},
{"text": "the", "start": 10.38, "end": 10.42},
{"text": "look", "start": 10.519, "end": 10.699},
{"text": "you", "start": 10.739, "end": 10.859},
{"text": "want", "start": 10.98, "end": 11.34},
{"text": "but", "start": 11.359, "end": 11.52},
{"text": "don't", "start": 11.56, "end": 11.779},
{"text": "have", "start": 11.819, "end": 11.94},
{"text": "the", "start": 11.96, "end": 12.06},
{"text": "editing", "start": 12.079, "end": 12.4},
{"text": "skills", "start": 12.52, "end": 12.86},
{"text": "to", "start": 12.88, "end": 13.0},
{"text": "get", "start": 13.019, "end": 13.18},
{"text": "there.", "start": 13.22, "end": 14.22},
{"text": "So", "start": 14.239, "end": 14.399},
{"text": "we", "start": 14.42, "end": 14.52},
{"text": "built", "start": 14.619, "end": 14.88},
{"text": "Hyperframes.", "start": 15.079, "end": 16.02}
{ text: "We", start: 0.119, end: 0.259 },
{ text: "asked", start: 0.319, end: 0.479 },
{ text: "what", start: 0.519, end: 0.659 },
{ text: "you", start: 0.699, end: 0.819 },
{ text: "needed.", start: 0.859, end: 1.819 },
{ text: "Forty-seven", start: 1.86, end: 2.299 },
{ text: "percent", start: 2.399, end: 2.679 },
{ text: "of", start: 2.7, end: 2.799 },
{ text: "you", start: 2.839, end: 2.939 },
{ text: "said", start: 3.039, end: 3.179 },
{ text: "motion", start: 3.24, end: 3.559 },
{ text: "graphics,", start: 3.579, end: 4.599 },
{ text: "sixty-two", start: 4.679, end: 5.179 },
{ text: "percent", start: 5.299, end: 5.759 },
{ text: "said", start: 5.859, end: 5.98 },
{ text: "static", start: 6.079, end: 6.399 },
{ text: "content", start: 6.46, end: 6.879 },
{ text: "was", start: 6.92, end: 7.079 },
{ text: "costing", start: 7.099, end: 7.48 },
{ text: "you", start: 7.5, end: 7.579 },
{ text: "attention,", start: 7.679, end: 8.659 },
{ text: "and", start: 8.699, end: 8.86 },
{ text: "three", start: 8.88, end: 9.06 },
{ text: "out", start: 9.079, end: 9.18 },
{ text: "of", start: 9.199, end: 9.34 },
{ text: "four", start: 9.38, end: 9.799 },
{ text: "said", start: 9.84, end: 10.0 },
{ text: "you", start: 10.019, end: 10.159 },
{ text: "know", start: 10.179, end: 10.36 },
{ text: "the", start: 10.38, end: 10.42 },
{ text: "look", start: 10.519, end: 10.699 },
{ text: "you", start: 10.739, end: 10.859 },
{ text: "want", start: 10.98, end: 11.34 },
{ text: "but", start: 11.359, end: 11.52 },
{ text: "don't", start: 11.56, end: 11.779 },
{ text: "have", start: 11.819, end: 11.94 },
{ text: "the", start: 11.96, end: 12.06 },
{ text: "editing", start: 12.079, end: 12.4 },
{ text: "skills", start: 12.52, end: 12.86 },
{ text: "to", start: 12.88, end: 13.0 },
{ text: "get", start: 13.019, end: 13.18 },
{ text: "there.", start: 13.22, end: 14.22 },
{ text: "So", start: 14.239, end: 14.399 },
{ text: "we", start: 14.42, end: 14.52 },
{ text: "built", start: 14.619, end: 14.88 },
{ text: "Hyperframes.", start: 15.079, end: 16.02 },
];
// Group words into lines (max 5 words per line)
@@ -97,9 +97,9 @@
for (let i = 0; i < script.length; i += 5) {
const lineWords = script.slice(i, i + 5);
lines.push({
text: lineWords.map(w => w.text).join(' '),
text: lineWords.map((w) => w.text).join(" "),
start: lineWords[0].start,
end: lineWords[lineWords.length - 1].end
end: lineWords[lineWords.length - 1].end,
});
}
@@ -109,21 +109,29 @@
lines.forEach((line, index) => {
// Fade in and set text
tl.to(box, {
opacity: 1,
duration: 0.1,
ease: "power2.out",
onStart: () => {
textEl.textContent = line.text;
}
}, line.start);
tl.to(
box,
{
opacity: 1,
duration: 0.1,
ease: "power2.out",
onStart: () => {
textEl.textContent = line.text;
},
},
line.start,
);
// Fade out at the end of the line
tl.to(box, {
opacity: 0,
duration: 0.1,
ease: "power2.in"
}, line.end);
tl.to(
box,
{
opacity: 0,
duration: 0.1,
ease: "power2.in",
},
line.end,
);
});
window.__timelines["captions"] = tl;
@@ -17,7 +17,10 @@
<div id="moment-3" class="moment rect-stat">
<div class="icon-shape">
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<path d="M20,20 Q50,0 80,20 Q100,50 80,80 Q50,100 20,80 Q0,50 20,20" fill="currentColor" />
<path
d="M20,20 Q50,0 80,20 Q100,50 80,80 Q50,100 20,80 Q0,50 20,20"
fill="currentColor"
/>
</svg>
</div>
<div class="stat-text">Editing Skills</div>
@@ -28,7 +31,7 @@
position: relative;
width: 1920px;
height: 1080px;
font-family: 'Outfit', sans-serif;
font-family: "Outfit", sans-serif;
color: white;
overflow: hidden;
}
@@ -46,7 +49,7 @@
[data-composition-id="graphics"] #moment-1 {
width: 500px;
height: 500px;
background-color: #3B5E3A;
background-color: #3b5e3a;
border-radius: 50%;
left: 1400px;
top: 540px;
@@ -72,7 +75,7 @@
[data-composition-id="graphics"] #moment-2 {
width: 500px;
height: 220px;
background-color: #CC8832;
background-color: #cc8832;
border-radius: 110px;
left: 960px;
top: 200px;
@@ -83,7 +86,7 @@
[data-composition-id="graphics"] #moment-3 {
width: 550px;
height: 180px;
background-color: #C45D3E;
background-color: #c45d3e;
border-radius: 40px;
left: 400px;
top: 540px;
@@ -117,41 +120,44 @@
</style>
<script>
(function() {
(function () {
const tl = gsap.timeline({ paused: true });
// Moment 1: 1.8s - 4.5s
// Gentle drift into place and settle
tl.fromTo('#moment-1',
{ opacity: 0, x: '+=40', y: '+=15', scale: 0.8 },
{ opacity: 1, x: 0, y: 0, scale: 1, duration: 1.2, ease: 'back.out(1.7)' },
1.8
tl.fromTo(
"#moment-1",
{ opacity: 0, x: "+=40", y: "+=15", scale: 0.8 },
{ opacity: 1, x: 0, y: 0, scale: 1, duration: 1.2, ease: "back.out(1.7)" },
1.8,
);
// Hold until 4.5s, then fade out
tl.to('#moment-1', { opacity: 0, scale: 0.8, duration: 0.3, ease: 'power2.in' }, 4.2);
tl.to("#moment-1", { opacity: 0, scale: 0.8, duration: 0.3, ease: "power2.in" }, 4.2);
// Moment 2: 4.6s - 8.6s
// Gentle drift into place and settle
tl.fromTo('#moment-2',
{ opacity: 0, y: '-=40', x: '+=10', scale: 0.8 },
{ opacity: 1, y: 0, x: 0, scale: 1, duration: 1.2, ease: 'back.out(1.7)' },
4.6
tl.fromTo(
"#moment-2",
{ opacity: 0, y: "-=40", x: "+=10", scale: 0.8 },
{ opacity: 1, y: 0, x: 0, scale: 1, duration: 1.2, ease: "back.out(1.7)" },
4.6,
);
// Hold until 8.6s, then fade out
tl.to('#moment-2', { opacity: 0, scale: 0.8, duration: 0.3, ease: 'power2.in' }, 8.3);
tl.to("#moment-2", { opacity: 0, scale: 0.8, duration: 0.3, ease: "power2.in" }, 8.3);
// Moment 3: 8.8s - 14s
// Gentle drift into place and settle
tl.fromTo('#moment-3',
{ opacity: 0, x: '-=40', y: '-=10', scale: 0.8 },
{ opacity: 1, x: 0, y: 0, scale: 1, duration: 1.2, ease: 'back.out(1.7)' },
8.8
tl.fromTo(
"#moment-3",
{ opacity: 0, x: "-=40", y: "-=10", scale: 0.8 },
{ opacity: 1, x: 0, y: 0, scale: 1, duration: 1.2, ease: "back.out(1.7)" },
8.8,
);
// Hold until end (14s)
tl.to('#moment-3', { opacity: 0, duration: 0.5, ease: 'power2.in' }, 13.5);
tl.to("#moment-3", { opacity: 0, duration: 0.5, ease: "power2.in" }, 13.5);
window.__timelines["graphics"] = tl;
})();
</script>
</div>
</template>
</template>
@@ -9,7 +9,7 @@
<style>
/* Import a rounded humanist sans-serif font */
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;600&display=swap');
@import url("https://fonts.googleapis.com/css2?family=Outfit:wght@400;600&display=swap");
[data-composition-id="intro"] .container {
width: 100%;
@@ -18,15 +18,15 @@
justify-content: flex-start; /* Align to left for speaker card */
align-items: center;
padding-left: 5%;
font-family: 'Outfit', sans-serif;
font-family: "Outfit", sans-serif;
background: transparent;
}
[data-composition-id="intro"] .title-card {
background-color: #3B5E3A; /* Forest Green for contrast */
background-color: #3b5e3a; /* Forest Green for contrast */
padding: 40px 60px;
border-radius: 30px;
box-shadow: 0 15px 40px rgba(0,0,0,0.2);
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
text-align: left;
opacity: 0;
transform: translateX(-100%); /* Start off-screen left */
@@ -35,7 +35,7 @@
[data-composition-id="intro"] .title {
font-size: 100px;
font-weight: 600;
color: #F5F0E0; /* Cream text on green card */
color: #f5f0e0; /* Cream text on green card */
margin: 0;
line-height: 1.1;
letter-spacing: -2px;
@@ -44,31 +44,39 @@
[data-composition-id="intro"] .subtitle {
font-size: 50px;
font-weight: 400;
color: #CC8832; /* Ochre accent */
color: #cc8832; /* Ochre accent */
margin: 10px 0 0 0;
line-height: 1.2;
}
</style>
<script>
(function() {
(function () {
const tl = gsap.timeline({ paused: true });
// Animation: Speaker card slides in from the left
tl.to('[data-composition-id="intro"] .title-card', {
opacity: 1,
x: 0,
duration: 0.8,
ease: 'power2.out'
}, 0.2);
tl.to(
'[data-composition-id="intro"] .title-card',
{
opacity: 1,
x: 0,
duration: 0.8,
ease: "power2.out",
},
0.2,
);
// Exit: Slide off left at 1.8s (synced with 47% graphic)
tl.to('[data-composition-id="intro"] .title-card', {
x: '-120%',
opacity: 0,
duration: 0.6,
ease: 'power2.in'
}, 1.8);
tl.to(
'[data-composition-id="intro"] .title-card',
{
x: "-120%",
opacity: 0,
duration: 0.6,
ease: "power2.in",
},
1.8,
);
window.__timelines["intro"] = tl;
})();
+265 -179
View File
@@ -1,195 +1,281 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Warm Grain - Hyperframes</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #F5F0E0; /* Cream background */
font-family: 'Outfit', 'Lexend', sans-serif;
}
body,
html {
margin: 0;
padding: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background-color: #f5f0e0; /* Cream background */
font-family: "Outfit", "Lexend", sans-serif;
}
#main-composition {
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
}
#main-composition {
position: relative;
width: 1920px;
height: 1080px;
overflow: hidden;
}
/* Paper texture and Grain overlay */
#grain-overlay-comp {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
/* Paper texture and Grain overlay */
#grain-overlay-comp {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
}
/* Grain animation */
@keyframes grain-noise {
0%, 100% { transform: translate(0, 0); }
10% { transform: translate(-5%, -5%); }
20% { transform: translate(-10%, 5%); }
30% { transform: translate(5%, -10%); }
40% { transform: translate(-5%, 15%); }
50% { transform: translate(-10%, 5%); }
60% { transform: translate(15%, 0); }
70% { transform: translate(0, 10%); }
80% { transform: translate(-15%, 0); }
90% { transform: translate(10%, 5%); }
/* Grain animation */
@keyframes grain-noise {
0%,
100% {
transform: translate(0, 0);
}
10% {
transform: translate(-5%, -5%);
}
20% {
transform: translate(-10%, 5%);
}
30% {
transform: translate(5%, -10%);
}
40% {
transform: translate(-5%, 15%);
}
50% {
transform: translate(-10%, 5%);
}
60% {
transform: translate(15%, 0);
}
70% {
transform: translate(0, 10%);
}
80% {
transform: translate(-15%, 0);
}
90% {
transform: translate(10%, 5%);
}
}
.grain-texture {
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: url('https://www.transparenttextures.com/patterns/natural-paper.png');
opacity: 0.15;
animation: grain-noise 0.5s steps(1) infinite;
}
.grain-texture {
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: url("https://www.transparenttextures.com/patterns/natural-paper.png");
opacity: 0.15;
animation: grain-noise 0.5s steps(1) infinite;
}
#a-roll {
position: absolute;
border-radius: 16px;
object-fit: cover;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
#a-roll {
position: absolute;
border-radius: 16px;
object-fit: cover;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
.comp-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.comp-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
</style>
</head>
<body>
<div id="main-composition" data-composition-id="main-video" data-width="1920" data-height="1080" data-duration="17">
<!-- Background Layer -->
<div id="grain-overlay-comp" data-composition-id="grain-overlay" data-width="1920" data-height="1080" data-duration="17" data-track-index="100">
<div class="grain-texture"></div>
<script>
const grainTl = gsap.timeline({ paused: true });
window.__timelines["grain-overlay"] = grainTl;
</script>
</div>
<!-- A-Roll Video -->
<video id="a-roll"
src="__VIDEO_SRC__"
data-start="0"
data-duration="17"
data-track-index="0">
</video>
<!-- Compositions -->
<div id="intro-layer" class="comp-layer"
data-composition-id="intro"
data-composition-src="compositions/intro.html"
data-start="0"
data-duration="2.5"
data-track-index="1">
</div>
<div id="graphics-layer" class="comp-layer"
data-composition-id="graphics"
data-composition-src="compositions/graphics.html"
data-start="0"
data-duration="17"
data-track-index="2">
</div>
<div id="captions-layer" class="comp-layer"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="17"
data-track-index="3">
</div>
<!-- SFX -->
<audio id="sfx-swipe-1" src="" data-start="1.8" data-duration="1" data-track-index="4"></audio>
<audio id="sfx-swipe-2" src="" data-start="4.6" data-duration="1" data-track-index="4"></audio>
<audio id="sfx-swipe-3" src="" data-start="8.8" data-duration="1" data-track-index="4"></audio>
</head>
<body>
<div
id="main-composition"
data-composition-id="main-video"
data-width="1920"
data-height="1080"
data-duration="17"
>
<!-- Background Layer -->
<div
id="grain-overlay-comp"
data-composition-id="grain-overlay"
data-width="1920"
data-height="1080"
data-duration="17"
data-track-index="100"
>
<div class="grain-texture"></div>
<script>
const tl = gsap.timeline({ paused: true });
// A-Roll Framing Strategy
// 1. 0s-1.8s: Intro scale up from small (60%) to medium (80%) - Shifted right slightly to clear speaker card
// 2. 1.8s-4.6s: Grid view / Shift Left (x: 600, scale: 70%) for 47% graphic
// 3. 4.6s-8.8s: Shift Center-Bottom (y: 800, scale: 70%) for 62% graphic (top)
// 4. 8.8s-14s: Shift Right (x: 1320, scale: 75%) for Editing Skills graphic (left)
// 5. 14s-17s: Final Reveal (Center, scale: 100%)
// Initial state
gsap.set('#a-roll', { x: 1100, y: 540, xPercent: -50, yPercent: -50, width: 1920 * 0.6, height: 1080 * 0.6 });
// 1. Intro Scale Up (0s - 1.8s)
tl.to('#a-roll', {
x: 1200,
width: 1920 * 0.8,
height: 1080 * 0.8,
duration: 1.8,
ease: "power2.inOut"
}, 0);
// 2. Moment 1: 47% Graphic Trigger (1.8s) - Shift Left
tl.to('#a-roll', {
x: 600,
y: 540,
width: 1920 * 0.7,
height: 1080 * 0.7,
duration: 0.5,
ease: "power2.inOut"
}, 1.8);
// 3. Moment 2: 62% Graphic Trigger (4.6s) - Shift Center-Bottom
tl.to('#a-roll', {
x: 960,
y: 750,
width: 1920 * 0.7,
height: 1080 * 0.7,
duration: 0.5,
ease: "power2.inOut"
}, 4.6);
// 4. Moment 3: Editing Skills Trigger (8.8s) - Shift Right
tl.to('#a-roll', {
x: 1320,
y: 540,
width: 1920 * 0.75,
height: 1080 * 0.75,
duration: 0.5,
ease: "power2.inOut"
}, 8.8);
// 5. Final Reveal (14s - 17s)
tl.to('#a-roll', {
x: 960,
y: 540,
width: 1920 * 1.0,
height: 1080 * 1.0,
duration: 1.0,
ease: "power2.inOut"
}, 14);
window.__timelines["main-video"] = tl;
const grainTl = gsap.timeline({ paused: true });
window.__timelines["grain-overlay"] = grainTl;
</script>
</div>
<!-- A-Roll Video -->
<video
id="a-roll"
src="__VIDEO_SRC__"
data-start="0"
data-duration="17"
data-track-index="0"
></video>
<!-- Compositions -->
<div
id="intro-layer"
class="comp-layer"
data-composition-id="intro"
data-composition-src="compositions/intro.html"
data-start="0"
data-duration="2.5"
data-track-index="1"
></div>
<div
id="graphics-layer"
class="comp-layer"
data-composition-id="graphics"
data-composition-src="compositions/graphics.html"
data-start="0"
data-duration="17"
data-track-index="2"
></div>
<div
id="captions-layer"
class="comp-layer"
data-composition-id="captions"
data-composition-src="compositions/captions.html"
data-start="0"
data-duration="17"
data-track-index="3"
></div>
<!-- SFX -->
<audio
id="sfx-swipe-1"
src=""
data-start="1.8"
data-duration="1"
data-track-index="4"
></audio>
<audio
id="sfx-swipe-2"
src=""
data-start="4.6"
data-duration="1"
data-track-index="4"
></audio>
<audio
id="sfx-swipe-3"
src=""
data-start="8.8"
data-duration="1"
data-track-index="4"
></audio>
<script>
const tl = gsap.timeline({ paused: true });
// A-Roll Framing Strategy
// 1. 0s-1.8s: Intro scale up from small (60%) to medium (80%) - Shifted right slightly to clear speaker card
// 2. 1.8s-4.6s: Grid view / Shift Left (x: 600, scale: 70%) for 47% graphic
// 3. 4.6s-8.8s: Shift Center-Bottom (y: 800, scale: 70%) for 62% graphic (top)
// 4. 8.8s-14s: Shift Right (x: 1320, scale: 75%) for Editing Skills graphic (left)
// 5. 14s-17s: Final Reveal (Center, scale: 100%)
// Initial state
gsap.set("#a-roll", {
x: 1100,
y: 540,
xPercent: -50,
yPercent: -50,
width: 1920 * 0.6,
height: 1080 * 0.6,
});
// 1. Intro Scale Up (0s - 1.8s)
tl.to(
"#a-roll",
{
x: 1200,
width: 1920 * 0.8,
height: 1080 * 0.8,
duration: 1.8,
ease: "power2.inOut",
},
0,
);
// 2. Moment 1: 47% Graphic Trigger (1.8s) - Shift Left
tl.to(
"#a-roll",
{
x: 600,
y: 540,
width: 1920 * 0.7,
height: 1080 * 0.7,
duration: 0.5,
ease: "power2.inOut",
},
1.8,
);
// 3. Moment 2: 62% Graphic Trigger (4.6s) - Shift Center-Bottom
tl.to(
"#a-roll",
{
x: 960,
y: 750,
width: 1920 * 0.7,
height: 1080 * 0.7,
duration: 0.5,
ease: "power2.inOut",
},
4.6,
);
// 4. Moment 3: Editing Skills Trigger (8.8s) - Shift Right
tl.to(
"#a-roll",
{
x: 1320,
y: 540,
width: 1920 * 0.75,
height: 1080 * 0.75,
duration: 0.5,
ease: "power2.inOut",
},
8.8,
);
// 5. Final Reveal (14s - 17s)
tl.to(
"#a-roll",
{
x: 960,
y: 540,
width: 1920 * 1.0,
height: 1080 * 1.0,
duration: 1.0,
ease: "power2.inOut",
},
14,
);
window.__timelines["main-video"] = tl;
</script>
</div>
</body>
</body>
</html>