mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
fix(examples): host the kinetic-type A-roll so the video actually renders (#1799)
* fix(examples): host the kinetic-type A-roll so the video actually renders The A-roll <video> was authored inside the main-graphics sub-composition template. The runtime only seeks and decodes media that is a direct child of the host root, so the footage was never driven by the live runtime and renders blank in Studio preview and the player (the producer's compile step happened to hoist it, masking the contract violation in server renders). The example also failed lint with eight errors. Root cause and fixes: - Move the <video> out of compositions/main-graphics.html and into index.html as a direct child of #root, with data-start/data-duration/data-track-index and class="clip". Its per-scene opacity reveal now runs on the main timeline at global time, since a sub-composition timeline cannot reach host elements. - Make the sub-composition a transparent overlay shell (background: transparent) and stack it above the host video so the type renders over the footage. - Drop the crossorigin attribute (plain displayed media never needs it) and mark the audible footage with data-has-audio="true". - Replace the three CSS translateY values that GSAP would overwrite with fromTo tweens (carson-line-1, wes-text-top, wes-text-bottom). - Swap the unbundled Libre Baskerville for the bundled Playfair Display serif so the renderer can supply the Wes Anderson typography, and drop the redundant -apple-system token from the body font stack. lint reports 0 errors, validate passes, and frame extraction confirms the A-roll composites correctly under every type scene. * docs(examples): note the A-roll reveal-time coupling to the sub-composition
This commit is contained in:
+15
-32
@@ -5,20 +5,12 @@
|
||||
data-height="1080"
|
||||
data-duration="14.72"
|
||||
>
|
||||
<!-- A-Roll Video -->
|
||||
<video
|
||||
id="a-roll-video"
|
||||
src="https://gen-os-static.s3.us-east-2.amazonaws.com/astral_assets/uploaded_assets/67cf5a05_e134ec83a57042b38776c952da595870.mp4"
|
||||
style="
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
opacity: 1;
|
||||
z-index: 0;
|
||||
"
|
||||
crossorigin="anonymous"
|
||||
></video>
|
||||
<!--
|
||||
The A-Roll footage lives in the host root (index.html), positioned UNDER
|
||||
this overlay shell. This sub-composition is the transparent graphics layer:
|
||||
scenes and overlays paint over the footage and its reveal is timed on the
|
||||
main timeline. Media nested in a sub-composition is never seeked/decoded.
|
||||
-->
|
||||
|
||||
<!-- Scene 1: Hook -->
|
||||
<div
|
||||
@@ -156,7 +148,7 @@
|
||||
|
||||
<style>
|
||||
[data-composition-id="main-graphics"] {
|
||||
background: black;
|
||||
background: transparent;
|
||||
font-family: "Inter", sans-serif;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
@@ -401,7 +393,6 @@
|
||||
left: 10%;
|
||||
font-size: 140px;
|
||||
font-weight: 900;
|
||||
transform: translateY(200px);
|
||||
z-index: 2;
|
||||
}
|
||||
.carson-line-1 .red-dot {
|
||||
@@ -448,10 +439,9 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
.wes-text-top {
|
||||
font-family: "Libre Baskerville", serif;
|
||||
font-family: "Playfair Display", serif;
|
||||
font-size: 44px;
|
||||
font-style: italic;
|
||||
transform: translateY(-100px);
|
||||
}
|
||||
.wes-rule {
|
||||
width: 0;
|
||||
@@ -460,9 +450,8 @@
|
||||
margin: 20px auto;
|
||||
}
|
||||
.wes-text-bottom {
|
||||
font-family: "Libre Baskerville", serif;
|
||||
font-family: "Playfair Display", serif;
|
||||
font-size: 44px;
|
||||
transform: translateY(100px);
|
||||
}
|
||||
|
||||
/* Scene 6: Vignelli Style */
|
||||
@@ -495,14 +484,11 @@
|
||||
<script>
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const video = document.getElementById("a-roll-video");
|
||||
// The A-roll footage lives in the host root (index.html); its reveal is
|
||||
// driven on the main timeline there. This timeline only animates the
|
||||
// graphics overlay's own elements.
|
||||
|
||||
// --- Initial Setup ---
|
||||
tl.set(
|
||||
video,
|
||||
{ width: "100%", height: "100%", left: 0, top: 0, borderRadius: 0, scale: 1, opacity: 0 },
|
||||
0,
|
||||
);
|
||||
tl.set("#white-wipe", { xPercent: -100 }, 0);
|
||||
|
||||
// --- Scene 1: Hook (0s - 2.0s) ---
|
||||
@@ -519,7 +505,6 @@
|
||||
// --- Transition to Scene 2 (2.0s - 2.4s) ---
|
||||
tl.to("#white-wipe", { xPercent: 0, duration: 0.2, ease: "power2.in" }, 2.0);
|
||||
tl.set("#scene-1", { opacity: 0 }, 2.2);
|
||||
tl.set(video, { opacity: 1 }, 2.2);
|
||||
tl.to("#white-wipe", { xPercent: 100, duration: 0.2, ease: "power2.out" }, 2.2);
|
||||
|
||||
// --- Scene 2: Swiss Style (2.0s - 5.0s) ---
|
||||
@@ -554,21 +539,19 @@
|
||||
|
||||
// --- Scene 4: David Carson Style (9.6s - 11.7s) ---
|
||||
tl.to("#scene-4", { opacity: 1, duration: 0.1 }, 9.6);
|
||||
tl.to(".carson-line-1", { y: 0, duration: 0.6, ease: "expo.out" }, 9.7);
|
||||
tl.fromTo(".carson-line-1", { y: 200 }, { y: 0, duration: 0.6, ease: "expo.out" }, 9.7);
|
||||
tl.to(".carson-line-2", { opacity: 1, x: -50, duration: 0.5, ease: "back.out" }, 10.2);
|
||||
tl.to(".carson-container", { y: 300, duration: 0.6, ease: "expo.in" }, 11.4);
|
||||
tl.to("#scene-4", { opacity: 0, duration: 0.1 }, 11.7);
|
||||
|
||||
// --- Scene 5: Wes Anderson (11.7s - 13.5s) ---
|
||||
tl.to(video, { opacity: 0, duration: 0.4 }, 11.7);
|
||||
tl.to("#scene-5", { opacity: 1, duration: 0.1 }, 11.7);
|
||||
tl.to(".wes-text-top", { y: 0, duration: 0.6, ease: "back.out(1.2)" }, 12.0);
|
||||
tl.fromTo(".wes-text-top", { y: -100 }, { y: 0, duration: 0.6, ease: "back.out(1.2)" }, 12.0);
|
||||
tl.to(".wes-rule", { width: 400, duration: 0.6 }, 12.3);
|
||||
tl.to(".wes-text-bottom", { y: 0, duration: 0.6, ease: "back.out(1.2)" }, 12.6);
|
||||
tl.fromTo(".wes-text-bottom", { y: 100 }, { y: 0, duration: 0.6, ease: "back.out(1.2)" }, 12.6);
|
||||
tl.to("#scene-5", { opacity: 0, duration: 0.5 }, 13.0);
|
||||
|
||||
// --- Scene 6: Vignelli Style (13.5s - 14.72s) ---
|
||||
tl.set(video, { opacity: 1 }, 13.5);
|
||||
tl.set("#scene-6", { opacity: 1 }, 13.5);
|
||||
tl.set("#scene-6-overlay", { opacity: 1 }, 13.5);
|
||||
|
||||
|
||||
+43
-5
@@ -8,7 +8,7 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,700;0,900;1,400&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&display=block"
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:ital,wght@0,400;0,700;0,900;1,400&family=Playfair+Display:ital,wght@0,400;0,700;1,400&display=block"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<style>
|
||||
@@ -24,10 +24,7 @@
|
||||
height: 1080px;
|
||||
overflow: hidden;
|
||||
background-color: #0a0a0f;
|
||||
font-family:
|
||||
"Inter",
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -40,6 +37,31 @@
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
>
|
||||
<!--
|
||||
A-Roll video. Media is only seeked/decoded when it is a DIRECT child of
|
||||
the host root, so the footage lives here (not inside the sub-composition
|
||||
template) and its per-scene reveal is driven on the main timeline below.
|
||||
-->
|
||||
<video
|
||||
id="a-roll-video"
|
||||
class="clip"
|
||||
src="https://gen-os-static.s3.us-east-2.amazonaws.com/astral_assets/uploaded_assets/67cf5a05_e134ec83a57042b38776c952da595870.mp4"
|
||||
data-start="0"
|
||||
data-duration="14.72"
|
||||
data-track-index="0"
|
||||
data-has-audio="true"
|
||||
playsinline
|
||||
style="
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: 0;
|
||||
opacity: 0;
|
||||
"
|
||||
></video>
|
||||
<div
|
||||
id="graphics-layer"
|
||||
data-composition-id="main-graphics"
|
||||
@@ -49,12 +71,28 @@
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
style="position: absolute; inset: 0; z-index: 1"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
// The A-roll <video> is a host-root element, so the sub-composition
|
||||
// timeline cannot reach it. Drive its reveal here on the main timeline at
|
||||
// global time (the graphics sub-comp starts at 0, so scene-local == global).
|
||||
//
|
||||
// COUPLING: the reveal/hide times below (2.2 / 11.7 / 13.5) are hand-tuned
|
||||
// to the graphics-layer sub-composition's scene boundaries and assume it is
|
||||
// mounted at data-start="0". If you re-time the sub-composition's scenes or
|
||||
// change its data-start, these absolute times drift out of alignment and
|
||||
// must be updated to match the new scene boundaries.
|
||||
tl.set("#a-roll-video", { opacity: 0 }, 0);
|
||||
tl.set("#a-roll-video", { opacity: 1 }, 2.2); // reveal after the Scene 1 white wipe
|
||||
tl.to("#a-roll-video", { opacity: 0, duration: 0.4 }, 11.7); // hide for the Wes Anderson scene
|
||||
tl.set("#a-roll-video", { opacity: 1 }, 13.5); // back for the Vignelli outro
|
||||
|
||||
window.__timelines["main"] = tl;
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user