@topy-ai/maggie 0.8.15 → 0.8.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-TW.md +1 -1
- package/README.md +1 -1
- package/bundled-references/captions-transcription.md +21 -1
- package/bundled-references/design-editor-patterns.md +29 -2
- package/bundled-references/ffmpeg-recipes.md +21 -0
- package/bundled-references/generative-visuals.md +23 -0
- package/bundled-references/image-recipes.md +43 -0
- package/bundled-references/programmatic-video.md +22 -0
- package/bundled-references/video-timeline-model.md +22 -4
- package/bundled-references/web-animation-patterns.md +124 -29
- package/bundled-skills/maggie-image/SKILL.md +6 -2
- package/bundled-skills/maggie-video/SKILL.md +1 -1
- package/bundled-tools/clis/maggie_image.py +40 -3
- package/bundled-tools/clis/maggie_video.py +22 -14
- package/package.json +1 -1
- package/references/captions-transcription.md +21 -1
- package/references/design-editor-patterns.md +29 -2
- package/references/ffmpeg-recipes.md +21 -0
- package/references/generative-visuals.md +23 -0
- package/references/image-recipes.md +43 -0
- package/references/programmatic-video.md +22 -0
- package/references/video-timeline-model.md +22 -4
- package/references/web-animation-patterns.md +124 -29
|
@@ -25,7 +25,8 @@ sequenced, scroll-driven work.
|
|
|
25
25
|
gsap.registerPlugin(ScrollTrigger);
|
|
26
26
|
const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.6 } });
|
|
27
27
|
tl.from(".hero h1", { y: 40, opacity: 0 })
|
|
28
|
-
.from(".hero p", { y: 24, opacity: 0 }, "-=0.3")
|
|
28
|
+
.from(".hero p", { y: 24, opacity: 0 }, "-=0.3") // overlap previous by 0.3s
|
|
29
|
+
.from(".hero a", { opacity: 0 }, "<"); // "<"/">" = start/end of prev tween
|
|
29
30
|
gsap.from(".card", {
|
|
30
31
|
scrollTrigger: { trigger: ".card", start: "top 80%", once: true },
|
|
31
32
|
y: 32, opacity: 0, stagger: 0.08,
|
|
@@ -35,6 +36,10 @@ gsap.from(".card", {
|
|
|
35
36
|
GSAP including all former Club plugins is 100% free for commercial use, but it is a
|
|
36
37
|
proprietary license, not open source — flag it before bundling. CDN:
|
|
37
38
|
`cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js`.
|
|
39
|
+
*Source note:* the `0.6`/`power3.out` above are our **house** defaults, not GSAP's
|
|
40
|
+
(its own tween defaults are `0.5`/`power1.out` = quad); don't attribute them to GSAP.
|
|
41
|
+
Parameterized ease strings — `"elastic.out(1,0.5)"`, `"back.out(1.7)"`,
|
|
42
|
+
`"steps(12)"` — author a bespoke curve as a string.
|
|
38
43
|
**Reach for it when:** a page needs a real timeline (chained, overlapping steps) or
|
|
39
44
|
scroll-scrubbed sequencing beyond a one-shot reveal. Overkill for simple fades.
|
|
40
45
|
|
|
@@ -45,13 +50,17 @@ springs, `scroll()`, `inView()`, layout transitions.
|
|
|
45
50
|
```js
|
|
46
51
|
import { animate, inView, scroll, stagger } from "motion";
|
|
47
52
|
animate("#box", { x: 100, opacity: 1 }, { type: "spring", stiffness: 300, damping: 30 });
|
|
48
|
-
inView(".card", (el) => { animate(el, { opacity: 1, y: 0 }); }, { amount:
|
|
53
|
+
inView(".card", (el) => { animate(el, { opacity: 1, y: 0 }); }, { amount: "some" });
|
|
54
|
+
// inView idiom is amount:"some"|"all" (a number works too) + margin (→ rootMargin)
|
|
49
55
|
// React: <motion.div initial={{opacity:0,y:24}} whileInView={{opacity:1,y:0}} viewport={{once:true}}/>
|
|
50
56
|
```
|
|
51
57
|
**License: MIT** (core; a paid "Motion+" add-on exists but isn't required).
|
|
52
58
|
**Reach for it when:** the project is already React/Vue, or you want springs +
|
|
53
59
|
scroll + inView from one small MIT lib. `inView` is a clean IntersectionObserver
|
|
54
|
-
wrapper — our preferred engine when a dependency is acceptable.
|
|
60
|
+
wrapper — our preferred engine when a dependency is acceptable. `motion/mini` is a
|
|
61
|
+
WAAPI-only subset for the smallest payload. Spring also takes a **designer mode**
|
|
62
|
+
`{ visualDuration, bounce }` (settle-time + bounciness, SwiftUI-style) instead of raw
|
|
63
|
+
`stiffness/damping` — expose that to non-engineers (see the Spring pattern below).
|
|
55
64
|
|
|
56
65
|
### anime.js (juliangarnier/anime) — v4
|
|
57
66
|
Small, elegant timeline/stagger/easing lib. V4 is ESM tree-shakable.
|
|
@@ -61,9 +70,14 @@ animate(".square", {
|
|
|
61
70
|
x: 320, rotate: { from: -180 }, duration: 1250,
|
|
62
71
|
delay: stagger(65, { from: "center" }), ease: "inOutQuint",
|
|
63
72
|
});
|
|
73
|
+
// 2D ripple from a grid cell (v4): delay: stagger(60, { grid: [cols, rows], from: "center" })
|
|
64
74
|
```
|
|
65
|
-
**License: MIT
|
|
66
|
-
|
|
75
|
+
**License: MIT** (v4: ESM, per-feature export subpaths — `animejs`, `animejs/stagger`,
|
|
76
|
+
…; exports `animate, stagger, createTimeline, createTimer, createSpring, onScroll`,
|
|
77
|
+
`eases/utils/svg/text`). **Reach for it when:** you want expressive staggers/keyframes
|
|
78
|
+
lighter than GSAP and don't need ScrollTrigger-grade scroll control. Stagger vocabulary
|
|
79
|
+
is rich: `from:'first'|'center'|'last'|'random'|index`, `grid:[x,y]`, `axis`,
|
|
80
|
+
`reversed`, and an `ease` (even a spring) across the stagger.
|
|
67
81
|
|
|
68
82
|
### lottie-web (airbnb/lottie-web)
|
|
69
83
|
Plays **Lottie JSON** (vector animations exported from After Effects via Bodymovin)
|
|
@@ -75,10 +89,16 @@ const anim = lottie.loadAnimation({
|
|
|
75
89
|
});
|
|
76
90
|
anim.playSegments([0, 60], true); // play part of the timeline
|
|
77
91
|
anim.setSpeed(1); anim.pause();
|
|
92
|
+
lottie.freeze(); // GLOBAL pause of every instance (tab hidden)
|
|
78
93
|
```
|
|
79
94
|
**License: MIT.** **Reach for it when:** a designer delivers an AE/Lottie file and
|
|
80
95
|
you need a crisp, scalable, small looped illustration (see §2 Lottie workflow).
|
|
81
|
-
Default to `renderer: "svg"`; switch to `canvas` for heavy/many-layer files.
|
|
96
|
+
Default to `renderer: "svg"`; switch to `canvas` for heavy/many-layer files. For a
|
|
97
|
+
small payload load the **`lottie_light`** build (SVG-only, no expressions). Perf/sync
|
|
98
|
+
hooks worth using: `progressiveLoad`, `setSubframe(false)`, and the fine-grained events
|
|
99
|
+
`enterFrame`/`loopComplete`/`segmentStart`. `freeze()/unfreeze()` are **global**
|
|
100
|
+
(all instances); per-instance use `pause`/`goToAndStop`. No built-in reduced-motion —
|
|
101
|
+
gate it yourself.
|
|
82
102
|
|
|
83
103
|
### rlottie (Samsung/rlottie)
|
|
84
104
|
Native (C++) Lottie renderer — the runtime behind Lottie on native/embedded (not a
|
|
@@ -117,20 +137,26 @@ Animate-on-scroll via HTML data-attributes + a prebuilt CSS set.
|
|
|
117
137
|
data-aos-once="true" data-aos-anchor-placement="top-center"></div>
|
|
118
138
|
<script>AOS.init({ once: true, duration: 800, easing: "ease-out-cubic" });</script>
|
|
119
139
|
```
|
|
120
|
-
**License: MIT.**
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
vocabulary (`fade-up`, `once`, per-element
|
|
140
|
+
**License: MIT.** **Correction (source-verified, v3.0.0-beta.6):** this release does
|
|
141
|
+
**not** use IntersectionObserver — it is classic **scroll + `lodash.throttle`**
|
|
142
|
+
(`throttleDelay:99`); the only observer is a MutationObserver for auto-refresh on DOM
|
|
143
|
+
injection. So copy its attribute *vocabulary* (`fade-up`, `once`, per-element
|
|
144
|
+
delay/offset/anchor-placement), but do **not** credit it for observer efficiency — our
|
|
145
|
+
hand-rolled reveal (§2) with a real IntersectionObserver is the better engine.
|
|
146
|
+
**Reach for it when:** a no-JS-authoring team wants declarative scroll reveals fast.
|
|
124
147
|
|
|
125
148
|
### typed.js (mattboldt/typed.js)
|
|
126
149
|
Typewriter effect.
|
|
127
150
|
```js
|
|
128
151
|
const typed = new Typed("#el", { strings: ["First.", "& second."], typeSpeed: 50, backSpeed: 30, loop: true });
|
|
129
152
|
```
|
|
130
|
-
**License: GPL — flag it
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
153
|
+
**License: GPL-3.0 — flag it** (source-verified; the repo also ships paid
|
|
154
|
+
`LIMITED`/`UNLIMITED_COMMERCIAL_LICENSE.md` with a Stripe link — a paid escape from
|
|
155
|
+
copyleft). Do **not** bundle into proprietary/client output; reimplement the ~20-line
|
|
156
|
+
effect yourself (or buy the commercial license). It also has **zero** reduced-motion
|
|
157
|
+
handling (grep-confirmed) — you must gate it. **Reach for the pattern when:** a hero
|
|
158
|
+
rotates through phrases. Keep it short, respect reduced-motion (render the final string
|
|
159
|
+
statically).
|
|
134
160
|
|
|
135
161
|
### tsparticles (tsparticles/tsparticles)
|
|
136
162
|
Config-driven particle backgrounds/confetti.
|
|
@@ -143,6 +169,27 @@ await tsParticles.load({ id: "tsparticles", options: {
|
|
|
143
169
|
**License: MIT.** **Reach for it when:** a hero wants a subtle particle/constellation
|
|
144
170
|
backdrop or a celebratory confetti burst. Use sparingly — it's a performance and
|
|
145
171
|
taste liability; cap particle count, pause offscreen, disable on reduced-motion.
|
|
172
|
+
Source notes: v3+ `load()` takes **one object** `{ id, element?, options?, url? }`
|
|
173
|
+
(positional form gone); 22 presets (`confetti`/`fireworks`/`snow`/`stars`/`links`/…)
|
|
174
|
+
are one-line `preset:` strings; ship the **slim** bundle + only the `@tsparticles/*`
|
|
175
|
+
feature packages you use. It also ships CLI scaffolders (`npm create tsparticles@latest`,
|
|
176
|
+
`create-confetti`) and an **MCP server** — precedent for an agent-driven particle config.
|
|
177
|
+
(Legacy origin: `particles.js` v2 — single-file, unmaintained, snake_case schema; use
|
|
178
|
+
tsparticles instead, which bundles a `pjs` compat shim.)
|
|
179
|
+
|
|
180
|
+
### mojs (@mojs/core)
|
|
181
|
+
Motion-graphics toolbelt for the web — the one lib here built for **celebratory point
|
|
182
|
+
bursts / success micro-interactions** (likes, add-to-cart, CTA confirm), a genuine gap
|
|
183
|
+
the others don't fill. Actively maintained.
|
|
184
|
+
```js
|
|
185
|
+
import { Burst, Shape } from "@mojs/core";
|
|
186
|
+
new Burst({ left: x, top: y, count: 8, radius: { 0: 60 },
|
|
187
|
+
children: { shape: "circle", fill: "#e94560", duration: 700 } }).play();
|
|
188
|
+
```
|
|
189
|
+
**License: MIT.** Also `ShapeSwirl`, `Html` (tween real DOM), `Timeline`, `stagger`,
|
|
190
|
+
custom eases via `easing.path("M0,100 ...")` / `easing.bezier()`. **Reach for it when:**
|
|
191
|
+
a discrete interaction deserves a tactile burst — keep it to a single gesture, gate on
|
|
192
|
+
reduced-motion.
|
|
146
193
|
|
|
147
194
|
### rive (rive-app/rive-runtime)
|
|
148
195
|
Interactive vector animations driven by **state machines** (inputs → states), not
|
|
@@ -161,23 +208,32 @@ drives animation state) — interactive mascots, animated toggles. Heavier workf
|
|
|
161
208
|
Animates SVG stroke draw-on ("self-drawing" line art).
|
|
162
209
|
```js
|
|
163
210
|
new Vivus("my-svg", { type: "oneByOne", duration: 200, start: "inViewport" }, cb);
|
|
164
|
-
// type: delayed
|
|
211
|
+
// type: delayed|sync|async|nsync|oneByOne|scenario|scenario-sync ; start: inViewport|manual|autostart
|
|
212
|
+
v.setFrameProgress(0.5); // scrub draw 0..1 (drive from scroll); play(-1) rewinds
|
|
165
213
|
```
|
|
166
|
-
**License: MIT.**
|
|
167
|
-
|
|
214
|
+
**License: MIT.** Timing fns are statics (`Vivus.EASE_OUT`, custom `function(x)`), set
|
|
215
|
+
whole (`animTimingFunction`) or per-path (`pathTimingFunction`); per-path
|
|
216
|
+
`data-delay/duration`, `data-vivus-ignore`; bundles `pathformer` (primitives → path).
|
|
217
|
+
**Reach for it when:** a logo/icon/diagram should draw itself in — and, via
|
|
218
|
+
`setFrameProgress(0..1)`, a **scroll-linked** draw-on (extends §2's one-shot draw). The
|
|
219
|
+
same effect is achievable with CSS `stroke-dasharray`/`stroke-dashoffset` — use
|
|
168
220
|
that for one element, Vivus when orchestrating many paths.
|
|
169
221
|
|
|
170
222
|
### lenis (darkroomengineering/lenis)
|
|
171
223
|
Smooth-scroll normalizer (momentum/eased scrolling). Already referenced by
|
|
172
224
|
`maggie-clone`.
|
|
173
225
|
```js
|
|
174
|
-
const lenis = new Lenis({ autoRaf: true }); //
|
|
175
|
-
lenis.on("scroll", (e) => {/*
|
|
226
|
+
const lenis = new Lenis({ autoRaf: true }); // DEFAULT is autoRaf:false → drive lenis.raf(t) yourself
|
|
227
|
+
lenis.on("scroll", (e) => {/* e is the whole Lenis instance: e.scroll/.velocity/.progress/.direction */});
|
|
176
228
|
```
|
|
177
229
|
**License: MIT.** **Reach for it when:** the design calls for premium eased scrolling
|
|
178
230
|
and you pair it with scroll-triggered motion (commonly `lenis.raf` + GSAP
|
|
179
|
-
ScrollTrigger).
|
|
180
|
-
|
|
231
|
+
ScrollTrigger). **Source-verified defaults:** `lerp` is `0.1` (not 0.075 — that's
|
|
232
|
+
`syncTouchLerp`), `autoRaf` defaults **false**, and `respectReducedMotion` is a
|
|
233
|
+
first-class option (defaults true, falls back to native scroll via matchMedia).
|
|
234
|
+
Attribute opt-outs: `data-lenis-prevent[-vertical|-horizontal]`. Accessibility caveat:
|
|
235
|
+
keep `respectReducedMotion` on; never trap scroll in a way that breaks keyboard/anchor
|
|
236
|
+
jumps.
|
|
181
237
|
|
|
182
238
|
### barba.js (barbajs/barba)
|
|
183
239
|
SPA-style page transitions over MPAs: intercepts navigation, animates the old
|
|
@@ -203,6 +259,11 @@ return <animated.div style={styles}>…</animated.div>;
|
|
|
203
259
|
```
|
|
204
260
|
**License: MIT.** **Reach for it when:** a React project wants physics-based
|
|
205
261
|
(not duration-based) motion. For non-React, Motion's `spring` covers the same need.
|
|
262
|
+
**Source-verified presets** (`tension`/`friction`[/`mass`]): default `{170,26}`,
|
|
263
|
+
`gentle {120,14}`, `wobbly {180,12}`, `stiff {210,20}`, `slow {280,60}`,
|
|
264
|
+
`molasses {280,120}`. The `AnimationConfig` also exposes a **designer-friendly**
|
|
265
|
+
vocabulary — `frequency` + `damping(ratio)` (tension/friction derived from them),
|
|
266
|
+
plus `clamp`, `bounce`, `decay` — prefer these when writing a config for non-engineers.
|
|
206
267
|
|
|
207
268
|
### animate.css (animate-css/animate.css)
|
|
208
269
|
Prebuilt CSS keyframe classes (`animate__animated animate__fadeInUp`).
|
|
@@ -211,9 +272,20 @@ Prebuilt CSS keyframe classes (`animate__animated animate__fadeInUp`).
|
|
|
211
272
|
```
|
|
212
273
|
**License: Hippocratic License 2.1 — flag it (NOT MIT).** An ethical-source license
|
|
213
274
|
with use restrictions; not OSI-approved. Treat as a caution for commercial bundling;
|
|
214
|
-
the keyframe recipes (`fadeInUp`, durations, timing)
|
|
215
|
-
|
|
216
|
-
|
|
275
|
+
the keyframe recipes (`fadeInUp`, the `back_*` entrance/exit family, durations, timing)
|
|
276
|
+
are fine to **reimplement** yourself. Two patterns worth copying wholesale: its
|
|
277
|
+
**3-custom-prop timing system** (`--animate-duration` / `--animate-delay` /
|
|
278
|
+
`--animate-repeat` + `calc()` utility multipliers) and its built-in **reduced-motion /
|
|
279
|
+
print kill-switch** (collapses to 1ms and forces `*Out` animations to opacity 0 so
|
|
280
|
+
content never sticks hidden). **Reach for the patterns when:** you want a quick
|
|
281
|
+
named-entrance vocabulary — but author your own keyframes to stay license-clean.
|
|
282
|
+
|
|
283
|
+
### Out of scope — pixijs (pixijs/pixijs)
|
|
284
|
+
A WebGL/WebGPU **2D renderer**, not an animation engine: it ships no tween/easing (its
|
|
285
|
+
`Ticker` gives only `deltaTime`). The particle/shader libs build *on* it; for standard
|
|
286
|
+
DOM/CSS marketing motion it's out of scope — reach for it only for a heavy custom
|
|
287
|
+
canvas scene, and bring your own tween (GSAP/Motion). (Notable: it ships 26 first-party
|
|
288
|
+
`SKILL.md` agent skills — precedent for a library shipping its own skills.)
|
|
217
289
|
|
|
218
290
|
### Category O (offline / desktop, NOT web)
|
|
219
291
|
- **synfig** (synfig/synfig) — desktop 2D vector animation studio. **GPL-3.0.**
|
|
@@ -236,14 +308,28 @@ Default to expressive ease-out curves, never browser defaults (`ease`, `linear`,
|
|
|
236
308
|
color/opacity 300ms (never < 200ms). Other good ones: `cubic-bezier(0.16,1,0.3,1)`
|
|
237
309
|
(ease-out-expo), `cubic-bezier(0.34,1.56,0.64,1)` (gentle back/overshoot).
|
|
238
310
|
Libs: GSAP eases, anime `inOut*`, Motion. **LP + DM.**
|
|
311
|
+
*Custom eases as data:* when a bespoke curve is needed, author it as data rather than
|
|
312
|
+
code — GSAP parameterized strings (`"back.out(1.7)"`), mojs `easing.path()`/`bezier()`,
|
|
313
|
+
vivus custom `function(x)`, or a popmotion-style `mirror/reverse` of a base ease. Store
|
|
314
|
+
the curve with the motion spec (see Theatre.js data model below).
|
|
239
315
|
|
|
240
316
|
### Spring physics
|
|
241
317
|
Duration-less, physics-based motion — natural for interactive/hover and anything
|
|
242
318
|
that should feel tactile. Config shape is universal: `{ stiffness, damping, mass }`
|
|
243
319
|
(Motion: `type:"spring", stiffness:300, damping:30`; react-spring: `config.gentle`).
|
|
320
|
+
For configs a non-engineer will touch, prefer the **designer vocabulary** both engines
|
|
321
|
+
expose — Motion `{ visualDuration, bounce }`, react-spring `frequency` +
|
|
322
|
+
`damping(ratio)` (settle-time + bounciness), rather than raw stiffness/damping.
|
|
244
323
|
Libs: Motion `spring`, react-spring, GSAP (via plugins). **DM;** light touch on LP
|
|
245
324
|
(mostly micro-interactions).
|
|
246
325
|
|
|
326
|
+
### Burst / success micro-interaction
|
|
327
|
+
A discrete gesture (like, add-to-cart, CTA confirm) earns a one-shot radial burst from
|
|
328
|
+
the click point — one shape stamped into N transformed copies with an opacity ramp.
|
|
329
|
+
Lib: mojs `Burst` (or a hand-rolled radial-stamp, same idea as the Lottie Repeater in
|
|
330
|
+
[generative visuals](generative-visuals.md)). One gesture only; gate on reduced-motion.
|
|
331
|
+
**LP (primary CTA) + DM.**
|
|
332
|
+
|
|
247
333
|
### Scroll-reveal via IntersectionObserver — never scroll listeners
|
|
248
334
|
Elements rise ~32px and fade over 600–800ms, **once**, when they cross into view.
|
|
249
335
|
Always IntersectionObserver (or a lib that wraps it); never an unthrottled `scroll`
|
|
@@ -349,7 +435,10 @@ illustration when a designer supplies the JSON.
|
|
|
349
435
|
| auto-animate | MIT | |
|
|
350
436
|
| AOS | MIT | |
|
|
351
437
|
| typed.js | **GPL** | **Flag — don't bundle in proprietary output; reimplement.** |
|
|
352
|
-
| tsparticles | MIT | |
|
|
438
|
+
| tsparticles | MIT | v3+ single-object `load()`; ships CLI scaffolders + an MCP server. |
|
|
439
|
+
| particles.js | MIT | Legacy v2, unmaintained — use tsparticles (`pjs` compat). |
|
|
440
|
+
| mojs (@mojs/core) | MIT | Celebratory point bursts / success micro-interactions. |
|
|
441
|
+
| pixijs | MIT | WebGL 2D **renderer**, no tween — out of scope for DOM motion. |
|
|
353
442
|
| rive-runtime | MIT | Web runtime is `@rive-app/canvas`. |
|
|
354
443
|
| vivus | MIT | |
|
|
355
444
|
| lenis | MIT | |
|
|
@@ -371,9 +460,10 @@ state**, replayed by a tiny headless runtime (`@theatre/core`) against three.js,
|
|
|
371
460
|
HTML/SVG, or any JS variable. The borrowable pattern is the **declarative keyframe
|
|
372
461
|
document**, not the editor: store motion as JSON - a `sequence` with `length` +
|
|
373
462
|
`subUnitsPerUnit` (an fps snap-grid) -> **tracks keyed by property path** ->
|
|
374
|
-
**keyframes** each carrying `{ position, value, handles:[lx,ly,rx,ry],
|
|
375
|
-
type
|
|
376
|
-
data; `
|
|
463
|
+
**keyframes** each carrying `{ id, position, value, handles:[lx,ly,rx,ry],
|
|
464
|
+
connectedRight:boolean, type?:'bezier'|'hold' }` (per-keyframe bezier handles =
|
|
465
|
+
per-segment easing baked into data; `type` is optional, defaults bezier; `value` may be
|
|
466
|
+
non-numeric). Playback mirrors CSS: `play({ iterationCount,
|
|
377
467
|
range, rate, direction:'alternateReverse' })`. Author a brand motion once, commit the
|
|
378
468
|
JSON as a reusable asset, replay it deterministically with no editor shipped - the
|
|
379
469
|
authoring story for `maggie-design-motion` (keep the motion *spec* as data, not
|
|
@@ -395,4 +485,9 @@ hero as `inputs -> conditions -> states` - declare inputs (`hovered:bool`,
|
|
|
395
485
|
`scroll:0..1`, `clicked:trigger`), bind DOM events to them, and switch CSS/WAAPI/GSAP
|
|
396
486
|
timelines by state rather than scripting each handler; a number input + interpolation
|
|
397
487
|
gives scroll-linked response, random-picked idle transitions give a "living" element.
|
|
398
|
-
(Rive's own MIT player is also a legitimate option.)
|
|
488
|
+
(Rive's own MIT player is also a legitimate option.) Source-verified, the model is
|
|
489
|
+
richer than the sketch above: any input source maps onto one **unified listener bus**
|
|
490
|
+
(pointer/scroll/keyboard/gamepad/text/focus), transitions can be guarded by **app data**
|
|
491
|
+
via **ViewModel data-binding conditions** (not just events), comparator ops are a full
|
|
492
|
+
enum (`eq/neq/lt/gt/lte/gte`), and nested state machines compose — so "driven by data,
|
|
493
|
+
not handlers" is the portable lesson for a browser reimplementation.
|