diff --git a/skills/music-to-video/references/motion-primitive-catalog.md b/skills/music-to-video/references/motion-primitive-catalog.md index 58d1e0b2b..97a733f49 100644 --- a/skills/music-to-video/references/motion-primitive-catalog.md +++ b/skills/music-to-video/references/motion-primitive-catalog.md @@ -1,95 +1,75 @@ # Motion-primitive catalog — the free-compose menu -The atomic layer: one anchor → one micro-move. Templates ([`template-catalog.md`](template-catalog.md)) -are built from these; when no template fits a group, the planner **free-composes** by naming -primitives from here, and the frame-worker realizes them. Two readers, one file: - -- **Planner (Step 3)** — scan **what it does** + **anchor** to pick the primitives a free group rides. Selection only. -- **Frame-worker (Step 4)** — open the cited recipe and lift its tweens. Build only. - -The **recipe** column says what to lift: - -- **✓** — a runnable, lint-clean composition at `motion-primitives//index.html`. Open it and lift the tweens. -- **≈ ``** — no separate file; use that recipe, it's the same idea. -- **—** — no file; implement inline from the description (a one-liner, e.g. a 0ms `tl.set`, or a move a template realizes internally). +The atomic layer: one anchor → one micro-move. When no template fits a group, free-compose by +naming primitives from here. Scan **anchor** + **best span** + **what it does**, then pick the +smallest set that carries the group. ## Timing & latency (applies to every primitive) -Quantified from frame-accurate reverse engineering of beat-synced reels: - - **Hard hits are 0ms.** Cuts, palette flips, content swaps, freezes are `tl.set(...)` with no duration — the percussion _is_ the motion. Easing a hit kills it. - **Lead the anchor.** A move that must _land_ on a beat (a wipe covering the frame, a count-up locking, two blocks colliding) starts **~40–190ms early** so it completes ON the anchor. Reactive entrances (something appearing _because_ of the hit) fire 0–45ms after. - **Eased entrances: 300–500ms** (scale punch, slides, camera pushes). **Macro builds: 800–2000ms** spanning a whole roll / silence. -- **Magnitudes:** scale-punch 0→1; weight pulse 1→1.06; hero fill up to 1→5; chromatic split ~20px, resolve clean in ≤150ms. - **Per-bar caps:** one accumulating element per hit (not a burst); a camera move at most once per phrase, never per beat; a dense flip/strobe system runs ≤2–3s. - **Tension-builds lock.** A count-up / sequential build / morph must _resolve on_ a downbeat or hard_stop, never trail off mid-bar. +- **Best span means active motion.** The catalog's span guidance is not a license to stretch one primitive over a whole frame. If a free-composed group runs longer than the listed span, add a hold / bed / next primitive, or split the frame into another group at the next musical anchor. ## Catalog -Each runnable recipe is self-contained and lint-clean: showcase chrome stripped, system-font -fallback, shared `../assets/gsap.min.js`, one paused timeline on `window.__timelines["main"]`. - -| id | anchor | what it does | recipe | -| --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------- | -| `hypercut-whip` | beat / hard_stop | fast whip-pan hard cut between frames | ✓ | -| `kinetic-letter-in` | downbeat / phrase | per-letter kinetic entrance | ✓ | -| `braam-punch` | drop / surge | big "braam" impact — scale + weight slam | ✓ | -| `chromatic-split` | snare / glitch / surge | RGB channel split / glitch on a word | ✓ | -| `mask-reveal` | section_start / downbeat | clip-path mask wipe reveal | ✓ | -| `screen-shake` | drop / crash / kick | camera / screen shake jitter | ✓ | -| `binary-decrypt` | roll / build | scramble→decode text (binary → word) | ✓ | -| `dolly-zoom` | phrase / build | vertigo dolly-zoom (scale vs perspective) | ✓ | -| `iris-open` | section_start / reveal | circular iris-open reveal | ✓ | -| `electric-arc` | accent / glitch | electric arc / lightning accent | ✓ | -| `neon-flicker` | hold / texture | neon-sign flicker | ✓ | -| `chrome-sweep` | downbeat / reveal | metallic specular sweep across text | ✓ | -| `slot-machine-reveal` | roll → downbeat | slot-machine spin-to-land character reveal | ✓ | -| `liquid-morph` | phrase / transition | liquid / blob morph | ✓ | -| `gooey-metaball` | build / drop | gooey metaball merge field | ✓ | -| `3d-card-flip` | downbeat / swap | 3D card flip (rotateY) | ✓ | -| `crash-zoom-in` | drop / surge | violent crash zoom-in | ✓ | -| `spotlight-sweep` | reveal / hold | spotlight / gradient sweep over text | ✓ | -| `outline-to-fill` | downbeat / reveal | stroke outline → solid fill | ✓ | -| `counting-punch` | roll → downbeat | number count-up that punches & locks | ✓ | -| `particle-burst` | drop / crash | particle explosion burst | ✓ | -| `radial-burst-lines` | drop / surge | radial speed-lines burst | ✓ | -| `pixel-dissolve` | transition / hard_stop | pixelated dissolve | ✓ | -| `datamosh-smear` | glitch / transition | datamosh / motion smear | ✓ | -| `text-wave-distort` | hold / texture | wavy text distortion | ✓ | -| `bg-flow-field` | energy / whole span (bed) | generative WebGL curl-noise flow-field **background bed** — palette-driven, breathes on the energy envelope; compose any foreground move over it | ✓ | -| `blur-resolve` | stop / final hold | blur-in to crisp focus, then blur-out on the cut | ✓ | -| `chromatic-pressure` | snare / glitch | RGB split / digital tension on a transient | ≈ `chromatic-split` | -| `color-grid-shuffle` | onset | grid of cells recoloured by a deterministic index per onset | — | -| `content-swap` | beat | 0ms swap of stacked nodes — the workhorse percussive move | ≈ `slot-machine-reveal` | -| `directional-fill` | beat / reveal | directional wipe-fill (scaleX) sweeping across bars | ✓ | -| `flash-cut` | drop / crash | full-frame flash masking a word / colour state change | ✓ | -| `freeze-hold` | hard_stop | freeze the moving system and hold it (desaturate + vignette) | — | -| `hard-cut` | beat / hard_stop | sample-accurate 0ms colour-block + word cut | ✓ | -| `mosaic-pack` | beat / build | scattered tiles fly in and pack into a grid | ✓ | -| `negative-space-hold` | silence / hard_stop / final hold | kill busy layers, hold one readable mark in empty space | — | -| `overlay-pop` | accent | badge / lower-third overlay pops in over a base | — | -| `palette-flip` | section change | same layout re-skins via 0ms palette-variable flips | ✓ | -| `staggered-exit` | phrase / transition | ordered cascade-out clearing the frame | ✓ | -| `staggered-reveal` | build | ordered cascade-in of a stack / list | — | -| `system-replace` | drop / regime change | hard-cut the entire visual system, then boot the new one | — | -| `text-spectral-rays` | phrase / sweep (hero text) | volumetric spectral light-rays cast by a wordmark toward a sweeping light cursor — grain + RGB-split; **WebGL hero-text system** | ✓ | -| `tile-mosaic` | build / reveal | grid of tiles revealed in a diagonal sweep, assembling a poster | ✓ | -| `typewriter-reveal` | roll / build | char / word type-on, explicit per-span set (no `stagger`) + caret | ✓ | -| `value-counter` | roll → downbeat | count-up that locks on a downbeat / hard_stop | ≈ `counting-punch` | -| `word-grid-burst` | onsets → downbeat | grid of words revealed per onset, refocus one on a downbeat | ✓ | - -> **Template-private verbs.** Some templates declare moves realized only inside their own -> impl — `held_lockup`, `anchor_pop_in`, `word_slot_cycle`, `per_line_color`, -> `scene_palette_flip`, `beat_jitter_shake`, `box_zoom_wipe` (`split-anchor-word-slot`), -> `motion-blur` (`logo-split-lockup-pulse`). Those live in the template's `index.html`, not here. +| id | anchor | best span | what it does | +| --------------------- | -------------------------------- | ----------------- | ------------------------------------------------------------------------- | +| `hypercut-whip` | beat / hard_stop | 0.18-0.45s | fast whip-pan hard cut between frames | +| `kinetic-letter-in` | downbeat / phrase | 0.4-1.2s | per-letter kinetic entrance | +| `braam-punch` | drop / surge | 0.2-0.9s active | big impact: scale + weight slam | +| `chromatic-split` | snare / glitch / surge | 0.1-0.6s | RGB channel split / glitch on a word | +| `mask-reveal` | section_start / downbeat | 0.5-1.2s | clip-path mask wipe reveal | +| `screen-shake` | drop / crash / kick | 0.1-0.5s | camera / screen shake jitter | +| `binary-decrypt` | roll / build | 0.8-2.5s | scramble→decode text (binary → word) | +| `dolly-zoom` | phrase / build | 1.2-2.5s | vertigo dolly-zoom (scale vs perspective) | +| `iris-open` | section_start / reveal | 0.6-1.2s | circular iris-open reveal | +| `electric-arc` | accent / glitch | 0.1-0.6s | electric arc / lightning accent | +| `neon-flicker` | hold / texture | 0.5-2.5s | neon-sign flicker | +| `chrome-sweep` | downbeat / reveal | 0.6-1.4s | metallic specular sweep across text | +| `slot-machine-reveal` | roll → downbeat | 0.8-2.0s | slot-machine spin-to-land character reveal | +| `liquid-morph` | phrase / transition | 1.0-2.5s | liquid / blob morph | +| `gooey-metaball` | build / drop | 1.5-3.0s | gooey metaball merge field | +| `3d-card-flip` | downbeat / swap | 0.8-1.6s | 3D card flip (rotateY) | +| `crash-zoom-in` | drop / surge | 0.2-0.8s | violent crash zoom-in | +| `spotlight-sweep` | reveal / hold | 0.8-2.0s | spotlight / gradient sweep over text | +| `outline-to-fill` | downbeat / reveal | 0.8-1.8s | stroke outline → solid fill | +| `counting-punch` | roll → downbeat | 1.0-2.5s | number count-up that punches & locks | +| `particle-burst` | drop / crash | 0.2-1.2s | particle explosion burst | +| `radial-burst-lines` | drop / surge | 0.2-0.8s | radial speed-lines burst | +| `pixel-dissolve` | transition / hard_stop | 0.5-1.5s | pixelated dissolve | +| `datamosh-smear` | glitch / transition | 0.4-1.2s | datamosh / motion smear | +| `text-wave-distort` | hold / texture | 1.0-2.5s | wavy text distortion | +| `bg-flow-field` | energy / whole span (bed) | 4-12s bed | generative curl-noise background bed; compose any foreground move over it | +| `blur-resolve` | stop / final hold | 0.7-2.0s | blur-in to crisp focus, then blur-out on the cut | +| `chromatic-pressure` | snare / glitch | 0.1-0.5s | RGB split / digital tension on a transient | +| `color-grid-shuffle` | onset | 0ms hits; ≤2s run | grid of cells recolored by a deterministic index per onset | +| `content-swap` | beat | 0ms hits; ≤3s run | 0ms swap of stacked nodes: the workhorse percussive move | +| `directional-fill` | beat / reveal | 0.3-1.0s each | directional wipe-fill (scaleX) sweeping across bars | +| `flash-cut` | drop / crash | 0-0.6s | full-frame flash masking a word / color state change | +| `freeze-hold` | hard_stop | 0ms in; 0.5-2s | freeze the moving system and hold it | +| `hard-cut` | beat / hard_stop | 0ms in; 0.3-2s | sample-accurate color-block + word cut | +| `mosaic-pack` | beat / build | 1.5-3.5s | scattered tiles fly in and pack into a grid | +| `negative-space-hold` | silence / hard_stop / final hold | 1-6s hold | kill busy layers, hold one readable mark in empty space | +| `overlay-pop` | accent | 0.2-0.6s in | badge / lower-third overlay pops in over a base | +| `palette-flip` | section change | 0ms flip; 0.5-4s | same layout re-skins via 0ms palette-variable flips | +| `staggered-exit` | phrase / transition | 0.4-1.2s | ordered cascade-out clearing the frame | +| `staggered-reveal` | build | 0.8-2.5s | ordered cascade-in of a stack / list | +| `system-replace` | drop / regime change | 0ms cut | hard-cut the entire visual system, then boot the new one | +| `text-spectral-rays` | phrase / sweep (hero text) | 2.5-5s | volumetric light-rays cast by a wordmark toward a sweeping light cursor | +| `tile-mosaic` | build / reveal | 1.5-3.5s | grid of tiles revealed in a diagonal sweep, assembling a poster | +| `typewriter-reveal` | roll / build | 1.0-3.0s | character / word type-on with caret | +| `value-counter` | roll → downbeat | 1.0-2.5s | count-up that locks on a downbeat / hard_stop | +| `word-grid-burst` | onsets → downbeat | 1.8-3.2s | grid of words revealed per onset, refocus one on a downbeat | ## How to combine -- One dominant system per group; layer at most one texture recipe over one structural recipe. +- One dominant system per group; layer at most one texture primitive over one structural primitive. - Structure on strong beats (cuts, camera, `system-replace` → downbeat / phrase / section_start); texture on weak / syncopated hits (`content-swap`, typewriter letters, chromatic accents). - A roll is an accumulation container — build during it, hard-cut to a clean layout on the downbeat that ends it. - `drop` ≠ `downbeat`: a downbeat is a cut within the regime; a drop is a regime change (`system-replace`, total clear, element-count jump). - Let silence remove density (`negative-space-hold`). -- **Background beds are a layer, not a move.** A bed (`bg-flow-field`) runs the whole span on the **energy / phrase** channel, leaving the **beat anchors** free for the foreground — so it composes cleanly _under_ any discrete primitive. One bed at a time; merge the bed's uniform tweens onto the group's master timeline (don't run a second timeline), bundle a local `three`/WebGL (no CDN), repaint via the timeline's `onUpdate` (no rAF). -- **WebGL "system" primitives come in two roles:** a **bed** (`bg-flow-field`, behind everything) and a **hero-text treatment** (`text-spectral-rays`, which rasterizes the wordmark and _is_ the hero). Use at most one of each; feed text/raster locally (no CDN fonts), repaint via `onUpdate`. -- **`text-spectral-rays` renders its OWN wordmark — never give the word a second source.** It draws the solid letters AND the rays from one glyph mask (perfectly registered). Do NOT use it as a "rays-only" layer behind a separate DOM logo (or stack `content-swap` / `chromatic-pressure` on the same word): the two fonts/positions won't match and you get a doubled / ghosted wordmark — deleting the shader's letter terms does not fix it (the ray mask is still the second, misaligned copy). Let the shader be the wordmark; hide any DOM logo (keep it only as an invisible layout spacer). If you move the word off frame-center, move the light cursor's `y` by the same amount. Full recipe: [`motion-primitives/text-spectral-rays/USAGE.md`](motion-primitives/text-spectral-rays/USAGE.md). +- Background beds are a layer, not a move: one bed at a time, under foreground primitives. +- `text-spectral-rays` is the hero wordmark treatment; do not stack another visible copy of the same word on top. diff --git a/skills/music-to-video/references/template-catalog.md b/skills/music-to-video/references/template-catalog.md index 72a4f1790..45cb44d9c 100644 --- a/skills/music-to-video/references/template-catalog.md +++ b/skills/music-to-video/references/template-catalog.md @@ -6,9 +6,10 @@ template realizes **one group** of a frame (a frame may stack several groups; th unifies them). **How to pick.** For each group, read its frame's `pacing` + `mood` + the one-line music -situation from the skeleton, then scan **Reach for it when** below and take the closest fit. -If nothing fits, **free-compose** from [`motion-primitive-catalog.md`](motion-primitive-catalog.md) -— that is a first-class choice, not a failure. +situation from the skeleton, then scan **Reach for it when** + **Best span** below and take the +closest fit. If nothing fits, **free-compose** from +[`motion-primitive-catalog.md`](motion-primitive-catalog.md) — that is a first-class choice, not a +failure. **Brand comes from `frame.md`, not the template.** Templates ship their own demo palette (`theme` / `palette` / color params). Fill those params from the project's `frame.md` (the @@ -22,58 +23,84 @@ reads those at build time; you only name the values. Pacing tag: every template below is **beat_cut** except `held-message-living-field` (**phrase_flow**). Never put a beat_cut template on a phrase_flow frame. +## Group duration discipline + +Template choice is per **group**, not per frame. A frame longer than a template's **Best span** +should usually split into multiple groups at real audiomap anchors (`SURGE`, `DROP`, roll edge, +hard_stop, phrase edge) instead of stretching one template across the whole frame. + +- **Best span** below is the active treatment span: the part where the template's system is doing + meaningful motion. A short readable hold at the end is fine; a long empty tail means pick another + group. +- **Frames over ~6s** usually need 2+ groups. Beat-cut exceptions are rich programs with real + sub-phases (`poster-tile-mosaic`, sometimes `card-flyby`); phrase-flow exceptions use + `held-message-living-field`. +- **Roll templates are one-roll tools.** If a frame has two rolls or a drop between rolls, split it + into two groups. +- Do not extend by slowing every tween. Preserve the template's motion feel, then fill extra time + with a hold / palette change / new group. + --- ### card-flyby - **What** — a depth column of cards rolls forward through perspective; each landing beat tumbles the next card into the front slot with a solid colored wipe, the old front falls toward camera, dwells shrink card-to-card so the deck accelerates into a held final card. - **Reach for it when** — a stream of discrete onsets that **accelerate** (gaps shrinking / a build into a downbeat) and you want to flash a **sequence of items** — titles, projects, posters, tiles — one per hit, climaxing on a held card. +- **Best span** — **4-6.5s** for 4-7 landings plus a short final hold; split at the next downbeat if it wants to run **>7s**. - **Params** — `theme`, `bgColor`, `cards`, `landings`, `yaw` ### held-message-living-field · phrase_flow - **What** — a readable mark (logo / word / title) held dead still over a soft, color-shifting blurred field; only the field breathes. - **Reach for it when** — a **calm / sparse** stretch with an onset desert — energy present but few or no onsets (a held pad or riser); you have one word or mark to hold and let breathe. +- **Best span** — **6-16s**; this is the long-group exception. Under 4s feels underdeveloped; over ~20s needs a state change or another group. - **Params** — `markText`, `titleText`, `tagText`, `palette`, `flowSpeed`, `duration` ### held-text-strobe-burst - **What** — a dead-still word whose letters flip through texture-filled frames (texture-clipped fill + per-frame tint + bg color) every ~3 frames, in short bursts pinned to a roll. - **Reach for it when** — a **dense, hard-hitting roll / fill** and a single word you want to strobe through textures for a few bars. (Ships texture-mask PNGs under `assets/`.) +- **Best span** — **1.2-3.5s**; strobe fatigue starts fast, so cap at ~4s and cut to a cleaner system. - **Params** — `markText`, `fontStyle`, `markScale`, `idleColor`, `idleInk`, `frames`, `strobePlan`, `decor`, `duration` ### intro-kinetic-cascade - **What** — a line laid out as a sequence of big editorial **phrases** (each a stacked poster with one enlarged hero word), revealed word-by-word on its anchors, hard cut between phrases, climaxing on a phrase that slides in with a swappable ringing **icon** (bell / cursor / sparkle / emoji / SVG). - **Reach for it when** — an **intro / opening statement**: a short line to land word-by-word as big type, climaxing on one keyword + an icon. Medium-or-more energy, steady grid. +- **Best span** — **3.5-7s** for 2-4 phrase beats; if the statement needs more time, make the next clause a new group. - **Params** — `theme`, `icon`, `phrases`, `climax` ### logo-split-lockup-pulse - **What** — a two-part mark joined at center splits left↔right to open a gap, grows a center word-lockup one word per onset (key word lands on the downbeat surge), snap-closes on a hit, then pulses with the beat. - **Reach for it when** — a short **logo / brand sting** (not a typed sentence): fast dense onsets + a sustained roll bed to pulse on, with a left/right bracketing mark. +- **Best span** — **2-4s**; at **>4.5s** it reads like a sting stretched too long. Follow with a separate held-lockup / next idea group. - **Params** — `bgColor`, `markColor`, `textColor`, `leftMark`, `rightMark`, `word1`, `word2`, `word3`, `word4` ### poster-tile-mosaic - **What** — a packed **mosaic** of different-sized colored tiles that tessellate to fill the frame (no overlap), driven by interchangeable beat-synced operations: staggered enter/exit, locked global recolor, snake-fill + overlay. - **Reach for it when** — many discrete, individually-placeable onsets (a hit for every tile move) with distinct sub-phases you want articulated differently (accumulate → recolor-on-roll → fill-then-drop). A dense section best held as **one** rich tile program rather than split. +- **Best span** — **4-7s**, up to **8s** only when the program has clear sub-phases. If the music changes regime, split even if the tile system could continue. - **Params** — `bgColor`, `tiles`, `bands`, `gap`, `showText`, `labels`, `program` ### roll-flipbook-word-cycle - **What** — a hi-hat roll drives a centred word that flips every 16th-note through a word list; optionally the flicker resolves and locks into a final phrase. - **Reach for it when** — a **fast sustained-fill roll** (hundreds of hits/min, ~16th-note) with no single readable message — fill the roll with a rapidly-cycling word flipbook. +- **Best span** — **1.2-3.8s**, one roll into one resolve. Two rolls, or a drop between rolls, means two groups. - **Params** — `bgColor`, `textColor`, `accentColor`, `flipWords`, `resolveText`, `periodChar` ### split-anchor-word-slot - **What** — a held left anchor column of fixed-word rows beside a torn-paper word-slot box on the right, driven by beat-synced operators: anchor lock-in, slot word-group cycle (in/out + per-line color), full-scene background flip, per-beat jitter, box-zoom exit wipe. Row count + number of flips are data. - **Reach for it when** — a short section with a **held idea** (a brand / name to anchor on the left) **and** a stream of onsets popping separate words on the right, plus a dense run to ride a shake on and a strong downbeat to wipe out into. +- **Best span** — **3-6s**; above ~6.5s the fixed anchor goes stale unless the right slot enters a new group/program. - **Params** — `bgColor`, `anchors`, `theme`, `showText`, `program` ### typewriter-phrase-keyword-shuffle - **What** — words type in one-per-onset to spell a phrase, then one keyword cycles typefaces on the beat while everything else holds dead still. - **Reach for it when** — a steady grid with a **continuous onset stream** (no desert): a phrase to type out, then a keyword to shuffle. The inverse of `held-message-living-field` (which wants an onset desert). +- **Best span** — **2.5-5s**; if the phrase cannot type and shuffle inside ~5s, reduce words or split the sentence across groups. - **Params** — `bgColor`, `textColor`, `accentColor`, `lead1`, `lead2`, `lead3`, `keyword`, `periodChar` diff --git a/skills/music-to-video/references/templates/card-flyby/assets/gsap.min.js b/skills/music-to-video/references/templates/card-flyby/assets/gsap.min.js deleted file mode 100644 index 3c73d761a..000000000 --- a/skills/music-to-video/references/templates/card-flyby/assets/gsap.min.js +++ /dev/null @@ -1,11 +0,0 @@ -/*! - * GSAP 3.15.0 - * https://gsap.com - * - * @license Copyright 2026, GreenSock. All rights reserved. - * Subject to the terms at https://gsap.com/standard-license. - * @author: Jack Doyle, jack@greensock.com - */ - -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).window=t.window||{})}(this,function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function r(t){return"string"==typeof t}function s(t){return"function"==typeof t}function t(t){return"number"==typeof t}function u(t){return void 0===t}function v(t){return"object"==typeof t}function w(t){return!1!==t}function x(){return"undefined"!=typeof window}function y(t){return s(t)||r(t)}function R(t){return(i=bt(t,ht))&&Fe}function S(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function T(t,e){return!e&&console.warn(t)}function U(t,e){return t&&(ht[t]=e)&&i&&(i[t]=e)||ht}function V(){return 0}function ga(t){var e,r,i=t[0];if(v(i)||s(i)||(t=[t]),!(e=(i._gsap||{}).harness)){for(r=yt.length;r--&&!yt[r].targetTest(i););e=yt[r]}for(r=t.length;r--;)t[r]&&(t[r]._gsap||(t[r]._gsap=new Xt(t[r],e)))||t.splice(r,1);return t}function ha(t){return t._gsap||ga(Pt(t))[0]._gsap}function ia(t,e,r){return(r=t[e])&&s(r)?t[e]():u(r)&&t.getAttribute&&t.getAttribute(e)||r}function ja(t,e){return(t=t.split(",")).forEach(e)||t}function ka(t){return Math.round(1e5*t)/1e5||0}function la(t){return Math.round(1e7*t)/1e7||0}function ma(t,e){var r=e.charAt(0),i=parseFloat(e.substr(2));return t=parseFloat(t),"+"===r?t+i:"-"===r?t-i:"*"===r?t*i:t/i}function na(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++ia;)s=s._prev;return s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t,e}function Ba(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function Ca(t,e){t.parent&&(!e||t.parent.autoRemoveChildren)&&t.parent.remove&&t.parent.remove(t),t._act=0}function Da(t,e){if(t&&(!e||e._end>t._dur||e._start<0))for(var r=t;r;)r._dirty=1,r=r.parent;return t}function Fa(t,e,r,i){return t._startAt&&(I?t._startAt.revert(ft):t.vars.immediateRender&&!t.vars.autoRevert||t._startAt.render(e,!0,i))}function Ha(t){return t._repeat?wt(t._tTime,t=t.duration()+t._rDelay)*t:0}function Ja(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function Ka(t){return t._end=la(t._start+(t._tDur/Math.abs(t._ts||t._rts||q)||0))}function La(t,e){var r=t._dp;return r&&r.smoothChildTiming&&t._ts&&(t._start=la(r._time-(0q)&&e.render(r,!0)),Da(t,e)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur(n=Math.abs(n))&&(a=i,o=n);return a}function wb(t){return Ca(t),t.scrollTrigger&&t.scrollTrigger.kill(!!I),t.progress()<1&&At(t,"onInterrupt"),t}function zb(t){if(t)if(t=!t.name&&t.default||t,x()||t.headless){var e=t.name,r=s(t),i=e&&!r&&t.init?function(){this._props=[]}:t,n={init:V,render:_e,add:$t,kill:Te,modifier:ve,rawVars:0},a={targetTest:0,get:0,getSetter:ue,aliases:{},register:0};if(Lt(),t!==i){if(mt[e])return;ta(i,ta(xa(t,n),a)),bt(i.prototype,bt(n,xa(t,a))),mt[i.prop=e]=i,t.targetTest&&(yt.push(i),dt[e]=1),e=("css"===e?"CSS":e.charAt(0).toUpperCase()+e.substr(1))+"Plugin"}U(e,i),t.register&&t.register(Fe,i,we)}else Dt.push(t)}function Cb(t,e,r){return(6*(t+=t<0?1:1>16,e>>8&zt,e&zt]:0:Rt.black;if(!p){if(","===e.substr(-1)&&(e=e.substr(0,e.length-1)),Rt[e])p=Rt[e];else if("#"===e.charAt(0)){if(e.length<6&&(e="#"+(n=e.charAt(1))+n+(a=e.charAt(2))+a+(s=e.charAt(3))+s+(5===e.length?e.charAt(4)+e.charAt(4):"")),9===e.length)return[(p=parseInt(e.substr(1,6),16))>>16,p>>8&zt,p&zt,parseInt(e.substr(7),16)/255];p=[(e=parseInt(e.substr(1),16))>>16,e>>8&zt,e&zt]}else if("hsl"===e.substr(0,3))if(p=d=e.match(rt),r){if(~e.indexOf("="))return p=e.match(it),i&&p.length<4&&(p[3]=1),p}else o=+p[0]%360/360,u=p[1]/100,n=2*(h=p[2]/100)-(a=h<=.5?h*(u+1):h+u-h*u),3=X?u.endTime(!1):t._dur;return r(e)&&(isNaN(e)||e in o)?(a=e.charAt(0),s="%"===e.substr(-1),n=e.indexOf("="),"<"===a||">"===a?(0<=n&&(e=e.replace(/=/,"")),("<"===a?u._start:u.endTime(0<=u._repeat))+(parseFloat(e.substr(1))||0)*(s?(n<0?u:i).totalDuration()/100:1)):n<0?(e in o||(o[e]=h),o[e]):(a=parseFloat(e.charAt(n-1)+e.substr(n+1)),s&&i&&(a=a/100*(K(i)?i[0]:i).totalDuration()),1=r&&te)return i;i=i._next}else for(i=t._last;i&&i._start>=r;){if("isPause"===i.data&&i._start=n._start)&&n._ts&&h!==n){if(n.parent!==this)return this.render(t,e,r);if(n.render(0=this.totalDuration()||!v&&_)&&(f!==this._start&&Math.abs(l)===Math.abs(this._ts)||this._lock||(!t&&g||!(v===m&&0=i&&(a instanceof te?e&&n.push(a):(r&&n.push(a),t&&n.push.apply(n,a.getChildren(!0,e,r)))),a=a._next;return n},e.getById=function getById(t){for(var e=this.getChildren(1,1,1),r=e.length;r--;)if(e[r].vars.id===t)return e[r]},e.remove=function remove(t){return r(t)?this.removeLabel(t):s(t)?this.killTweensOf(t):(t.parent===this&&Ba(this,t),t===this._recent&&(this._recent=this._last),Da(this))},e.totalTime=function totalTime(t,e){return arguments.length?(this._forcing=1,!this._dp&&this._ts&&(this._start=la(It.time-(0r:!r||s.isActive())&&n.push(s):(i=s.getTweensOf(a,r)).length&&n.push.apply(n,i),s=s._next;return n},e.tweenTo=function tweenTo(t,e){e=e||{};var r,i=this,n=Ot(i,t),a=e.startAt,s=e.onStart,o=e.onStartParams,u=e.immediateRender,h=te.to(i,ta({ease:e.ease||"none",lazy:!1,immediateRender:!1,time:n,overwrite:"auto",duration:e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale())||q,onStart:function onStart(){if(i.pause(),!r){var t=e.duration||Math.abs((n-(a&&"time"in a?a.time:i._time))/i.timeScale());h._dur!==t&&Ua(h,t,0,1).render(h._time,!0,!0),r=1}s&&s.apply(h,o||[])}},e));return u?h.render(0):h},e.tweenFromTo=function tweenFromTo(t,e,r){return this.tweenTo(e,ta({startAt:{time:Ot(this,t)}},r))},e.recent=function recent(){return this._recent},e.nextLabel=function nextLabel(t){return void 0===t&&(t=this._time),ub(this,Ot(this,t))},e.previousLabel=function previousLabel(t){return void 0===t&&(t=this._time),ub(this,Ot(this,t),1)},e.currentLabel=function currentLabel(t){return arguments.length?this.seek(t,!0):this.previousLabel(this._time+q)},e.shiftChildren=function shiftChildren(t,e,r){void 0===r&&(r=0);var i,n=this._first,a=this.labels;for(t=la(t);n;)n._start>=r&&(n._start+=t,n._end+=t),n=n._next;if(e)for(i in a)a[i]>=r&&(a[i]+=t);return Da(this)},e.invalidate=function invalidate(t){var e=this._first;for(this._lock=0;e;)e.invalidate(t),e=e._next;return i.prototype.invalidate.call(this,t)},e.clear=function clear(t){void 0===t&&(t=!0);for(var e,r=this._first;r;)e=r._next,this.remove(r),r=e;return this._dp&&(this._time=this._tTime=this._pTime=0),t&&(this.labels={}),Da(this)},e.totalDuration=function totalDuration(t){var e,r,i,n=0,a=this,s=a._last,o=X;if(arguments.length)return a.timeScale((a._repeat<0?a.duration():a.totalDuration())/(a.reversed()?-t:t));if(a._dirty){for(i=a.parent;s;)e=s._prev,s._dirty&&s.totalDuration(),o<(r=s._start)&&a._sort&&s._ts&&!a._lock?(a._lock=1,Na(a,s,r-s._delay,1)._lock=0):o=r,r<0&&s._ts&&(n-=r,(!i&&!a._dp||i&&i.smoothChildTiming)&&(a._start+=la(r/a._ts),a._time-=r,a._tTime-=r),a.shiftChildren(-r,!1,-Infinity),o=0),s._end>n&&s._ts&&(n=s._end),s=e;Ua(a,a===L&&a._time>n?a._time:n,1,1),a._dirty=0}return a._tDur},Timeline.updateRoot=function updateRoot(t){if(L._ts&&(qa(L,Ja(t,L)),f=It.frame),It.frame>=vt){vt+=Y.autoSleep||120;var e=L._first;if((!e||!e._ts)&&Y.autoSleep&&It._listeners.length<2){for(;e&&!e._ts;)e=e._next;e||It.sleep()}}},Timeline}(qt);ta(Gt.prototype,{_lock:0,_hasPause:0,_forcing:0});function cc(t,e,i,n,a,o){var u,h,l,f;if(mt[t]&&!1!==(u=new mt[t]).init(a,u.rawVars?e[t]:function _processVars(t,e,i,n,a){if(s(t)&&(t=Qt(t,a,e,i,n)),!v(t)||t.style&&t.nodeType||K(t)||J(t))return r(t)?Qt(t,a,e,i,n):t;var o,u={};for(o in t)u[o]=Qt(t[o],a,e,i,n);return u}(e[t],n,a,o,i),i,n,o)&&(i._pt=h=new we(i._pt,a,t,0,1,u.render,u,0,u.priority),i!==c))for(l=i._ptLookup[i._targets.indexOf(a)],f=u._props.length;f--;)l[u._props[f]]=h;return u}function ic(t,r,e,i){var n,a,s=r.ease||i||"power1.inOut";if(K(r))a=e[t]||(e[t]=[]),r.forEach(function(t,e){return a.push({t:e/(r.length-1)*100,v:t,e:s})});else for(n in r)a=e[n]||(e[n]=[]),"ease"===n||a.push({t:parseFloat(t),v:r[n],e:s})}var Zt,Wt,$t=function _addPropTween(t,e,i,n,a,o,u,h,l,f){s(n)&&(n=n(a||0,t,o));var c,d=t[e],p="get"!==i?i:s(d)?l?t[e.indexOf("set")||!s(t["get"+e.substr(3)])?e:"get"+e.substr(3)](l):t[e]():d,_=s(d)?l?se:ae:ie;if(r(n)&&(~n.indexOf("random(")&&(n=rb(n)),"="===n.charAt(1)&&(!(c=ma(p,n)+(_a(p)||0))&&0!==c||(n=c))),!f||p!==n||Wt)return isNaN(p*n)||""===n?(d||e in t||S(e,n),function _addComplexStringPropTween(t,e,r,i,n,a,s){var o,u,h,l,f,c,d,p,_=new we(this._pt,t,e,0,1,pe,null,n),m=0,g=0;for(_.b=r,_.e=i,r+="",(d=~(i+="").indexOf("random("))&&(i=rb(i)),a&&(a(p=[r,i],t,e),r=p[0],i=p[1]),u=r.match(at)||[];o=at.exec(i);)l=o[0],f=i.substring(m,o.index),h?h=(h+1)%5:"rgba("===f.substr(-5)&&(h=1),l!==u[g++]&&(c=parseFloat(u[g-1])||0,_._pt={_next:_._pt,p:f||1===g?f:",",s:c,c:"="===l.charAt(1)?ma(c,l)-c:parseFloat(l)-c,m:h&&h<4?Math.round:0},m=at.lastIndex);return _.c=m")}),s.duration();else{for(l in u={},k)"ease"===l||"easeEach"===l||ic(l,k[l],u,k.easeEach);for(l in u)for(A=u[l].sort(function(t,e){return t.t-e.t}),o=R=0;o=t._tDur||e<0)&&t.ratio===u&&(u&&Ca(t,1),r||I||(At(t,u?"onComplete":"onReverseComplete",!0),t._prom&&t._prom()))}else t._zTime||(t._zTime=e)}(this,t,e,r);return this},e.targets=function targets(){return this._targets},e.invalidate=function invalidate(t){return t&&this.vars.runBackwards||(this._startAt=0),this._pt=this._op=this._onUpdate=this._lazy=this.ratio=0,this._ptLookup=[],this.timeline&&this.timeline.invalidate(t),E.prototype.invalidate.call(this,t)},e.resetTo=function resetTo(t,e,r,i,n){d||It.wake(),this._ts||this.play();var a,s=Math.min(this._dur,(this._dp._time-this._start)*this._ts);return this._initted||Ht(this,s),a=this._ease(s/this._dur),function _updatePropTweens(t,e,r,i,n,a,s,o){var u,h,l,f,c=(t._pt&&t._ptCache||(t._ptCache={}))[e];if(!c)for(c=t._ptCache[e]=[],l=t._ptLookup,f=t._targets.length;f--;){if((u=l[f][e])&&u.d&&u.d._pt)for(u=u.d._pt;u&&u.p!==e&&u.fp!==e;)u=u._next;if(!u)return Wt=1,t.vars[e]="+=0",Ht(t,s),Wt=0,o?T(e+" not eligible for reset. Try splitting into individual properties"):1;c.push(u)}for(f=c.length;f--;)(u=(h=c[f])._pt||h).s=!i&&0!==i||n?u.s+(i||0)+a*u.c:i,u.c=r-u.s,h.e&&(h.e=ka(r)+_a(h.e)),h.b&&(h.b=u.s+_a(h.b))}(this,t,e,r,i,a,s,n)?this.resetTo(t,e,r,i,1):(La(this,0),this.parent||Aa(this._dp,this,"_first","_last",this._dp._sort?"_start":0),this.render(0))},e.kill=function kill(t,e){if(void 0===e&&(e="all"),!(t||e&&"all"!==e))return this._lazy=this._pt=0,this.parent?wb(this):this.scrollTrigger&&this.scrollTrigger.kill(!!I),this;if(this.timeline){var i=this.timeline.totalDuration();return this.timeline.killTweensOf(t,e,Zt&&!0!==Zt.vars.overwrite)._first||wb(this),this.parent&&i!==this.timeline.totalDuration()&&Ua(this,this._dur*this.timeline._tDur/i,0,1),this}var n,a,s,o,u,h,l,f=this._targets,c=t?Pt(t):f,d=this._ptLookup,p=this._pt;if((!e||"all"===e)&&function _arraysMatch(t,e){for(var r=t.length,i=r===e.length;i&&r--&&t[r]===e[r];);return r<0}(f,c))return"all"===e&&(this._pt=0),wb(this);for(n=this._op=this._op||[],"all"!==e&&(r(e)&&(u={},ja(e,function(t){return u[t]=1}),e=u),e=function _addAliasesToVars(t,e){var r,i,n,a,s=t[0]?ha(t[0]).harness:0,o=s&&s.aliases;if(!o)return e;for(i in r=bt({},e),o)if(i in r)for(n=(a=o[i].split(",")).length;n--;)r[a[n]]=r[i];return r}(f,e)),l=f.length;l--;)if(~c.indexOf(f[l]))for(u in a=d[l],"all"===e?(n[l]=e,o=a,s={}):(s=n[l]=n[l]||{},o=e),o)(h=a&&a[u])&&("kill"in h.d&&!0!==h.d.kill(u)||Ba(this,h,"_pt"),delete a[u]),"all"!==s&&(s[u]=1);return this._initted&&!this._pt&&p&&wb(this),this},Tween.to=function to(t,e,r){return new Tween(t,e,r)},Tween.from=function from(t,e){return Ya(1,arguments)},Tween.delayedCall=function delayedCall(t,e,r,i){return new Tween(e,0,{immediateRender:!1,lazy:!1,overwrite:!1,delay:t,onComplete:e,onReverseComplete:e,onCompleteParams:r,onReverseCompleteParams:r,callbackScope:i})},Tween.fromTo=function fromTo(t,e,r){return Ya(2,arguments)},Tween.set=function set(t,e){return e.duration=0,e.repeatDelay||(e.repeat=0),new Tween(t,e)},Tween.killTweensOf=function killTweensOf(t,e,r){return L.killTweensOf(t,e,r)},Tween}(qt);ta(te.prototype,{_targets:[],_lazy:0,_startAt:0,_op:0,_onInit:0}),ja("staggerTo,staggerFrom,staggerFromTo",function(r){te[r]=function(){var t=new Gt,e=Ct.call(arguments,0);return e.splice("staggerFromTo"===r?5:4,0,0),t[r].apply(t,e)}});function qc(t,e,r){return t.setAttribute(e,r)}function yc(t,e,r,i){i.mSet(t,e,i.m.call(i.tween,r,i.mt),i)}var ie=function _setterPlain(t,e,r){return t[e]=r},ae=function _setterFunc(t,e,r){return t[e](r)},se=function _setterFuncWithParam(t,e,r,i){return t[e](i.fp,r)},ue=function _getSetter(t,e){return s(t[e])?ae:u(t[e])&&t.setAttribute?qc:ie},fe=function _renderPlain(t,e){return e.set(e.t,e.p,Math.round(1e6*(e.s+e.c*t))/1e6,e)},de=function _renderBoolean(t,e){return e.set(e.t,e.p,!!(e.s+e.c*t),e)},pe=function _renderComplexString(t,e){var r=e._pt,i="";if(!t&&e.b)i=e.b;else if(1===t&&e.e)i=e.e;else{for(;r;)i=r.p+(r.m?r.m(r.s+r.c*t):Math.round(1e4*(r.s+r.c*t))/1e4)+i,r=r._next;i+=e.c}e.set(e.t,e.p,i,e)},_e=function _renderPropTweens(t,e){for(var r=e._pt;r;)r.r(t,r.d),r=r._next},ve=function _addPluginModifier(t,e,r,i){for(var n,a=this._pt;a;)n=a._next,a.p===i&&a.modifier(t,e,r),a=n},Te=function _killPropTweensOf(t){for(var e,r,i=this._pt;i;)r=i._next,i.p===t&&!i.op||i.op===t?Ba(this,i,"_pt"):i.dep||(e=1),i=r;return!e},be=function _sortPropTweensByPriority(t){for(var e,r,i,n,a=t._pt;a;){for(e=a._next,r=i;r&&r.pr>a.pr;)r=r._next;(a._prev=r?r._prev:n)?a._prev._next=a:i=a,(a._next=r)?r._prev=a:n=a,a=e}t._pt=i},we=(PropTween.prototype.modifier=function modifier(t,e,r){this.mSet=this.mSet||this.set,this.set=yc,this.m=t,this.mt=r,this.tween=e},PropTween);function PropTween(t,e,r,i,n,a,s,o,u){this.t=e,this.s=i,this.c=n,this.p=r,this.r=a||fe,this.d=s||this,this.set=o||ie,this.pr=u||0,(this._next=t)&&(t._prev=this)}ja(Tt+"parent,duration,ease,delay,overwrite,runBackwards,startAt,yoyo,immediateRender,repeat,repeatDelay,data,paused,reversed,lazy,callbackScope,stringFilter,id,yoyoEase,stagger,inherit,repeatRefresh,keyframes,autoRevert,scrollTrigger,easeReverse",function(t){return dt[t]=1}),ht.TweenMax=ht.TweenLite=te,ht.TimelineLite=ht.TimelineMax=Gt,L=new Gt({sortChildren:!1,defaults:j,autoRemoveChildren:!0,id:"root",smoothChildTiming:!0}),Y.stringFilter=Ib;function Gc(t){return(Oe[t]||Me).map(function(t){return t()})}function Hc(){var t=Date.now(),o=[];2 Card Flyby · accelerating 3D deck cascade — reference impl - +