@topy-ai/maggie 0.8.10 → 0.8.12

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.
@@ -0,0 +1,90 @@
1
+ # Generative visuals (creative coding)
2
+
3
+ Patterns for generating marketing visuals in code - hero backgrounds, textures, 3D
4
+ product shots, data-viz, and stylized images - distilled from the leading creative-
5
+ coding libraries. We adopt **patterns, not code**. Output becomes a deliverable as a
6
+ **still** (canvas/SVG export) or a **loop** (captured via
7
+ [design-motion production](design-motion-production.md) Part C or
8
+ [ffmpeg recipes](ffmpeg-recipes.md), then assembled in `maggie-video`). Determinism
9
+ by seeding matches `maggie-spirit`'s philosophy: same seed -> same pixels.
10
+
11
+ ## Libraries
12
+
13
+ | Library | What / model | Lang | License | Marketing fit |
14
+ |---|---|---|---|---|
15
+ | three.js | WebGL 3D: Scene + Camera + WebGLRenderer; `renderer.render(scene,camera)` in a loop | JS | MIT | 3D product spins, logo stings, depth-y hero backgrounds |
16
+ | Babylon.js | Higher-level 3D engine (PBR, asset pipeline); heavier | JS/TS | Apache-2.0 | 3D product config; alt to three when its pipeline earns the weight |
17
+ | react-three-fiber | three.js as React JSX (`<mesh><boxGeometry/>…`), `useFrame` | JS/TS | MIT | 3D on a React site |
18
+ | p5.js | Canvas sketch: `setup()` once + `draw()` per frame; `random()/noise()` with `randomSeed()/noiseSeed()` | JS | **LGPL-2.1** | generative hero backgrounds, flow fields, noise art |
19
+ | paper.js | Vector scene graph (Path/Group), boolean ops, hit-testing | JS | MIT | editable vector hero art, print-quality SVG |
20
+ | two.js | One 2D API across SVG/Canvas/WebGL renderers | JS | MIT | vector art you want to export as SVG or capture from canvas |
21
+ | rough.js | Hand-drawn/sketchy shapes; `{seed}` = reproducible | JS/TS | MIT | approachable hand-made brand style, doodle accents |
22
+ | zdog | Pseudo-3D round/flat vector, designer-friendly | JS | MIT | cute 3D-ish icons, mascot/logo spins |
23
+ | pts | Computational geometry (Space + Form + Pt) | TS/JS | Apache-2.0 | geometric/particle hero art |
24
+ | hydra | Live-coded video synth (chained GLSL ops) | JS | **AGPL-3.0** | trippy animated backgrounds - **pattern only, do not ship its code** |
25
+ | regl | Functional WebGL (stateless draw commands) | JS | MIT | custom shader backgrounds/gradients when three is overkill |
26
+ | d3 | Data-driven SVG (scales + selections) | JS | ISC | bespoke infographics - but defer standard charts to the `dataviz` skill |
27
+ | fogleman/primitive | Reproduce an image with N geometric primitives (CLI) | Go | MIT | stylize a product photo into abstract art (still or GIF) |
28
+ | svg.js | Lightweight SVG DOM manipulation | JS | MIT | programmatic SVG icons/badges/dividers |
29
+ | nannou | Rust creative framework (desktop) | Rust | MIT/Apache | note only - high-perf generative art in Rust |
30
+
31
+ **License flags:** hydra is **AGPL-3.0**, p5 is **LGPL-2.1**, processing (non-core)
32
+ is GPL - fine as *idea* sources, but do not vendor their code into shipped product;
33
+ reimplement the pattern or use an MIT equivalent (two.js / pts / regl / svg.js).
34
+
35
+ ## Patterns and the deliverable path
36
+
37
+ - **2D generative** (p5 / paper / two / rough / zdog / pts / svg.js): `setup()` once +
38
+ `draw()`/`update()` per frame. Use for brand-tinted hero/section backgrounds,
39
+ textures, doodle accents, geometric motifs. **Still:** SVG-capable libs serialize
40
+ their `<svg>` (crisp, editable, print-ready); canvas libs use `canvas.toDataURL()`
41
+ -> PNG. **Loop:** run the sketch headless and capture via design-motion Part C, or
42
+ in-browser with CCapture.js (MIT), then hand to `maggie-video`.
43
+ - **3D** (three / babylon / r3f): Scene + Camera + Renderer; animate by frame index.
44
+ Product spins, 3D logo stings, depth-y backgrounds. **Still:**
45
+ `renderer.domElement.toDataURL()` (set `preserveDrawingBuffer:true`); **loop:** drive
46
+ by frame, capture as above. Prefer three/r3f (MIT); babylon only when needed.
47
+ - **Data-viz** (d3): `d3-scale` + `d3-selection`; SVG is the native output. For
48
+ standard charts, **defer to the `dataviz` skill** (its palette/spec); pull in d3
49
+ only for bespoke marks (arc diagrams, force layouts, custom infographics).
50
+ - **Live visuals** (hydra): chained feedback-graph ops -> animated GLSL. Renders to a
51
+ canvas -> capture -> `maggie-video`. **AGPL: idea only**; for an MIT shader
52
+ background use regl.
53
+ - **Image -> primitives** (fogleman/primitive, MIT, Go CLI): stylize a photo into
54
+ abstract geometry.
55
+
56
+ ```bash
57
+ primitive -i input.png -o output.svg -n 100 -m 1
58
+ # -n shapes (50-200); -m mode (1 triangle,2 rect,3 ellipse,4 circle,6 beziers,8 polygon);
59
+ # output type by extension: PNG/JPG (raster), SVG (vector), GIF (animated, needs ImageMagick)
60
+ ```
61
+
62
+ **Still:** PNG/SVG directly; **loop:** `.gif` or `%d`-numbered PNG frames ->
63
+ `maggie-video`. It is randomized (no seed): generate once and **store the artifact**;
64
+ do not regenerate on every build.
65
+
66
+ ## Determinism
67
+
68
+ p5 `randomSeed()/noiseSeed()`, rough.js `{seed}`, and a seeded PRNG in place of
69
+ `Math.random` give byte-reproducible stills; the frame-index/virtual-clock rule from
70
+ [programmatic video](programmatic-video.md) gives reproducible motion. `primitive`
71
+ and `hydra` are non-deterministic - capture and store their output as a fixed asset.
72
+
73
+ ## Placement
74
+
75
+ - **maggie-spirit** owns seeded brand marks/characters; borrow the 2D-canvas sketch
76
+ model and seed discipline for flat-vector mark construction (zdog/two.js/rough).
77
+ Generative *backgrounds/scenes* do not live here.
78
+ - **maggie-design** owns generative hero backgrounds, section textures, 3D product
79
+ shots and image stylization as page/brand visuals; it points at this reference and
80
+ cross-links design-motion / `maggie-video` for capture-to-deliverable.
81
+ - **Reference-only:** d3 (defer to `dataviz`), hydra (AGPL, idea only), regl, babylon,
82
+ nannou/processing/openFrameworks (desktop notes), svg.js.
83
+
84
+ ## Credits
85
+
86
+ Patterns adapted (not code) from three.js, p5.js, d3, paper.js, two.js, rough.js,
87
+ zdog, pts, hydra, regl, Babylon.js, react-three-fiber, fogleman/primitive, svg.js,
88
+ nannou - licenses in the table above. Capture pipeline: see
89
+ [programmatic video](programmatic-video.md), [design-motion production](design-motion-production.md),
90
+ [ffmpeg recipes](ffmpeg-recipes.md).
@@ -0,0 +1,89 @@
1
+ # Image recipes
2
+
3
+ The distilled, correct image-processing command layer for marketing assets, used by
4
+ `maggie-image`. These are the commands `maggie_image.py` generates. Distilled from
5
+ ImageMagick, sharp, svgo, resvg, squoosh and imagemin (reference library category P).
6
+ We **invoke binaries at arm's length** (adopt defaults, not code).
7
+
8
+ **Tool posture.** ImageMagick (`magick` on IM7, else `convert`) is almost always
9
+ present and covers nearly every raster op, so it is the **primary** path; dedicated
10
+ tools (svgo, resvg, cwebp, avifenc, pngquant) are the **better-quality alternative
11
+ used automatically when installed**. Web-delivery quality defaults follow sharp/
12
+ squoosh: JPEG/WebP ~80, AVIF ~50. OG/social are **cover-cropped**; logos **pad**.
13
+ Strip metadata on anything public (privacy + bytes).
14
+
15
+ ## Resize + fit (the most-used op)
16
+
17
+ ```bash
18
+ # cover / crop to exactly WxH (fills the frame, center-crop)
19
+ convert in.jpg -strip -resize 1200x630^ -gravity center -extent 1200x630 -quality 82 out.jpg
20
+ # contain / letterbox with a pad color
21
+ convert in.jpg -strip -resize 1200x630 -background '#ffffff' -gravity center -extent 1200x630 out.jpg
22
+ # downscale-only (never enlarge): -resize 1200x630>
23
+ ```
24
+
25
+ sharp's smart crop (`fit:'cover', position:attention`) avoids cutting off a face;
26
+ ImageMagick has no equal, so for portraits prefer sharp when available.
27
+
28
+ ## WebP / AVIF (file-size wins)
29
+
30
+ ```bash
31
+ convert in.png -strip -quality 80 -define webp:method=6 out.webp # or: cwebp -q 80 -m 6 in.png -o out.webp
32
+ convert in.png -strip -quality 50 out.avif # or: avifenc -s 6 --min 20 --max 40 in.png out.avif
33
+ ```
34
+
35
+ ## Channel / OG presets
36
+
37
+ Cover-crop to the target: OG 1200x630, Twitter 1600x900, square 1080x1080, story/reel
38
+ 1080x1920, landscape 1920x1080, LinkedIn 1200x627, Pinterest 1000x1500. Same command
39
+ as cover resize with the preset size, `-strip -quality 82`.
40
+
41
+ ## Favicon + OG set
42
+
43
+ ```bash
44
+ convert in.png -define icon:auto-resize=64,48,32,16 favicon.ico # multi-res .ico
45
+ convert in.png -strip -resize 180x180 apple-touch-icon.png # + 16/32/48/192/512 PNGs
46
+ ```
47
+
48
+ ## Strip metadata / compress
49
+
50
+ ```bash
51
+ convert in.jpg -strip out.jpg # drop EXIF/GPS/ICC
52
+ convert in.jpg -strip -interlace Plane -quality 82 out.jpg # progressive JPEG
53
+ pngquant --quality 60-82 --strip --output out.png in.png # lossy PNG (best); IM fallback: -colors 256 -define png:compression-level=9
54
+ ```
55
+
56
+ ## SVG optimize / render
57
+
58
+ ```bash
59
+ svgo --multipass -i in.svg -o out.svg # keeps viewBox + title (responsive + a11y). If svgo absent, leave the SVG alone - never rasterize as a substitute.
60
+ resvg -w 512 in.svg out.png # best-fidelity SVG -> PNG (or rsvg-convert -w 512); IM fallback (-background none -density 384) is lower fidelity
61
+ ```
62
+
63
+ ## Montage / contact sheet (carousels, screenshot grids)
64
+
65
+ ```bash
66
+ montage a.png b.png c.png -tile 3x -geometry 400x400+10+10 -background '#ffffff' sheet.jpg
67
+ ```
68
+
69
+ ## The CLI
70
+
71
+ `maggie_image.py` generates each command above (and runs it with `--run` when the
72
+ tool is on PATH; `--force-im` forces the ImageMagick path). It detects IM6 `convert`
73
+ vs IM7 `magick`:
74
+
75
+ ```bash
76
+ maggie tool maggie_image.py social --input hero.png --output og.jpg --preset og
77
+ maggie tool maggie_image.py --run webp --input hero.png --output hero.webp --quality 80
78
+ maggie tool maggie_image.py --run favicon --input logo.png --out-dir public/
79
+ maggie tool maggie_image.py svg2png --input logo.svg --output logo.png --width 512
80
+ maggie tool maggie_image.py presets
81
+ ```
82
+
83
+ ## Licenses
84
+
85
+ Invoked at arm's length: ImageMagick (permissive), SVGO (MIT), resvg (MIT/Apache),
86
+ sharp (Apache-2.0), squoosh codecs (Apache-2.0), imagemin (MIT), cwebp/avifenc
87
+ (BSD). **Avoid vendoring code from** Upscayl (AGPL-3.0) - for AI upscaling invoke the
88
+ separate `realesrgan-ncnn-vulkan` binary instead. sharp/squoosh quality defaults are
89
+ adopted as the preset numbers.
@@ -97,16 +97,18 @@ shape renders through ffmpeg without any GPL engine.
97
97
 
98
98
  `maggie_video.py compile --spec timeline.json` compiles this model into one ffmpeg
99
99
  `filter_complex` command (printed; run with `--run`). Supported today: a main video
100
- track of clips (video/image) fit `cover`/`contain` to the canvas, hard-cut `concat`
101
- or sequential `crossfade` (from `transitions`), **ken-burns on image clips**
100
+ track of clips (video/image) fit `cover`/`contain`, hard-cut `concat` or sequential
101
+ `crossfade` (from `transitions`), **ken-burns on image *and* video clips**
102
102
  (`"kenBurns":{"zoom":"in"|"out","amount":0.12}` or a `zoom` effect, via `zoompan`),
103
103
  image/text/caption overlays with `position`+`duration` timing and `rect` placement,
104
- **text opacity keyframes** (`effects:[{"type":"opacity","keyframes":[{"t","v"}...]}]`,
105
- via a drawtext `alpha` expression), and an `audio[]` mix with per-track
106
- `position`/`gain` plus `loudnorm`. Output is bounded to the computed video duration
107
- and uses the shared web-safe profile. Not compiled yet (emitted as `# NOTE:` lines):
108
- ken-burns on *video* clips, non-opacity overlay effects, and sidechain ducking - set
109
- static values or use a programmatic engine for those.
104
+ **overlay keyframes** - opacity (`effects:[{"type":"opacity","keyframes":[{"t","v"}]}]`
105
+ -> drawtext/alpha), **move/slide** (`{"type":"move","x":[{t,v}],"y":[{t,v}]}` ->
106
+ animated x/y), and **zoom on sized image overlays** (`{"type":"zoom","keyframes":...}`
107
+ with `rect` w+h) - and an `audio[]` mix with per-track `position`/`gain`, **sidechain
108
+ ducking** (`"ducking":{"under":"<asset>"}` -> `sidechaincompress`), plus `loudnorm`.
109
+ Output is bounded to the computed video duration and uses the shared web-safe profile.
110
+ Remaining programmatic-engine territory (emitted as `# NOTE:` lines): animated text
111
+ font size and free-form overlay shrink/pop below 1x.
110
112
 
111
113
  ```bash
112
114
  maggie tool maggie_video.py compile --spec timeline.json # print the command
@@ -0,0 +1,364 @@
1
+ # Web / UI animation patterns
2
+
3
+ Engine-neutral motion vocabulary for marketing web pages, distilled from the leading
4
+ open-source animation libraries. We adopt **patterns and per-library guidance, not
5
+ code** — we rarely ship these libraries; we copy the technique (the eases, the
6
+ IntersectionObserver reveal, the spring config, the Lottie workflow). Feeds
7
+ `maggie-landing-page` (B7 motion + the mandatory tagline reveal) and
8
+ `maggie-design-motion` (its *website* context).
9
+
10
+ Rule of thumb: a marketing page needs **CSS transitions + IntersectionObserver +
11
+ one tiny helper** far more often than a 30KB animation engine. Reach for a library
12
+ only when the pattern below says so. Default is zero-dependency.
13
+
14
+ ---
15
+
16
+ ## 1. The libraries
17
+
18
+ Each entry: what it is · core API shape (real snippet) · license · when to reach for it.
19
+
20
+ ### GSAP (greensock/GSAP) — v3.15
21
+ Framework-agnostic JS animation engine: tweens, timelines, eases, plugins
22
+ (ScrollTrigger, SplitText, MorphSVG, Flip, MotionPath). The gold standard for
23
+ sequenced, scroll-driven work.
24
+ ```js
25
+ gsap.registerPlugin(ScrollTrigger);
26
+ const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.6 } });
27
+ tl.from(".hero h1", { y: 40, opacity: 0 })
28
+ .from(".hero p", { y: 24, opacity: 0 }, "-=0.3"); // overlap previous by 0.3s
29
+ gsap.from(".card", {
30
+ scrollTrigger: { trigger: ".card", start: "top 80%", once: true },
31
+ y: 32, opacity: 0, stagger: 0.08,
32
+ });
33
+ ```
34
+ **License: custom "Standard no-charge license" (NOT MIT/OSI).** As of 2024 (Webflow)
35
+ GSAP including all former Club plugins is 100% free for commercial use, but it is a
36
+ proprietary license, not open source — flag it before bundling. CDN:
37
+ `cdn.jsdelivr.net/npm/gsap@3.15/dist/gsap.min.js`.
38
+ **Reach for it when:** a page needs a real timeline (chained, overlapping steps) or
39
+ scroll-scrubbed sequencing beyond a one-shot reveal. Overkill for simple fades.
40
+
41
+ ### Motion / framer-motion (motiondivision/motion)
42
+ Hybrid engine: a tiny imperative `animate()` for vanilla JS plus declarative
43
+ `<motion.div>` for React/Vue. Uses the native WAAPI where possible (GPU, 120fps),
44
+ springs, `scroll()`, `inView()`, layout transitions.
45
+ ```js
46
+ import { animate, inView, scroll, stagger } from "motion";
47
+ animate("#box", { x: 100, opacity: 1 }, { type: "spring", stiffness: 300, damping: 30 });
48
+ inView(".card", (el) => { animate(el, { opacity: 1, y: 0 }); }, { amount: 0.3 });
49
+ // React: <motion.div initial={{opacity:0,y:24}} whileInView={{opacity:1,y:0}} viewport={{once:true}}/>
50
+ ```
51
+ **License: MIT** (core; a paid "Motion+" add-on exists but isn't required).
52
+ **Reach for it when:** the project is already React/Vue, or you want springs +
53
+ scroll + inView from one small MIT lib. `inView` is a clean IntersectionObserver
54
+ wrapper — our preferred engine when a dependency is acceptable.
55
+
56
+ ### anime.js (juliangarnier/anime) — v4
57
+ Small, elegant timeline/stagger/easing lib. V4 is ESM tree-shakable.
58
+ ```js
59
+ import { animate, stagger } from "animejs";
60
+ animate(".square", {
61
+ x: 320, rotate: { from: -180 }, duration: 1250,
62
+ delay: stagger(65, { from: "center" }), ease: "inOutQuint",
63
+ });
64
+ ```
65
+ **License: MIT.** **Reach for it when:** you want expressive staggers/keyframes
66
+ lighter than GSAP and don't need ScrollTrigger-grade scroll control.
67
+
68
+ ### lottie-web (airbnb/lottie-web)
69
+ Plays **Lottie JSON** (vector animations exported from After Effects via Bodymovin)
70
+ in the browser as SVG/canvas/HTML.
71
+ ```js
72
+ const anim = lottie.loadAnimation({
73
+ container: el, renderer: "svg", loop: true, autoplay: true,
74
+ path: "hero.json", // or animationData: <obj>
75
+ });
76
+ anim.playSegments([0, 60], true); // play part of the timeline
77
+ anim.setSpeed(1); anim.pause();
78
+ ```
79
+ **License: MIT.** **Reach for it when:** a designer delivers an AE/Lottie file and
80
+ 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.
82
+
83
+ ### rlottie (Samsung/rlottie)
84
+ Native (C++) Lottie renderer — the runtime behind Lottie on native/embedded (not a
85
+ web lib). Category O. **License: MIT** (mostly; some vendored parts differ, see
86
+ COPYING). **Reach for it when:** the same Lottie JSON must also play in a native app
87
+ (our Expo/RN surfaces) — same asset, native renderer. On web it's lottie-web.
88
+
89
+ ### theatre.js (theatre-js/theatre)
90
+ In-browser motion-design **editor**: scrub a timeline, keyframe any JS object's
91
+ props, then play the saved sequence at runtime via `@theatre/core`.
92
+ ```js
93
+ import { getProject } from "@theatre/core";
94
+ const sheet = getProject("Hero").sheet("Intro");
95
+ const obj = sheet.object("Logo", { x: 0, opacity: 0 });
96
+ obj.onValuesChange((v) => { el.style.transform = `translateX(${v.x}px)`; el.style.opacity = v.opacity; });
97
+ sheet.sequence.play({ iterationCount: 1 });
98
+ ```
99
+ **License: Apache-2.0.** **Reach for it when:** a complex bespoke sequence is easier
100
+ to hand-author on a timeline than in code. Niche for marketing pages; mostly a
101
+ design-time tool. Note for `maggie-design-motion`, not landing pages.
102
+
103
+ ### auto-animate (formkit/auto-animate)
104
+ Zero-config: one call and children added/removed/moved animate automatically.
105
+ ```js
106
+ import autoAnimate from "@formkit/auto-animate";
107
+ autoAnimate(document.getElementById("list")); // React: const [ref] = useAutoAnimate()
108
+ ```
109
+ **License: MIT.** **Reach for it when:** lists, filters, accordions, or reordering UI
110
+ need smooth transitions with no keyframes. Great low-effort polish for interactive
111
+ sections (pricing toggles, FAQ, filtered galleries).
112
+
113
+ ### AOS (michalsnik/aos)
114
+ Animate-on-scroll via HTML data-attributes + a prebuilt CSS set.
115
+ ```html
116
+ <div data-aos="fade-up" data-aos-delay="50" data-aos-duration="800"
117
+ data-aos-once="true" data-aos-anchor-placement="top-center"></div>
118
+ <script>AOS.init({ once: true, duration: 800, easing: "ease-out-cubic" });</script>
119
+ ```
120
+ **License: MIT.** Uses IntersectionObserver internally. **Reach for it when:** a
121
+ no-JS-authoring team wants declarative scroll reveals fast. For our output we
122
+ usually hand-roll the same effect (§2) rather than ship AOS, but its attribute
123
+ vocabulary (`fade-up`, `once`, per-element delay/offset) is the pattern to copy.
124
+
125
+ ### typed.js (mattboldt/typed.js)
126
+ Typewriter effect.
127
+ ```js
128
+ const typed = new Typed("#el", { strings: ["First.", "& second."], typeSpeed: 50, backSpeed: 30, loop: true });
129
+ ```
130
+ **License: GPL — flag it.** GNU GPL, not MIT. Do **not** bundle into proprietary
131
+ output; reimplement the ~20-line effect yourself (or use a permissive alt) if you
132
+ need typing. **Reach for the pattern when:** a hero rotates through phrases. Keep it
133
+ short, respect reduced-motion (render the final string statically).
134
+
135
+ ### tsparticles (tsparticles/tsparticles)
136
+ Config-driven particle backgrounds/confetti.
137
+ ```js
138
+ await tsParticles.load({ id: "tsparticles", options: {
139
+ background: { color: "#0d1117" },
140
+ particles: { number: { value: 60 }, move: { enable: true } },
141
+ }});
142
+ ```
143
+ **License: MIT.** **Reach for it when:** a hero wants a subtle particle/constellation
144
+ backdrop or a celebratory confetti burst. Use sparingly — it's a performance and
145
+ taste liability; cap particle count, pause offscreen, disable on reduced-motion.
146
+
147
+ ### rive (rive-app/rive-runtime)
148
+ Interactive vector animations driven by **state machines** (inputs → states), not
149
+ just linear playback. `rive-runtime` is the C++ core; on web you use `@rive-app/canvas`.
150
+ ```js
151
+ import { Rive } from "@rive-app/canvas";
152
+ const r = new Rive({ src: "button.riv", canvas, autoplay: true,
153
+ stateMachines: "State Machine 1", onLoad: () => r.resizeDrawingSurfaceToCanvas() });
154
+ r.stateMachineInputs("State Machine 1").find(i => i.name === "hover").value = true;
155
+ ```
156
+ **License: MIT.** **Reach for it when:** an element must *react* (hover/click/scroll
157
+ drives animation state) — interactive mascots, animated toggles. Heavier workflow
158
+ (needs the Rive editor); overkill for passive decoration — prefer Lottie for that.
159
+
160
+ ### vivus (maxwellito/vivus)
161
+ Animates SVG stroke draw-on ("self-drawing" line art).
162
+ ```js
163
+ new Vivus("my-svg", { type: "oneByOne", duration: 200, start: "inViewport" }, cb);
164
+ // type: delayed | sync | oneByOne | scenario ; start: inViewport | manual | autostart
165
+ ```
166
+ **License: MIT.** **Reach for it when:** a logo/icon/diagram should draw itself in.
167
+ The same effect is achievable with CSS `stroke-dasharray`/`stroke-dashoffset` — use
168
+ that for one element, Vivus when orchestrating many paths.
169
+
170
+ ### lenis (darkroomengineering/lenis)
171
+ Smooth-scroll normalizer (momentum/eased scrolling). Already referenced by
172
+ `maggie-clone`.
173
+ ```js
174
+ const lenis = new Lenis({ autoRaf: true }); // or drive lenis.raf(t) in your own rAF
175
+ lenis.on("scroll", (e) => {/* sync scroll-linked effects */});
176
+ ```
177
+ **License: MIT.** **Reach for it when:** the design calls for premium eased scrolling
178
+ and you pair it with scroll-triggered motion (commonly `lenis.raf` + GSAP
179
+ ScrollTrigger). Accessibility caveat: disable/reduce under `prefers-reduced-motion`;
180
+ never trap or override scroll in a way that breaks keyboard/anchor jumps.
181
+
182
+ ### barba.js (barbajs/barba)
183
+ SPA-style page transitions over MPAs: intercepts navigation, animates the old
184
+ container out and the new one in (no full reload).
185
+ ```js
186
+ barba.init({ transitions: [{
187
+ name: "fade",
188
+ leave: ({ current }) => gsap.to(current.container, { opacity: 0 }),
189
+ enter: ({ next }) => gsap.from(next.container, { opacity: 0 }),
190
+ }]});
191
+ // markup: <main data-barba="wrapper"><section data-barba="container" data-barba-namespace="home">
192
+ ```
193
+ **License: MIT.** **Reach for it when:** a multi-page marketing site wants seamless
194
+ cross-page transitions. Needs care for SEO/analytics/scroll-restore; often more than
195
+ a landing page needs.
196
+
197
+ ### react-spring (pmndrs/react-spring)
198
+ Spring-physics animation for React (hooks).
199
+ ```js
200
+ import { animated, useSpring } from "@react-spring/web";
201
+ const styles = useSpring({ from: { opacity: 0, y: 24 }, to: { opacity: 1, y: 0 } });
202
+ return <animated.div style={styles}>…</animated.div>;
203
+ ```
204
+ **License: MIT.** **Reach for it when:** a React project wants physics-based
205
+ (not duration-based) motion. For non-React, Motion's `spring` covers the same need.
206
+
207
+ ### animate.css (animate-css/animate.css)
208
+ Prebuilt CSS keyframe classes (`animate__animated animate__fadeInUp`).
209
+ ```html
210
+ <h1 class="animate__animated animate__fadeInUp">Hi</h1>
211
+ ```
212
+ **License: Hippocratic License 2.1 — flag it (NOT MIT).** An ethical-source license
213
+ with use restrictions; not OSI-approved. Treat as a caution for commercial bundling;
214
+ the keyframe recipes (`fadeInUp`, durations, timing) are fine to **reimplement**
215
+ yourself. **Reach for the patterns when:** you want a quick named-entrance
216
+ vocabulary — but author your own keyframes to stay license-clean.
217
+
218
+ ### Category O (offline / desktop, NOT web)
219
+ - **synfig** (synfig/synfig) — desktop 2D vector animation studio. **GPL-3.0.**
220
+ - **friction** (friction2d/friction) — desktop motion-graphics/vector animator.
221
+ **GPL-3.0.** Sparse docs.
222
+ Both are authoring tools, not runtimes. Note as offline/GPL; they can *produce*
223
+ assets (e.g. exported video/sequences) but nothing here ships to the web.
224
+
225
+ ---
226
+
227
+ ## 2. Engine-neutral pattern set (what we actually adopt)
228
+
229
+ For each pattern: the technique, which libs embody it, and where it belongs
230
+ (**LP** = `maggie-landing-page`, **DM** = `maggie-design-motion` website context).
231
+
232
+ ### Eased entrances — the good cubic-beziers
233
+ Default to expressive ease-out curves, never browser defaults (`ease`, `linear`,
234
+ `ease-in-out`). House base curve: `cubic-bezier(0.22, 1, 0.36, 1)` ("ease-out-quint",
235
+ ~500ms for layout/position; GSAP's `power3/power4.out` equivalent). Hover
236
+ color/opacity 300ms (never < 200ms). Other good ones: `cubic-bezier(0.16,1,0.3,1)`
237
+ (ease-out-expo), `cubic-bezier(0.34,1.56,0.64,1)` (gentle back/overshoot).
238
+ Libs: GSAP eases, anime `inOut*`, Motion. **LP + DM.**
239
+
240
+ ### Spring physics
241
+ Duration-less, physics-based motion — natural for interactive/hover and anything
242
+ that should feel tactile. Config shape is universal: `{ stiffness, damping, mass }`
243
+ (Motion: `type:"spring", stiffness:300, damping:30`; react-spring: `config.gentle`).
244
+ Libs: Motion `spring`, react-spring, GSAP (via plugins). **DM;** light touch on LP
245
+ (mostly micro-interactions).
246
+
247
+ ### Scroll-reveal via IntersectionObserver — never scroll listeners
248
+ Elements rise ~32px and fade over 600–800ms, **once**, when they cross into view.
249
+ Always IntersectionObserver (or a lib that wraps it); never an unthrottled `scroll`
250
+ listener. Engine-neutral baseline (no dependency):
251
+ ```js
252
+ const io = new IntersectionObserver((entries) => {
253
+ for (const e of entries) if (e.isIntersecting) {
254
+ e.target.classList.add("in"); // CSS transitions transform+opacity
255
+ io.unobserve(e.target); // once
256
+ }
257
+ }, { threshold: 0.2, rootMargin: "0px 0px -10% 0px" });
258
+ document.querySelectorAll("[data-reveal]").forEach((el) => io.observe(el));
259
+ ```
260
+ Libs that embody it: Motion `inView`, AOS (`data-aos` + `once`), GSAP ScrollTrigger
261
+ (`once:true`). **LP (core) + DM.**
262
+
263
+ ### Stagger
264
+ Sequence a group so items arrive one after another (reading order), stepped
265
+ ~60–80ms, capped (~400ms total for menus). Libs: GSAP `stagger`, anime
266
+ `stagger(65,{from:"center"})`, Motion `stagger`. Hand-rolled: per-item
267
+ `transition-delay: calc(var(--i) * 60ms)`. **LP (menu entrance, card grids) + DM.**
268
+
269
+ ### SVG draw-on
270
+ Line art draws itself via `stroke-dasharray`/`stroke-dashoffset` animated to 0.
271
+ Libs: Vivus (`type:"oneByOne"`), or pure CSS for a single path. **DM (logos,
272
+ diagrams);** occasional LP hero accent.
273
+
274
+ ### Typing
275
+ Rotate/type phrases in a hero. Pattern: type → pause → delete → next, respect
276
+ reduced-motion by rendering the final string. Lib: typed.js (**GPL — reimplement**,
277
+ don't bundle). **LP (hero headline variants) + DM.**
278
+
279
+ ### Page transitions + smooth scroll
280
+ Cross-page: animate container out/in instead of a hard reload (barba.js, or a
281
+ framework's view-transitions). Smooth scroll: eased momentum scrolling (lenis),
282
+ commonly paired with scroll-triggered motion (`lenis.raf` → GSAP ScrollTrigger).
283
+ **DM / full-site builds;** a single landing page rarely needs barba. Lenis already
284
+ used by `maggie-clone`.
285
+
286
+ ### Particles
287
+ Subtle generative backdrop or confetti. Lib: tsparticles (config: `particles.number`,
288
+ `move`, `background`). Use sparingly; cap count, pause offscreen, kill on
289
+ reduced-motion. **LP hero (optional accent) + DM.**
290
+
291
+ ### The Lottie workflow
292
+ Pipeline: **design in After Effects → export with Bodymovin → `.json` →** play with
293
+ **lottie-web** on web / **rlottie** on native (same JSON asset, two renderers).
294
+ ```js
295
+ lottie.loadAnimation({ container: el, renderer: "svg", loop: true, autoplay: true, path: "hero.json" });
296
+ ```
297
+ **When to use Lottie vs code vs looped video:**
298
+ - **Lottie** — designer-authored vector illustration/icon motion; scalable, crisp,
299
+ small, loopable, recolorable, interactive (segments/speed). The default for
300
+ "animated illustration." Prefer `renderer:"svg"`; use `canvas` for heavy files.
301
+ - **Code (CSS/GSAP/Motion)** — UI motion tied to the DOM: entrances, hovers,
302
+ scroll reveals, state changes. Anything that must respond to layout/interaction.
303
+ - **Looped video (mp4/webm)** — photographic/complex/3D content that isn't vector
304
+ and doesn't need interaction or recolor. Heaviest payload; provide a poster and
305
+ `prefers-reduced-motion` fallback. (See `references/programmatic-video.md`.)
306
+ Libs: lottie-web (web), rlottie (native). **DM (primary);** LP for a hero/spot
307
+ illustration when a designer supplies the JSON.
308
+
309
+ ---
310
+
311
+ ## 3. Performance & accessibility rules (shared by all of them)
312
+
313
+ - **Animate only `transform` and `opacity`.** Never `top`/`left`/`width`/`height`/
314
+ `margin` (they trigger layout/paint and jank). Use `transform: translate/scale`
315
+ for position and size. Prefer the compositor; add `will-change` only on the
316
+ element about to animate, and remove it after.
317
+ - **No scroll/resize listeners for reveal.** Use IntersectionObserver for visibility
318
+ and `requestAnimationFrame` for any per-frame work; throttle/debounce the rest.
319
+ Never run animation logic directly in a `scroll` handler.
320
+ - **Respect `prefers-reduced-motion`.** Replace movement with a plain opacity change
321
+ (or show the final state instantly). Gate every nontrivial effect:
322
+ ```css
323
+ @media (prefers-reduced-motion: reduce) {
324
+ *, *::before, *::after { animation-duration:.01ms!important;
325
+ animation-iteration-count:1!important; transition-duration:.01ms!important; }
326
+ }
327
+ ```
328
+ In JS, branch on `matchMedia("(prefers-reduced-motion: reduce)").matches` before
329
+ typing, particles, smooth-scroll, or autoplay loops.
330
+ - **Reveal once; don't re-fire** on scroll-back (`once:true` / `unobserve`).
331
+ - **Pause offscreen / on hidden tab** (Lottie, particles, video): check
332
+ `document.hidden` / IntersectionObserver and stop rAF to save battery/CPU.
333
+ - **Keep durations honest:** entrances 300–800ms; hovers 200–300ms; never block
334
+ interaction or delay content paint behind an animation. Don't animate above the
335
+ fold in a way that hides LCP text.
336
+
337
+ ---
338
+
339
+ ## License quick-reference
340
+
341
+ | Library | License | Note |
342
+ |---|---|---|
343
+ | GSAP | Custom "no-charge" | **Not OSI/MIT.** Free (incl. all plugins) but proprietary — flag before bundling. |
344
+ | Motion / framer-motion | MIT | Paid Motion+ add-on optional, not required. |
345
+ | anime.js | MIT | |
346
+ | lottie-web | MIT | |
347
+ | rlottie | MIT | Some vendored parts differ (see COPYING). |
348
+ | theatre.js | Apache-2.0 | |
349
+ | auto-animate | MIT | |
350
+ | AOS | MIT | |
351
+ | typed.js | **GPL** | **Flag — don't bundle in proprietary output; reimplement.** |
352
+ | tsparticles | MIT | |
353
+ | rive-runtime | MIT | Web runtime is `@rive-app/canvas`. |
354
+ | vivus | MIT | |
355
+ | lenis | MIT | |
356
+ | barba.js | MIT | |
357
+ | react-spring | MIT | |
358
+ | animate.css | **Hippocratic 2.1** | **Flag — ethical-source, not OSI. Reimplement keyframes.** |
359
+ | synfig / friction | GPL-3.0 | Desktop authoring tools (category O), not web runtimes. |
360
+
361
+ Most are MIT and safe to reference/learn from freely. The four to flag: **GSAP**
362
+ (proprietary no-charge), **typed.js** (GPL), **animate.css** (Hippocratic 2.1), and
363
+ **synfig/friction** (GPL desktop tools). For the flagged ones we adopt the *pattern*
364
+ and author our own code.