mirror of
https://github.com/hanzoai/frames.git
synced 2026-09-24 00:08:03 +00:00
Every SKILL.md already declared the new name — name: frames, frames-cli, frames-core, and so on — but the directories were never moved, so the tree carried frames-* in content and hyperframes-* on disk. Everything that resolves a skill by path missed: the core-skill list, the plugin marketplace pin, and the docs the CLI reads at runtime. Eight tests failed on main because the files they open do not exist. The directories now match what the files say they are, and the guide the claude-design contract reads takes the name that contract already used.
650 lines
21 KiB
HTML
650 lines
21 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=1920, height=1080" />
|
||
<title>Scene 09 — Split Comparison Reveal</title>
|
||
|
||
<!--
|
||
Frames composition.tsx.
|
||
|
||
Choreography (3 phases, 5 seconds total):
|
||
0.17 – 0.83s Title slides down from top: "Build Video With Frames"
|
||
0.50 – 1.83s Left card "HTML Composition" enters from left (+16° rotateY)
|
||
0.83 – 1.83s Right card "Render Pipeline" enters from right (-16° rotateY)
|
||
1.67 – 2.17s Left pill badge "Seekable Timeline" pops in with back.out(1.7)
|
||
2.00 – 2.50s Right pill badge "Render Ready" pops in
|
||
0 – 5.00s Continuous floating: cards y ±6 px / rotation ±1° (phase-opposed)
|
||
Badges y ±5 px (slow shared sine)
|
||
and .card-tilt (static rotateY + float rotation) so entry and float
|
||
don't fight on the same alias
|
||
- All continuous floating consolidated into one shared scene-ticker onUpdate
|
||
(6 gsap.set calls per frame, batched by the browser)
|
||
- Phase offset Math.PI between the two cards' floats — opposed breathing
|
||
- Card images are Frames workflow mockups (no asset files needed)
|
||
- Ambient dual-glow via two radial-gradients in a single overlay
|
||
-->
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
|
||
|
||
<style>
|
||
:root {
|
||
--bg-dark: #0a1415;
|
||
--text-primary: #ffffff;
|
||
--text-secondary: rgba(255, 255, 255, 0.65);
|
||
--brand-cyan: #18d9e8;
|
||
--brand-cyan-glow: rgba(24, 217, 232, 1);
|
||
--brand-green: #7bea5a;
|
||
--brand-green-glow: rgba(123, 234, 90, 1);
|
||
--glass-bg: rgba(255, 255, 255, 0.08);
|
||
--border: rgba(255, 255, 255, 0.12);
|
||
}
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
html,
|
||
body {
|
||
margin: 0;
|
||
width: 1920px;
|
||
height: 1080px;
|
||
overflow: hidden;
|
||
background: var(--bg-dark);
|
||
font-family:
|
||
"Inter",
|
||
system-ui,
|
||
-apple-system,
|
||
sans-serif;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.stage {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ============================================================
|
||
BACKGROUND
|
||
============================================================ */
|
||
.bg {
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse at 35% 50%, rgba(24, 217, 232, 0.2), transparent 45%),
|
||
radial-gradient(ellipse at 72% 50%, rgba(123, 234, 90, 0.16), transparent 45%),
|
||
linear-gradient(135deg, #3a3a3a 0%, #17211f 30%, #0b2328 48%, #1f3518 70%, #343434 100%);
|
||
}
|
||
|
||
/* ============================================================
|
||
TITLE
|
||
============================================================ */
|
||
.title {
|
||
position: absolute;
|
||
top: 60px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
font-size: 88px;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
text-align: center;
|
||
letter-spacing: 0;
|
||
white-space: nowrap;
|
||
will-change: transform, opacity;
|
||
/* initial opacity 0 + y -40 set via gsap.set */
|
||
}
|
||
.title .accent {
|
||
color: var(--brand-cyan);
|
||
text-shadow: 0 0 34px rgba(24, 217, 232, 0.28);
|
||
}
|
||
|
||
/* ============================================================
|
||
CARDS ROW
|
||
============================================================ */
|
||
.cards-row {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
display: flex;
|
||
gap: 76px;
|
||
padding-top: 30px;
|
||
perspective: 980px;
|
||
perspective-origin: 50% 42%;
|
||
transform-style: preserve-3d;
|
||
}
|
||
|
||
/* Two nested wrappers per card */
|
||
.card {
|
||
transform-style: preserve-3d;
|
||
}
|
||
.card-pos {
|
||
perspective: 980px;
|
||
perspective-origin: 50% 45%;
|
||
transform-style: preserve-3d;
|
||
will-change: transform, opacity;
|
||
/* initial x/scale/opacity set via gsap.set */
|
||
}
|
||
.card-tilt {
|
||
transform-style: preserve-3d;
|
||
will-change: transform;
|
||
/* initial rotationY set via gsap.set */
|
||
}
|
||
.card-content {
|
||
width: 720px;
|
||
transform-style: preserve-3d;
|
||
}
|
||
.card-image {
|
||
width: 100%;
|
||
height: 500px;
|
||
border-radius: 24px;
|
||
overflow: hidden;
|
||
border: 1px solid var(--border);
|
||
position: relative;
|
||
transform: translateZ(0) rotateX(0.01deg);
|
||
backface-visibility: hidden;
|
||
}
|
||
.card-left .card-tilt {
|
||
transform-origin: 100% 50%;
|
||
}
|
||
.card-right .card-tilt {
|
||
transform-origin: 0% 50%;
|
||
}
|
||
.card-label {
|
||
margin-top: 26px;
|
||
text-align: center;
|
||
font-size: 54px;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
transform: translateZ(34px);
|
||
text-shadow: 0 0 30px rgba(24, 217, 232, 0.16);
|
||
}
|
||
.card-subtitle {
|
||
margin-top: 8px;
|
||
text-align: center;
|
||
font-size: 24px;
|
||
color: var(--text-secondary);
|
||
transform: translateZ(26px);
|
||
}
|
||
|
||
/* Left card: shadow falls right (positive x in box-shadow = right) */
|
||
.card-left .card-image {
|
||
box-shadow:
|
||
30px 30px 60px rgba(0, 0, 0, 0.45),
|
||
0 0 60px rgba(24, 217, 232, 0.2);
|
||
}
|
||
/* Right card: shadow falls left */
|
||
.card-right .card-image {
|
||
box-shadow:
|
||
-30px 30px 60px rgba(0, 0, 0, 0.45),
|
||
0 0 60px rgba(123, 234, 90, 0.2);
|
||
}
|
||
|
||
/* ============================================================
|
||
CARD IMAGE PLACEHOLDERS (mock UI)
|
||
============================================================ */
|
||
/* Left card — HTML Composition: gradient + timed clip grid */
|
||
.card-left .card-image {
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(12, 38, 42, 0.96) 0%,
|
||
rgba(18, 66, 63, 0.9) 52%,
|
||
rgba(32, 57, 38, 0.94) 100%
|
||
);
|
||
}
|
||
.mock-templates {
|
||
position: absolute;
|
||
inset: 0;
|
||
padding: 56px 66px;
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
grid-template-rows: repeat(2, 1fr);
|
||
gap: 22px;
|
||
opacity: 0.22;
|
||
}
|
||
.mock-thumb {
|
||
background: linear-gradient(135deg, rgba(24, 217, 232, 0.2), rgba(123, 234, 90, 0.08));
|
||
border-radius: 14px;
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: flex-start;
|
||
padding: 14px;
|
||
transform: translateZ(18px);
|
||
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.18);
|
||
}
|
||
.mock-thumb .label {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
}
|
||
|
||
/* Right card — Render Pipeline: validation rows */
|
||
.card-right .card-image {
|
||
background: linear-gradient(
|
||
135deg,
|
||
rgba(23, 45, 34, 0.96) 0%,
|
||
rgba(17, 70, 73, 0.9) 50%,
|
||
rgba(38, 57, 45, 0.94) 100%
|
||
);
|
||
}
|
||
.mock-team {
|
||
position: absolute;
|
||
inset: 0;
|
||
padding: 66px 72px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20px;
|
||
justify-content: center;
|
||
opacity: 0.24;
|
||
}
|
||
.mock-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
padding: 15px 20px;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border-radius: 12px;
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
transform: translateZ(18px);
|
||
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.18);
|
||
}
|
||
.mock-avatar {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
background: linear-gradient(135deg, var(--brand-green), var(--brand-cyan));
|
||
}
|
||
.mock-avatar.purple {
|
||
background: linear-gradient(135deg, var(--brand-cyan), #38bdf8);
|
||
}
|
||
.mock-avatar.green {
|
||
background: linear-gradient(135deg, var(--brand-green), var(--brand-cyan));
|
||
}
|
||
.mock-avatar.orange {
|
||
background: linear-gradient(135deg, #facc15, var(--brand-green));
|
||
}
|
||
.mock-row .name {
|
||
font-size: 22px;
|
||
font-weight: 600;
|
||
color: rgba(255, 255, 255, 0.85);
|
||
}
|
||
.mock-row .status {
|
||
margin-left: auto;
|
||
font-size: 16px;
|
||
color: var(--brand-green);
|
||
}
|
||
|
||
/* ============================================================
|
||
FLOATING BADGES
|
||
============================================================ */
|
||
.badge {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 14px 22px;
|
||
border-radius: 999px;
|
||
background-color: var(--glass-bg);
|
||
backdrop-filter: blur(10px);
|
||
-webkit-backdrop-filter: blur(10px);
|
||
will-change: transform, opacity;
|
||
z-index: 50;
|
||
}
|
||
.badge-left {
|
||
border: 1px solid rgba(24, 217, 232, 0.4);
|
||
box-shadow: 0 0 30px rgba(24, 217, 232, 0.35);
|
||
}
|
||
.badge-right {
|
||
border: 1px solid rgba(123, 234, 90, 0.4);
|
||
box-shadow: 0 0 30px rgba(123, 234, 90, 0.35);
|
||
}
|
||
.badge-icon-wrap {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--bg-dark);
|
||
flex-shrink: 0;
|
||
}
|
||
.badge-left .badge-icon-wrap {
|
||
background-color: var(--brand-cyan);
|
||
}
|
||
.badge-right .badge-icon-wrap {
|
||
background-color: var(--brand-green);
|
||
}
|
||
.badge-label {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* ============================================================
|
||
AMBIENT GLOW + VIGNETTE
|
||
============================================================ */
|
||
.ambient-glow {
|
||
position: absolute;
|
||
inset: 0;
|
||
background:
|
||
radial-gradient(ellipse at 30% 50%, var(--brand-cyan-glow) 0%, transparent 35%),
|
||
radial-gradient(ellipse at 70% 50%, var(--brand-green-glow) 0%, transparent 35%);
|
||
opacity: 0.13;
|
||
pointer-events: none;
|
||
}
|
||
.vignette {
|
||
position: absolute;
|
||
inset: 0;
|
||
background: radial-gradient(ellipse at center, transparent 40%, rgba(0, 0, 0, 0.45) 100%);
|
||
pointer-events: none;
|
||
z-index: 400;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div
|
||
id="root"
|
||
data-composition-id="main"
|
||
data-start="0"
|
||
data-duration="5"
|
||
data-width="1920"
|
||
data-height="1080"
|
||
>
|
||
<div
|
||
class="stage clip"
|
||
data-start="0"
|
||
data-duration="5"
|
||
data-track-index="1"
|
||
id="scene-stage"
|
||
>
|
||
<div class="bg"></div>
|
||
|
||
<!-- Title -->
|
||
<div class="title" id="title">Build Video With <span class="accent">Frames</span></div>
|
||
|
||
<!-- Cards row -->
|
||
<div class="cards-row">
|
||
<!-- Left card: HTML Composition -->
|
||
<div class="card card-left" id="card-left">
|
||
<div class="card-pos">
|
||
<div class="card-tilt">
|
||
<div class="card-content">
|
||
<div class="card-image">
|
||
<div class="mock-templates">
|
||
<div class="mock-thumb"><span class="label">HTML</span></div>
|
||
<div class="mock-thumb"><span class="label">CSS</span></div>
|
||
<div class="mock-thumb"><span class="label">GSAP</span></div>
|
||
<div class="mock-thumb"><span class="label">Audio</span></div>
|
||
<div class="mock-thumb"><span class="label">Captions</span></div>
|
||
<div class="mock-thumb"><span class="label">Assets</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card-label">HTML Composition</div>
|
||
<div class="card-subtitle">Timed DOM clips, media, and motion</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Right card: Render Pipeline -->
|
||
<div class="card card-right" id="card-right">
|
||
<div class="card-pos">
|
||
<div class="card-tilt">
|
||
<div class="card-content">
|
||
<div class="card-image">
|
||
<div class="mock-team">
|
||
<div class="mock-row">
|
||
<div class="mock-avatar purple"></div>
|
||
<span class="name">Register timeline</span>
|
||
<span class="status">● seekable</span>
|
||
</div>
|
||
<div class="mock-row">
|
||
<div class="mock-avatar green"></div>
|
||
<span class="name">Validate layout</span>
|
||
<span class="status">● clean</span>
|
||
</div>
|
||
<div class="mock-row">
|
||
<div class="mock-avatar orange"></div>
|
||
<span class="name">Render frames</span>
|
||
<span class="status">● stable</span>
|
||
</div>
|
||
<div class="mock-row">
|
||
<div class="mock-avatar"></div>
|
||
<span class="name">Publish MP4</span>
|
||
<span class="status">● ready</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-label">Render Pipeline</div>
|
||
<div class="card-subtitle">Preview, check, render, publish</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Floating badges -->
|
||
<div class="badge badge-left" id="badge-left">
|
||
<div class="badge-icon-wrap">
|
||
<svg
|
||
width="18"
|
||
height="18"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
aria-hidden="true"
|
||
>
|
||
<path d="M12 2L2 7L12 12L22 7L12 2Z" />
|
||
<path d="M2 17L12 22L22 17" />
|
||
<path d="M2 12L12 17L22 12" />
|
||
</svg>
|
||
</div>
|
||
<span class="badge-label">Seekable Timeline</span>
|
||
</div>
|
||
|
||
<div class="badge badge-right" id="badge-right">
|
||
<div class="badge-icon-wrap">
|
||
<svg
|
||
width="18"
|
||
height="18"
|
||
viewBox="0 0 24 24"
|
||
fill="none"
|
||
stroke="currentColor"
|
||
stroke-width="2"
|
||
stroke-linecap="round"
|
||
stroke-linejoin="round"
|
||
aria-hidden="true"
|
||
>
|
||
<path d="M17 21V19C17 16.7909 15.2091 15 13 15H5C2.79086 15 1 16.7909 1 19V21" />
|
||
<circle cx="9" cy="7" r="4" />
|
||
<path d="M23 21V19C22.9986 17.1771 21.765 15.5857 20 15.13" />
|
||
<path
|
||
d="M16 3.13C17.7699 3.58317 19.0078 5.17799 19.0078 7.005C19.0078 8.83201 17.7699 10.4268 16 10.88"
|
||
/>
|
||
</svg>
|
||
</div>
|
||
<span class="badge-label">Render Ready</span>
|
||
</div>
|
||
|
||
<div class="ambient-glow"></div>
|
||
</div>
|
||
|
||
<div class="vignette"></div>
|
||
</div>
|
||
|
||
<script>
|
||
/* ================================================================
|
||
CONSTANTS
|
||
================================================================ */
|
||
const W = 1920,
|
||
H = 1080;
|
||
const TOTAL_DUR = 5.0;
|
||
|
||
const TIMING = {
|
||
// Phase 1: title
|
||
titleAt: 0.17,
|
||
titleDur: 0.67,
|
||
|
||
// Phase 2: cards
|
||
leftAt: 0.5,
|
||
rightAt: 0.83,
|
||
entryDur: 0.7,
|
||
slideDist: 100,
|
||
baseTilt: 18,
|
||
|
||
// Phase 3: badges
|
||
badgeLeftAt: 1.67,
|
||
badgeRightAt: 2.0,
|
||
badgeEntryDur: 0.5,
|
||
|
||
// Continuous float
|
||
floatYSpeed: 0.02 * 30, // = 0.6 rad/sec
|
||
floatYAmp: 6,
|
||
floatRSpeed: 0.015 * 30, // = 0.45 rad/sec
|
||
floatRAmp: 1,
|
||
badgeYSpeed: 0.025 * 30, // = 0.75 rad/sec
|
||
badgeYAmp: 5,
|
||
};
|
||
|
||
/* ================================================================
|
||
BADGE POSITIONS — set via CSS left/top once (not tweened)
|
||
================================================================ */
|
||
const badgeLeftEl = document.getElementById("badge-left");
|
||
const badgeRightEl = document.getElementById("badge-right");
|
||
badgeLeftEl.style.left = W * 0.12 + "px"; // 230 px
|
||
badgeLeftEl.style.top = H * 0.35 + "px"; // 378 px
|
||
badgeLeftEl.style.position = "absolute";
|
||
badgeRightEl.style.left = W * 0.75 + "px"; // 1440 px
|
||
badgeRightEl.style.top = H * 0.38 + "px"; // 410 px
|
||
badgeRightEl.style.position = "absolute";
|
||
|
||
/* ================================================================
|
||
INITIAL STATES (via gsap.set, before the timeline runs)
|
||
================================================================ */
|
||
gsap.set("#title", { opacity: 0, y: -40 });
|
||
|
||
gsap.set("#card-left .card-pos", { x: -TIMING.slideDist, scale: 0.8, opacity: 0, y: 0 });
|
||
gsap.set("#card-right .card-pos", { x: TIMING.slideDist, scale: 0.8, opacity: 0, y: 0 });
|
||
gsap.set("#card-left .card-tilt", { rotationY: TIMING.baseTilt });
|
||
gsap.set("#card-right .card-tilt", { rotationY: -TIMING.baseTilt });
|
||
|
||
gsap.set(["#badge-left", "#badge-right"], { scale: 0, opacity: 0, y: 0 });
|
||
|
||
/* ================================================================
|
||
TIMELINE
|
||
================================================================ */
|
||
window.__timelines = window.__timelines || {};
|
||
const tl = gsap.timeline({ paused: true });
|
||
window.__timelines["main"] = tl;
|
||
|
||
/* ----------------------------------------------------------------
|
||
PHASE 1: Title slides down
|
||
---------------------------------------------------------------- */
|
||
tl.to(
|
||
"#title",
|
||
{
|
||
opacity: 1,
|
||
y: 0,
|
||
duration: TIMING.titleDur,
|
||
ease: "power3.out", // spring(stiffness:100, damping:16)
|
||
},
|
||
TIMING.titleAt,
|
||
);
|
||
|
||
/* ----------------------------------------------------------------
|
||
PHASE 2: Cards enter from opposite sides
|
||
---------------------------------------------------------------- */
|
||
tl.to(
|
||
"#card-left .card-pos",
|
||
{
|
||
x: 0,
|
||
scale: 1,
|
||
opacity: 1,
|
||
duration: TIMING.entryDur,
|
||
ease: "power3.out",
|
||
},
|
||
TIMING.leftAt,
|
||
);
|
||
|
||
tl.to(
|
||
"#card-right .card-pos",
|
||
{
|
||
x: 0,
|
||
scale: 1,
|
||
opacity: 1,
|
||
duration: TIMING.entryDur,
|
||
ease: "power3.out",
|
||
},
|
||
TIMING.rightAt,
|
||
);
|
||
|
||
/* ----------------------------------------------------------------
|
||
PHASE 3: Badges pop in
|
||
---------------------------------------------------------------- */
|
||
tl.to(
|
||
"#badge-left",
|
||
{
|
||
scale: 1,
|
||
opacity: 1,
|
||
duration: TIMING.badgeEntryDur,
|
||
ease: "back.out(1.7)",
|
||
},
|
||
TIMING.badgeLeftAt,
|
||
);
|
||
|
||
tl.to(
|
||
"#badge-right",
|
||
{
|
||
scale: 1,
|
||
opacity: 1,
|
||
duration: TIMING.badgeEntryDur,
|
||
ease: "back.out(1.7)",
|
||
},
|
||
TIMING.badgeRightAt,
|
||
);
|
||
|
||
/* ----------------------------------------------------------------
|
||
CONTINUOUS FLOATING — shared scene-ticker onUpdate
|
||
Six gsap.set calls per frame, batched by the browser.
|
||
---------------------------------------------------------------- */
|
||
const leftPos = document.querySelector("#card-left .card-pos");
|
||
const rightPos = document.querySelector("#card-right .card-pos");
|
||
const leftTilt = document.querySelector("#card-left .card-tilt");
|
||
const rightTilt = document.querySelector("#card-right .card-tilt");
|
||
|
||
tl.to(
|
||
{ tick: 0 },
|
||
{
|
||
tick: 1,
|
||
duration: TOTAL_DUR,
|
||
ease: "none",
|
||
onUpdate: function () {
|
||
const t = tl.time();
|
||
// Cards float in opposition (phase π apart).
|
||
const lY = Math.sin(t * TIMING.floatYSpeed) * TIMING.floatYAmp;
|
||
const lR = Math.sin(t * TIMING.floatRSpeed) * TIMING.floatRAmp;
|
||
const rY = Math.sin(t * TIMING.floatYSpeed + Math.PI) * TIMING.floatYAmp;
|
||
const rR = Math.sin(t * TIMING.floatRSpeed + Math.PI) * TIMING.floatRAmp;
|
||
gsap.set(leftPos, { y: lY });
|
||
gsap.set(rightPos, { y: rY });
|
||
gsap.set(leftTilt, { rotationY: TIMING.baseTilt + lR });
|
||
gsap.set(rightTilt, { rotationY: -TIMING.baseTilt + rR });
|
||
|
||
// Badges — small shared y oscillation.
|
||
const bY = Math.sin(t * TIMING.badgeYSpeed) * TIMING.badgeYAmp;
|
||
gsap.set(badgeLeftEl, { y: bY });
|
||
gsap.set(badgeRightEl, { y: bY });
|
||
},
|
||
},
|
||
0,
|
||
);
|
||
</script>
|
||
</body>
|
||
</html>
|