Files
hyperframes/registry/examples/product-promo/index.html
Miguel Ángel f2976536de fix(skills): mount music-to-video motion primitives as sub-compositions (#4136)
* fix(skills): mount music-to-video motion primitives as sub-compositions

Each primitive's root now only mounts scene.html, so the root is built from
a sub-composition and the structure lint has nothing to flag. Renders match
the originals (31 of 37 identical, the rest above 54 dB PSNR).
Registry examples mark their caption layer with data-track-kind=captions.

* fix(skills): keep primitive variables and page styles where the runtime reads them

Composition variables move onto the sub-composition element, the dead
#scene rule is dropped, and the frame-worker doc names where page styles
live.

* fix(skills): shorten a carried-over comment in the kinetic-letter-in scene
2026-09-18 20:57:54 -04:00

160 lines
4.5 KiB
HTML
Vendored

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>Product Promo</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;800&display=block"
rel="stylesheet"
/>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0f;
font-family: "Inter", sans-serif;
}
.scene {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.caption-text-wrapper {
position: absolute;
bottom: 150px;
left: 0;
right: 0;
display: flex;
justify-content: center;
pointer-events: none;
overflow: hidden;
padding: 10px 0;
}
.caption-line {
color: white;
font-size: 48px;
font-weight: 600;
letter-spacing: -0.02em;
text-align: center;
text-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
transform: translateY(100%);
opacity: 0;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="20"
data-width="1920"
data-height="1080"
>
<!-- Scene 1: Logo Intro -->
<div
id="scene-1"
class="scene"
data-composition-id="scene1-logo-intro"
data-composition-src="compositions/scene1-logo-intro.html"
data-start="0"
data-duration="1.5"
data-track-index="1"
data-width="1920"
data-height="1080"
></div>
<!-- Scene 2-4: Continuous Canvas -->
<div
id="scene-2-4"
class="scene"
data-composition-id="scene2-4-canvas"
data-composition-src="compositions/scene2-4-canvas.html"
data-start="1.5"
data-duration="12.5"
data-track-index="1"
data-width="1920"
data-height="1080"
></div>
<!-- Scene 5: Logo Outro -->
<div
id="scene-5"
class="scene"
data-composition-id="scene5-logo-outro"
data-composition-src="compositions/scene5-logo-outro.html"
data-start="14"
data-duration="6"
data-track-index="1"
data-width="1920"
data-height="1080"
></div>
<!-- Captions -->
<div
id="captions-comp"
data-track-kind="captions"
data-composition-id="captions"
data-start="1.5"
data-duration="12.5"
data-track-index="2"
data-width="1920"
data-height="1080"
>
<div class="caption-text-wrapper">
<div id="caption-text" class="caption-line">Starting with a blank canvas.</div>
</div>
<script>
(function () {
const tl = gsap.timeline({ paused: true });
const text = document.querySelector("#caption-text");
tl.to(text, { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 0);
tl.to(text, { opacity: 0, y: -20, duration: 0.3, ease: "power3.in" }, 3.2);
tl.set(text, { innerText: "Three cursors. One file. Zero meetings.", y: 40 }, 3.5);
tl.to(text, { opacity: 1, y: 0, duration: 0.6, ease: "power3.out" }, 3.5);
tl.to(text, { opacity: 0, y: -20, duration: 0.3, ease: "power3.in" }, 7.7);
tl.set(
text,
{ innerText: "Components in. Feedback resolved. No one waited.", y: 40 },
8.0,
);
tl.to(text, { opacity: 1, y: 0, duration: 0.6, ease: "power3.out" }, 8.0);
tl.to(text, { opacity: 0, y: -20, duration: 0.4, ease: "power3.in" }, 12.1);
window.__timelines = window.__timelines || {};
window.__timelines["captions"] = tl;
})();
</script>
</div>
</div>
<script>
window.__timelines = window.__timelines || {};
const mainTl = gsap.timeline({ paused: true });
mainTl.set("#scene-2-4", { scale: 1, filter: "blur(0px)" }, 1.5);
mainTl.to(
"#scene-2-4",
{ duration: 0.25, scale: 0.94, filter: "blur(6px)", opacity: 0, ease: "power2.in" },
13.75,
);
window.__timelines["main"] = mainTl;
</script>
</body>
</html>