use-scroll-animate 8.4.0 → 8.6.0

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/CHANGELOG.md CHANGED
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [8.6.0] - 2026-10-09
11
+
12
+ ### Added
13
+ - **Theme system (8.6)** — five surface themes (`light`, `dark`, `neon`, `glass`, `neu` / neumorphism) driven by a `data-usa-surface` attribute; `SURFACE_THEMES`, `applySurfaceTheme(name, target?)`.
14
+ - **2 new components (8.6)** in `motionary/components/widgets` (also in `dist/widgets.umd.js`):
15
+ - `<usa-theme-switcher>` — segmented theme switcher: sets `data-usa-surface` on `target` (default `<html>`), sliding pill, circular View-Transition wipe from the click point (page-level), `themes`, `value`, `persist` (localStorage key); `usa:change` { theme }.
16
+ - `<usa-theme-surface>` — themeable card that follows the nearest `data-usa-surface` (or its own `theme`): neon glow edge that pulses, frosted glass with a sheen, soft neumorphic relief that presses; cross-fades on theme change; `theme`; `usa:theme` { theme }.
17
+ - **Surface theme pack — `motionary/fx/surface`** (= `motionary/components/fx-surface`, `registerSurfacePack()`, also in `registerEffectPacks()`): `neon-ignite` (enter), `neon-pulse` (loop), `glass-frost` (enter), `neu-press` (attention). Names chosen not to override the existing 3.x `neon-flicker` theme effect.
18
+ - Showcase: 4 new gallery cards with copyable code, live demos and live Store thumbnails.
19
+
20
+ ### Accessibility
21
+ - Theme switcher is a labelled `radiogroup` of `radio`s with roving tabindex and arrow keys; the swatches are `aria-hidden`. Theme surfaces keep your content and text contrast in every theme. Reduced motion: the switch is instant (no wipe, no pill slide), the neon / sheen loops stop, `neon-ignite` / `glass-frost` just show, `neon-pulse` is skipped, `neu-press` does nothing.
22
+
23
+ ### Fixed
24
+ - the 5.8 theme packs (applyTheme / <usa-theme>) already own the `data-usa-theme` attribute, so the 8.6 surface themes use `data-usa-surface` instead (no clash with neon/paper/glass/retro/brutalist motion themes); effect names neon-ignite (not the 5.8 neon-flicker) and 8.5 paper-unfold (not 5.8 paper-fold) avoid overriding existing effects.
25
+
26
+ ## [8.5.0] - 2026-10-09
27
+
28
+ ### Added
29
+ - **2 new components (8.5)** in `motionary/components/widgets` (also in `dist/widgets.umd.js`):
30
+ - `<usa-sticky-wall>` — wall of sticky notes: each child becomes a pinned paper note (`data-color` yellow · pink · blue · green, or cycling) with a slight tilt (`seed`); notes drop onto the wall one by one on first view; click / Enter lifts a note to the front (`pick(index)`, `usa:pick` { index }); `notes`, `label`.
31
+ - `<usa-sketch-chart>` — hand-drawn chart: wobbly pencil axes, hatched bars (`type="bar"`) or a sketchy line with dots (`type="line"`), sketched in stroke by stroke on first view; `values`, `labels`, `color`, `label`; `values` / `setValues()`; `usa:drawn`.
32
+ - **Paper & hand-drawn pack — `motionary/fx/paper`** (= `motionary/components/fx-paper`, `registerPaperPack()`, also in `registerEffectPacks()`): `paper-unfold` (enter), `pencil-sketch` (enter), `watercolor` (enter), `crumple` (attention). `roughLine()`, `paperRandom()`.
33
+ - Showcase: 4 new gallery cards with copyable code, live demos and live Store thumbnails.
34
+
35
+ ### Accessibility
36
+ - Sticky wall is a `list` of focusable `listitem`s (Enter / Space picks a note). Sketch chart is an `img` whose label lists every label and value; the drawing is `aria-hidden`. Reduced motion: notes and charts are shown at once, `paper-unfold` / `watercolor` fade in, `pencil-sketch` shows the drawing, `crumple` does nothing.
37
+
38
+ ### Fixed
39
+ - the 5.8 theme pack already registers a `paper-fold` effect, so the 8.5 unfold effect is named `paper-unfold` (registering it as `paper-fold` would have overridden the 5.8 theme effect).
40
+ - the sketch chart only sketched itself once, on first view — it now re-sketches on click / `redraw()` (gallery and Store demos replay it).
41
+ - the sticky-wall and sketch-chart gallery / Store demos only animated once on first view — demos now have "Pick a note" / "New data" buttons (wired to `pick()` / `setValues()` + `redraw()`).
42
+
10
43
  ## [8.4.0] - 2026-10-09
11
44
 
12
45
  ### Added
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ var registry = require('../chunks/registry-BVklOepd.cjs');
4
+ require('../chunks/base-DoRUZBy-.cjs');
5
+
6
+ /** A deterministic PRNG in [0, 1) from a seed (8.5). */
7
+ function paperRandom(seed) {
8
+ let s = Math.abs(Math.round(seed * 1000)) % 233280 || 11;
9
+ return () => (s = (s * 9301 + 49297) % 233280) / 233280;
10
+ }
11
+ /** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */
12
+ function roughLine(x1, y1, x2, y2, seed = 1, amp = 1.5) {
13
+ const r = paperRandom(seed);
14
+ const j = () => (r() - 0.5) * 2 * amp;
15
+ const mx = (x1 + x2) / 2 + j() * 1.5;
16
+ const my = (y1 + y2) / 2 + j() * 1.5;
17
+ const f = (n) => Math.round(n * 10) / 10;
18
+ return `M${f(x1 + j())} ${f(y1 + j())} Q${f(mx)} ${f(my)} ${f(x2 + j())} ${f(y2 + j())}`;
19
+ }
20
+ const fade = (el, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
21
+ const PAPER_FX = [
22
+ {
23
+ name: 'paper-unfold',
24
+ kind: 'enter',
25
+ description: 'The element unfolds like a folded sheet of paper, with a soft crease shadow (`folds`).',
26
+ defaults: { duration: 900, folds: 2 },
27
+ run: (el, o, ctx) => {
28
+ if (ctx.reduced)
29
+ return fade(el, ctx);
30
+ const n = Math.max(1, Math.min(4, Math.round(Number(o.folds) || 2)));
31
+ const frames = [{ transform: 'perspective(800px) rotateX(-90deg)', opacity: 0, filter: 'brightness(.7)', offset: 0 }];
32
+ for (let i = 1; i <= n; i++)
33
+ frames.push({ transform: `perspective(800px) rotateX(${i % 2 ? 25 : -12}deg) scaleY(${(0.5 + (0.5 * i) / (n + 1)).toFixed(2)})`, opacity: 1, filter: 'brightness(.85)', offset: (i / (n + 1)) * 0.9 });
34
+ frames.push({ transform: 'none', opacity: 1, filter: 'none', offset: 1 });
35
+ const prev = el.style.transformOrigin;
36
+ el.style.transformOrigin = 'top center';
37
+ ctx.onCleanup(() => (el.style.transformOrigin = prev));
38
+ return ctx.animate(el, frames, { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);
39
+ },
40
+ },
41
+ {
42
+ name: 'pencil-sketch',
43
+ kind: 'enter',
44
+ description: 'SVG strokes inside are sketched in with a slightly wobbly pencil, one after another (`duration`, `stagger`).',
45
+ defaults: { duration: 700, stagger: 120 },
46
+ run: (el, o, ctx) => {
47
+ if (ctx.reduced)
48
+ return;
49
+ const strokes = Array.from(el.querySelectorAll('path, line, polyline, rect, circle, ellipse'));
50
+ const runs = strokes.map((p, i) => {
51
+ let len = 200;
52
+ try {
53
+ len = p.getTotalLength?.() || 200;
54
+ }
55
+ catch {
56
+ /* not rendered */
57
+ }
58
+ const prev = p.style.strokeDasharray;
59
+ p.style.strokeDasharray = `${len}`;
60
+ ctx.onCleanup(() => (p.style.strokeDasharray = prev));
61
+ return ctx.animate(p, [{ strokeDashoffset: `${len}`, transform: 'translate(0.6px,-0.4px)' }, { transform: 'translate(-0.5px,0.5px)', offset: 0.5 }, { strokeDashoffset: '0', transform: 'none' }], { duration: o.duration, delay: i * (Number(o.stagger) || 0), easing: 'cubic-bezier(.5,.1,.4,1)', fill: 'backwards' })?.finished.catch(() => undefined);
62
+ });
63
+ return Promise.all(runs).then(() => undefined);
64
+ },
65
+ },
66
+ {
67
+ name: 'watercolor',
68
+ kind: 'enter',
69
+ description: 'The element bleeds in like wet watercolour — blurred and saturated, spreading from the middle — then dries (`duration`).',
70
+ defaults: { duration: 1400 },
71
+ run: (el, o, ctx) => {
72
+ if (ctx.reduced)
73
+ return fade(el, ctx);
74
+ return ctx.animate(el, [
75
+ { opacity: 0, filter: 'blur(10px) saturate(2.2)', clipPath: 'circle(8% at 50% 50%)' },
76
+ { opacity: 0.9, filter: 'blur(4px) saturate(1.8)', clipPath: 'circle(55% at 48% 52%)', offset: 0.5 },
77
+ { opacity: 1, filter: 'blur(0) saturate(1)', clipPath: 'circle(150% at 50% 50%)' },
78
+ ], { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);
79
+ },
80
+ },
81
+ {
82
+ name: 'crumple',
83
+ kind: 'attention',
84
+ description: 'The element scrunches like crumpled paper and springs back flat.',
85
+ defaults: { duration: 700 },
86
+ run: (el, o, ctx) => {
87
+ if (ctx.reduced)
88
+ return;
89
+ return ctx.animate(el, [
90
+ { transform: 'none' },
91
+ { transform: 'scale(.82,.9) rotate(-4deg) skewX(6deg)', filter: 'brightness(.9)', offset: 0.3 },
92
+ { transform: 'scale(.9,.8) rotate(3deg) skewY(-5deg)', offset: 0.5 },
93
+ { transform: 'scale(1.04) rotate(-1deg)', filter: 'none', offset: 0.8 },
94
+ { transform: 'none' },
95
+ ], { duration: o.duration, easing: 'ease-in-out' })?.finished.catch(() => undefined);
96
+ },
97
+ },
98
+ ];
99
+ /** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */
100
+ function registerPaperPack() {
101
+ registry.registerEffects(PAPER_FX);
102
+ }
103
+
104
+ exports.PAPER_FX = PAPER_FX;
105
+ exports.paperRandom = paperRandom;
106
+ exports.registerPaperPack = registerPaperPack;
107
+ exports.roughLine = roughLine;
108
+ //# sourceMappingURL=fx-paper.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-paper.cjs","sources":["../../src/components/fx2/paper.ts"],"sourcesContent":["/**\n * 8.5 — Paper & hand-drawn pack (`motionary/fx/paper`, also `motionary/components/fx-paper`):\n *\n * - `paper-unfold` (enter) — the element unfolds like a folded sheet of paper,\n * top flap first, with a soft crease shadow (`folds`).\n * - `pencil-sketch` (enter) — SVG strokes inside are sketched in with a\n * slightly wobbly pencil, one after another (`duration`, `stagger`).\n * - `watercolor` (enter) — the element bleeds in like wet watercolour:\n * blurred, saturated, spreading from the middle, then dries (`duration`).\n * - `crumple` (attention) — the element scrunches like crumpled paper and\n * springs back flat.\n *\n * Reduced motion: paper-unfold / watercolor fade in, pencil-sketch shows the\n * drawing, crumple does nothing.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** A deterministic PRNG in [0, 1) from a seed (8.5). */\nexport function paperRandom(seed: number): () => number {\n let s = Math.abs(Math.round(seed * 1000)) % 233280 || 11;\n return () => (s = (s * 9301 + 49297) % 233280) / 233280;\n}\n\n/** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */\nexport function roughLine(x1: number, y1: number, x2: number, y2: number, seed = 1, amp = 1.5): string {\n const r = paperRandom(seed);\n const j = () => (r() - 0.5) * 2 * amp;\n const mx = (x1 + x2) / 2 + j() * 1.5;\n const my = (y1 + y2) / 2 + j() * 1.5;\n const f = (n: number) => Math.round(n * 10) / 10;\n return `M${f(x1 + j())} ${f(y1 + j())} Q${f(mx)} ${f(my)} ${f(x2 + j())} ${f(y2 + j())}`;\n}\n\nconst fade = (el: HTMLElement, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n\nexport const PAPER_FX: EffectDefinition[] = [\n {\n name: 'paper-unfold',\n kind: 'enter',\n description: 'The element unfolds like a folded sheet of paper, with a soft crease shadow (`folds`).',\n defaults: { duration: 900, folds: 2 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\n const n = Math.max(1, Math.min(4, Math.round(Number(o.folds) || 2)));\n const frames: Keyframe[] = [{ transform: 'perspective(800px) rotateX(-90deg)', opacity: 0, filter: 'brightness(.7)', offset: 0 }];\n for (let i = 1; i <= n; i++) frames.push({ transform: `perspective(800px) rotateX(${i % 2 ? 25 : -12}deg) scaleY(${(0.5 + (0.5 * i) / (n + 1)).toFixed(2)})`, opacity: 1, filter: 'brightness(.85)', offset: (i / (n + 1)) * 0.9 });\n frames.push({ transform: 'none', opacity: 1, filter: 'none', offset: 1 });\n const prev = el.style.transformOrigin;\n el.style.transformOrigin = 'top center';\n ctx.onCleanup(() => (el.style.transformOrigin = prev));\n return ctx.animate(el, frames, { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);\n },\n },\n {\n name: 'pencil-sketch',\n kind: 'enter',\n description: 'SVG strokes inside are sketched in with a slightly wobbly pencil, one after another (`duration`, `stagger`).',\n defaults: { duration: 700, stagger: 120 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const strokes = Array.from(el.querySelectorAll<SVGGeometryElement>('path, line, polyline, rect, circle, ellipse'));\n const runs = strokes.map((p, i) => {\n let len = 200;\n try {\n len = p.getTotalLength?.() || 200;\n } catch {\n /* not rendered */\n }\n const prev = p.style.strokeDasharray;\n p.style.strokeDasharray = `${len}`;\n ctx.onCleanup(() => (p.style.strokeDasharray = prev));\n return ctx.animate(p, [{ strokeDashoffset: `${len}`, transform: 'translate(0.6px,-0.4px)' }, { transform: 'translate(-0.5px,0.5px)', offset: 0.5 }, { strokeDashoffset: '0', transform: 'none' }], { duration: o.duration, delay: i * (Number(o.stagger) || 0), easing: 'cubic-bezier(.5,.1,.4,1)', fill: 'backwards' })?.finished.catch(() => undefined);\n });\n return Promise.all(runs).then(() => undefined);\n },\n },\n {\n name: 'watercolor',\n kind: 'enter',\n description: 'The element bleeds in like wet watercolour — blurred and saturated, spreading from the middle — then dries (`duration`).',\n defaults: { duration: 1400 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\n return ctx.animate(\n el,\n [\n { opacity: 0, filter: 'blur(10px) saturate(2.2)', clipPath: 'circle(8% at 50% 50%)' },\n { opacity: 0.9, filter: 'blur(4px) saturate(1.8)', clipPath: 'circle(55% at 48% 52%)', offset: 0.5 },\n { opacity: 1, filter: 'blur(0) saturate(1)', clipPath: 'circle(150% at 50% 50%)' },\n ],\n { duration: o.duration, easing: 'ease-out', fill: 'backwards' }\n )?.finished.catch(() => undefined);\n },\n },\n {\n name: 'crumple',\n kind: 'attention',\n description: 'The element scrunches like crumpled paper and springs back flat.',\n defaults: { duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n return ctx.animate(\n el,\n [\n { transform: 'none' },\n { transform: 'scale(.82,.9) rotate(-4deg) skewX(6deg)', filter: 'brightness(.9)', offset: 0.3 },\n { transform: 'scale(.9,.8) rotate(3deg) skewY(-5deg)', offset: 0.5 },\n { transform: 'scale(1.04) rotate(-1deg)', filter: 'none', offset: 0.8 },\n { transform: 'none' },\n ],\n { duration: o.duration, easing: 'ease-in-out' }\n )?.finished.catch(() => undefined);\n },\n },\n];\n\n/** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */\nexport function registerPaperPack(): void {\n registerEffects(PAPER_FX);\n}\n"],"names":["registerEffects"],"mappings":";;;;;AAkBA;AACM,SAAU,WAAW,CAAC,IAAY,EAAA;AACtC,IAAA,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,MAAM,IAAI,EAAE;AACxD,IAAA,OAAO,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,IAAI,MAAM,IAAI,MAAM;AACzD;AAEA;SACgB,SAAS,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAA;AAC3F,IAAA,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC;AAC3B,IAAA,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG;AACrC,IAAA,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG;AACpC,IAAA,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG;AACpC,IAAA,MAAM,CAAC,GAAG,CAAC,CAAS,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE;AAChD,IAAA,OAAO,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA,EAAA,EAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA,CAAA,EAAI,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE;AAC1F;AAEA,MAAM,IAAI,GAAG,CAAC,EAAe,EAAE,GAAkB,KAAK,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAEpJ,MAAM,QAAQ,GAAuB;AAC1C,IAAA;AACE,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,wFAAwF;QACrG,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;QACrC,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;AAAE,gBAAA,OAAO,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC;AACrC,YAAA,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpE,MAAM,MAAM,GAAe,CAAC,EAAE,SAAS,EAAE,oCAAoC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YACjI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AAAE,gBAAA,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAA,2BAAA,EAA8B,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA,YAAA,EAAe,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,CAAA,CAAG,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;YACnO,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AACzE,YAAA,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,eAAe;AACrC,YAAA,EAAE,CAAC,KAAK,CAAC,eAAe,GAAG,YAAY;AACvC,YAAA,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;AACtD,YAAA,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QAClI,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,eAAe;AACrB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,8GAA8G;QAC3H,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;QACzC,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;gBAAE;AACjB,YAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAqB,6CAA6C,CAAC,CAAC;YAClH,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAI;gBAChC,IAAI,GAAG,GAAG,GAAG;AACb,gBAAA,IAAI;oBACF,GAAG,GAAG,CAAC,CAAC,cAAc,IAAI,IAAI,GAAG;gBACnC;AAAE,gBAAA,MAAM;;gBAER;AACA,gBAAA,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,eAAe;gBACpC,CAAC,CAAC,KAAK,CAAC,eAAe,GAAG,CAAA,EAAG,GAAG,EAAE;AAClC,gBAAA,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;AACrD,gBAAA,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAA,CAAE,EAAE,SAAS,EAAE,yBAAyB,EAAE,EAAE,EAAE,SAAS,EAAE,yBAAyB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,0BAA0B,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC3V,YAAA,CAAC,CAAC;AACF,YAAA,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,SAAS,CAAC;QAChD,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,0HAA0H;AACvI,QAAA,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC5B,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;AAAE,gBAAA,OAAO,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC;AACrC,YAAA,OAAO,GAAG,CAAC,OAAO,CAChB,EAAE,EACF;gBACE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,0BAA0B,EAAE,QAAQ,EAAE,uBAAuB,EAAE;AACrF,gBAAA,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,yBAAyB,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,GAAG,EAAE;gBACpG,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,yBAAyB,EAAE;aACnF,EACD,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAChE,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACpC,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,kEAAkE;AAC/E,QAAA,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;QAC3B,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;gBAAE;AACjB,YAAA,OAAO,GAAG,CAAC,OAAO,CAChB,EAAE,EACF;gBACE,EAAE,SAAS,EAAE,MAAM,EAAE;gBACrB,EAAE,SAAS,EAAE,yCAAyC,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE;AAC/F,gBAAA,EAAE,SAAS,EAAE,wCAAwC,EAAE,MAAM,EAAE,GAAG,EAAE;gBACpE,EAAE,SAAS,EAAE,2BAA2B,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE;gBACvE,EAAE,SAAS,EAAE,MAAM,EAAE;aACtB,EACD,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,CAChD,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACpC,CAAC;AACF,KAAA;;AAGH;SACgB,iBAAiB,GAAA;IAC/BA,wBAAe,CAAC,QAAQ,CAAC;AAC3B;;;;;;;"}
@@ -0,0 +1,68 @@
1
+ type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
2
+ type Cleanup = () => void;
3
+
4
+ /**
5
+ * 5.0 — unified plugin-style effect registration. Every effect (built-in or
6
+ * yours) is a plain object registered once and played the same way:
7
+ * `playEffect(el, name)`, `bindEffect(el, name, { trigger })` or
8
+ * `<usa-fx effect="name" trigger="click">`. Effects get a context that
9
+ * already applies reduced motion, motion sensitivity, intensity and the
10
+ * animation budget.
11
+ */
12
+
13
+ declare const EFFECT_KINDS: readonly ["enter", "exit", "attention", "click", "hover", "card", "loop", "page", "background", "text", "cursor", "scroll"];
14
+ type EffectKind = (typeof EFFECT_KINDS)[number];
15
+ interface EffectContext {
16
+ /** Reduced motion applies (OS setting, `minimal` / `static` sensitivity). */
17
+ readonly reduced: boolean;
18
+ readonly sensitivity: MotionSensitivity;
19
+ /** The triggering event (pointer position for click effects), if any. */
20
+ readonly event?: Event;
21
+ /** `el.animate()` with the library's motion rules (may return `null`). */
22
+ animate(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
23
+ /** Register teardown for long-running effects (loops, listeners). */
24
+ onCleanup(fn: Cleanup): void;
25
+ }
26
+ interface EffectDefinition<O extends Record<string, unknown> = Record<string, any>> {
27
+ /** Unique, kebab-case. */
28
+ name: string;
29
+ kind: EffectKind;
30
+ /** One line for docs and the gallery. */
31
+ description?: string;
32
+ /** Option defaults (merged under the caller's options). */
33
+ defaults?: Partial<O>;
34
+ /**
35
+ * Under reduced motion: `'skip'` (do nothing — default for loop, background
36
+ * and cursor effects) or `'run'` (run with `ctx.reduced === true`, the
37
+ * effect degrades itself — default for everything else).
38
+ */
39
+ reduced?: 'skip' | 'run';
40
+ /** Play the effect. Return an Animation / Promise to be awaited, or a cleanup. */
41
+ run(el: HTMLElement, options: O, ctx: EffectContext): void | Cleanup | Animation | null | Promise<unknown>;
42
+ }
43
+
44
+ /**
45
+ * 8.5 — Paper & hand-drawn pack (`motionary/fx/paper`, also `motionary/components/fx-paper`):
46
+ *
47
+ * - `paper-unfold` (enter) — the element unfolds like a folded sheet of paper,
48
+ * top flap first, with a soft crease shadow (`folds`).
49
+ * - `pencil-sketch` (enter) — SVG strokes inside are sketched in with a
50
+ * slightly wobbly pencil, one after another (`duration`, `stagger`).
51
+ * - `watercolor` (enter) — the element bleeds in like wet watercolour:
52
+ * blurred, saturated, spreading from the middle, then dries (`duration`).
53
+ * - `crumple` (attention) — the element scrunches like crumpled paper and
54
+ * springs back flat.
55
+ *
56
+ * Reduced motion: paper-unfold / watercolor fade in, pencil-sketch shows the
57
+ * drawing, crumple does nothing.
58
+ */
59
+
60
+ /** A deterministic PRNG in [0, 1) from a seed (8.5). */
61
+ declare function paperRandom(seed: number): () => number;
62
+ /** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */
63
+ declare function roughLine(x1: number, y1: number, x2: number, y2: number, seed?: number, amp?: number): string;
64
+ declare const PAPER_FX: EffectDefinition[];
65
+ /** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */
66
+ declare function registerPaperPack(): void;
67
+
68
+ export { PAPER_FX, paperRandom, registerPaperPack, roughLine };
@@ -0,0 +1,68 @@
1
+ type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
2
+ type Cleanup = () => void;
3
+
4
+ /**
5
+ * 5.0 — unified plugin-style effect registration. Every effect (built-in or
6
+ * yours) is a plain object registered once and played the same way:
7
+ * `playEffect(el, name)`, `bindEffect(el, name, { trigger })` or
8
+ * `<usa-fx effect="name" trigger="click">`. Effects get a context that
9
+ * already applies reduced motion, motion sensitivity, intensity and the
10
+ * animation budget.
11
+ */
12
+
13
+ declare const EFFECT_KINDS: readonly ["enter", "exit", "attention", "click", "hover", "card", "loop", "page", "background", "text", "cursor", "scroll"];
14
+ type EffectKind = (typeof EFFECT_KINDS)[number];
15
+ interface EffectContext {
16
+ /** Reduced motion applies (OS setting, `minimal` / `static` sensitivity). */
17
+ readonly reduced: boolean;
18
+ readonly sensitivity: MotionSensitivity;
19
+ /** The triggering event (pointer position for click effects), if any. */
20
+ readonly event?: Event;
21
+ /** `el.animate()` with the library's motion rules (may return `null`). */
22
+ animate(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
23
+ /** Register teardown for long-running effects (loops, listeners). */
24
+ onCleanup(fn: Cleanup): void;
25
+ }
26
+ interface EffectDefinition<O extends Record<string, unknown> = Record<string, any>> {
27
+ /** Unique, kebab-case. */
28
+ name: string;
29
+ kind: EffectKind;
30
+ /** One line for docs and the gallery. */
31
+ description?: string;
32
+ /** Option defaults (merged under the caller's options). */
33
+ defaults?: Partial<O>;
34
+ /**
35
+ * Under reduced motion: `'skip'` (do nothing — default for loop, background
36
+ * and cursor effects) or `'run'` (run with `ctx.reduced === true`, the
37
+ * effect degrades itself — default for everything else).
38
+ */
39
+ reduced?: 'skip' | 'run';
40
+ /** Play the effect. Return an Animation / Promise to be awaited, or a cleanup. */
41
+ run(el: HTMLElement, options: O, ctx: EffectContext): void | Cleanup | Animation | null | Promise<unknown>;
42
+ }
43
+
44
+ /**
45
+ * 8.5 — Paper & hand-drawn pack (`motionary/fx/paper`, also `motionary/components/fx-paper`):
46
+ *
47
+ * - `paper-unfold` (enter) — the element unfolds like a folded sheet of paper,
48
+ * top flap first, with a soft crease shadow (`folds`).
49
+ * - `pencil-sketch` (enter) — SVG strokes inside are sketched in with a
50
+ * slightly wobbly pencil, one after another (`duration`, `stagger`).
51
+ * - `watercolor` (enter) — the element bleeds in like wet watercolour:
52
+ * blurred, saturated, spreading from the middle, then dries (`duration`).
53
+ * - `crumple` (attention) — the element scrunches like crumpled paper and
54
+ * springs back flat.
55
+ *
56
+ * Reduced motion: paper-unfold / watercolor fade in, pencil-sketch shows the
57
+ * drawing, crumple does nothing.
58
+ */
59
+
60
+ /** A deterministic PRNG in [0, 1) from a seed (8.5). */
61
+ declare function paperRandom(seed: number): () => number;
62
+ /** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */
63
+ declare function roughLine(x1: number, y1: number, x2: number, y2: number, seed?: number, amp?: number): string;
64
+ declare const PAPER_FX: EffectDefinition[];
65
+ /** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */
66
+ declare function registerPaperPack(): void;
67
+
68
+ export { PAPER_FX, paperRandom, registerPaperPack, roughLine };
@@ -0,0 +1,103 @@
1
+ import { registerEffects } from '../chunks/registry-CnO7ZVPK.js';
2
+ import '../chunks/base-CLuqlLfG.js';
3
+
4
+ /** A deterministic PRNG in [0, 1) from a seed (8.5). */
5
+ function paperRandom(seed) {
6
+ let s = Math.abs(Math.round(seed * 1000)) % 233280 || 11;
7
+ return () => (s = (s * 9301 + 49297) % 233280) / 233280;
8
+ }
9
+ /** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */
10
+ function roughLine(x1, y1, x2, y2, seed = 1, amp = 1.5) {
11
+ const r = paperRandom(seed);
12
+ const j = () => (r() - 0.5) * 2 * amp;
13
+ const mx = (x1 + x2) / 2 + j() * 1.5;
14
+ const my = (y1 + y2) / 2 + j() * 1.5;
15
+ const f = (n) => Math.round(n * 10) / 10;
16
+ return `M${f(x1 + j())} ${f(y1 + j())} Q${f(mx)} ${f(my)} ${f(x2 + j())} ${f(y2 + j())}`;
17
+ }
18
+ const fade = (el, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
19
+ const PAPER_FX = [
20
+ {
21
+ name: 'paper-unfold',
22
+ kind: 'enter',
23
+ description: 'The element unfolds like a folded sheet of paper, with a soft crease shadow (`folds`).',
24
+ defaults: { duration: 900, folds: 2 },
25
+ run: (el, o, ctx) => {
26
+ if (ctx.reduced)
27
+ return fade(el, ctx);
28
+ const n = Math.max(1, Math.min(4, Math.round(Number(o.folds) || 2)));
29
+ const frames = [{ transform: 'perspective(800px) rotateX(-90deg)', opacity: 0, filter: 'brightness(.7)', offset: 0 }];
30
+ for (let i = 1; i <= n; i++)
31
+ frames.push({ transform: `perspective(800px) rotateX(${i % 2 ? 25 : -12}deg) scaleY(${(0.5 + (0.5 * i) / (n + 1)).toFixed(2)})`, opacity: 1, filter: 'brightness(.85)', offset: (i / (n + 1)) * 0.9 });
32
+ frames.push({ transform: 'none', opacity: 1, filter: 'none', offset: 1 });
33
+ const prev = el.style.transformOrigin;
34
+ el.style.transformOrigin = 'top center';
35
+ ctx.onCleanup(() => (el.style.transformOrigin = prev));
36
+ return ctx.animate(el, frames, { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);
37
+ },
38
+ },
39
+ {
40
+ name: 'pencil-sketch',
41
+ kind: 'enter',
42
+ description: 'SVG strokes inside are sketched in with a slightly wobbly pencil, one after another (`duration`, `stagger`).',
43
+ defaults: { duration: 700, stagger: 120 },
44
+ run: (el, o, ctx) => {
45
+ if (ctx.reduced)
46
+ return;
47
+ const strokes = Array.from(el.querySelectorAll('path, line, polyline, rect, circle, ellipse'));
48
+ const runs = strokes.map((p, i) => {
49
+ let len = 200;
50
+ try {
51
+ len = p.getTotalLength?.() || 200;
52
+ }
53
+ catch {
54
+ /* not rendered */
55
+ }
56
+ const prev = p.style.strokeDasharray;
57
+ p.style.strokeDasharray = `${len}`;
58
+ ctx.onCleanup(() => (p.style.strokeDasharray = prev));
59
+ return ctx.animate(p, [{ strokeDashoffset: `${len}`, transform: 'translate(0.6px,-0.4px)' }, { transform: 'translate(-0.5px,0.5px)', offset: 0.5 }, { strokeDashoffset: '0', transform: 'none' }], { duration: o.duration, delay: i * (Number(o.stagger) || 0), easing: 'cubic-bezier(.5,.1,.4,1)', fill: 'backwards' })?.finished.catch(() => undefined);
60
+ });
61
+ return Promise.all(runs).then(() => undefined);
62
+ },
63
+ },
64
+ {
65
+ name: 'watercolor',
66
+ kind: 'enter',
67
+ description: 'The element bleeds in like wet watercolour — blurred and saturated, spreading from the middle — then dries (`duration`).',
68
+ defaults: { duration: 1400 },
69
+ run: (el, o, ctx) => {
70
+ if (ctx.reduced)
71
+ return fade(el, ctx);
72
+ return ctx.animate(el, [
73
+ { opacity: 0, filter: 'blur(10px) saturate(2.2)', clipPath: 'circle(8% at 50% 50%)' },
74
+ { opacity: 0.9, filter: 'blur(4px) saturate(1.8)', clipPath: 'circle(55% at 48% 52%)', offset: 0.5 },
75
+ { opacity: 1, filter: 'blur(0) saturate(1)', clipPath: 'circle(150% at 50% 50%)' },
76
+ ], { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);
77
+ },
78
+ },
79
+ {
80
+ name: 'crumple',
81
+ kind: 'attention',
82
+ description: 'The element scrunches like crumpled paper and springs back flat.',
83
+ defaults: { duration: 700 },
84
+ run: (el, o, ctx) => {
85
+ if (ctx.reduced)
86
+ return;
87
+ return ctx.animate(el, [
88
+ { transform: 'none' },
89
+ { transform: 'scale(.82,.9) rotate(-4deg) skewX(6deg)', filter: 'brightness(.9)', offset: 0.3 },
90
+ { transform: 'scale(.9,.8) rotate(3deg) skewY(-5deg)', offset: 0.5 },
91
+ { transform: 'scale(1.04) rotate(-1deg)', filter: 'none', offset: 0.8 },
92
+ { transform: 'none' },
93
+ ], { duration: o.duration, easing: 'ease-in-out' })?.finished.catch(() => undefined);
94
+ },
95
+ },
96
+ ];
97
+ /** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */
98
+ function registerPaperPack() {
99
+ registerEffects(PAPER_FX);
100
+ }
101
+
102
+ export { PAPER_FX, paperRandom, registerPaperPack, roughLine };
103
+ //# sourceMappingURL=fx-paper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-paper.js","sources":["../../src/components/fx2/paper.ts"],"sourcesContent":["/**\n * 8.5 — Paper & hand-drawn pack (`motionary/fx/paper`, also `motionary/components/fx-paper`):\n *\n * - `paper-unfold` (enter) — the element unfolds like a folded sheet of paper,\n * top flap first, with a soft crease shadow (`folds`).\n * - `pencil-sketch` (enter) — SVG strokes inside are sketched in with a\n * slightly wobbly pencil, one after another (`duration`, `stagger`).\n * - `watercolor` (enter) — the element bleeds in like wet watercolour:\n * blurred, saturated, spreading from the middle, then dries (`duration`).\n * - `crumple` (attention) — the element scrunches like crumpled paper and\n * springs back flat.\n *\n * Reduced motion: paper-unfold / watercolor fade in, pencil-sketch shows the\n * drawing, crumple does nothing.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** A deterministic PRNG in [0, 1) from a seed (8.5). */\nexport function paperRandom(seed: number): () => number {\n let s = Math.abs(Math.round(seed * 1000)) % 233280 || 11;\n return () => (s = (s * 9301 + 49297) % 233280) / 233280;\n}\n\n/** A hand-drawn SVG path from (x1,y1) to (x2,y2): a slightly bowed, wobbly line (8.5). */\nexport function roughLine(x1: number, y1: number, x2: number, y2: number, seed = 1, amp = 1.5): string {\n const r = paperRandom(seed);\n const j = () => (r() - 0.5) * 2 * amp;\n const mx = (x1 + x2) / 2 + j() * 1.5;\n const my = (y1 + y2) / 2 + j() * 1.5;\n const f = (n: number) => Math.round(n * 10) / 10;\n return `M${f(x1 + j())} ${f(y1 + j())} Q${f(mx)} ${f(my)} ${f(x2 + j())} ${f(y2 + j())}`;\n}\n\nconst fade = (el: HTMLElement, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n\nexport const PAPER_FX: EffectDefinition[] = [\n {\n name: 'paper-unfold',\n kind: 'enter',\n description: 'The element unfolds like a folded sheet of paper, with a soft crease shadow (`folds`).',\n defaults: { duration: 900, folds: 2 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\n const n = Math.max(1, Math.min(4, Math.round(Number(o.folds) || 2)));\n const frames: Keyframe[] = [{ transform: 'perspective(800px) rotateX(-90deg)', opacity: 0, filter: 'brightness(.7)', offset: 0 }];\n for (let i = 1; i <= n; i++) frames.push({ transform: `perspective(800px) rotateX(${i % 2 ? 25 : -12}deg) scaleY(${(0.5 + (0.5 * i) / (n + 1)).toFixed(2)})`, opacity: 1, filter: 'brightness(.85)', offset: (i / (n + 1)) * 0.9 });\n frames.push({ transform: 'none', opacity: 1, filter: 'none', offset: 1 });\n const prev = el.style.transformOrigin;\n el.style.transformOrigin = 'top center';\n ctx.onCleanup(() => (el.style.transformOrigin = prev));\n return ctx.animate(el, frames, { duration: o.duration, easing: 'ease-out', fill: 'backwards' })?.finished.catch(() => undefined);\n },\n },\n {\n name: 'pencil-sketch',\n kind: 'enter',\n description: 'SVG strokes inside are sketched in with a slightly wobbly pencil, one after another (`duration`, `stagger`).',\n defaults: { duration: 700, stagger: 120 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const strokes = Array.from(el.querySelectorAll<SVGGeometryElement>('path, line, polyline, rect, circle, ellipse'));\n const runs = strokes.map((p, i) => {\n let len = 200;\n try {\n len = p.getTotalLength?.() || 200;\n } catch {\n /* not rendered */\n }\n const prev = p.style.strokeDasharray;\n p.style.strokeDasharray = `${len}`;\n ctx.onCleanup(() => (p.style.strokeDasharray = prev));\n return ctx.animate(p, [{ strokeDashoffset: `${len}`, transform: 'translate(0.6px,-0.4px)' }, { transform: 'translate(-0.5px,0.5px)', offset: 0.5 }, { strokeDashoffset: '0', transform: 'none' }], { duration: o.duration, delay: i * (Number(o.stagger) || 0), easing: 'cubic-bezier(.5,.1,.4,1)', fill: 'backwards' })?.finished.catch(() => undefined);\n });\n return Promise.all(runs).then(() => undefined);\n },\n },\n {\n name: 'watercolor',\n kind: 'enter',\n description: 'The element bleeds in like wet watercolour — blurred and saturated, spreading from the middle — then dries (`duration`).',\n defaults: { duration: 1400 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\n return ctx.animate(\n el,\n [\n { opacity: 0, filter: 'blur(10px) saturate(2.2)', clipPath: 'circle(8% at 50% 50%)' },\n { opacity: 0.9, filter: 'blur(4px) saturate(1.8)', clipPath: 'circle(55% at 48% 52%)', offset: 0.5 },\n { opacity: 1, filter: 'blur(0) saturate(1)', clipPath: 'circle(150% at 50% 50%)' },\n ],\n { duration: o.duration, easing: 'ease-out', fill: 'backwards' }\n )?.finished.catch(() => undefined);\n },\n },\n {\n name: 'crumple',\n kind: 'attention',\n description: 'The element scrunches like crumpled paper and springs back flat.',\n defaults: { duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n return ctx.animate(\n el,\n [\n { transform: 'none' },\n { transform: 'scale(.82,.9) rotate(-4deg) skewX(6deg)', filter: 'brightness(.9)', offset: 0.3 },\n { transform: 'scale(.9,.8) rotate(3deg) skewY(-5deg)', offset: 0.5 },\n { transform: 'scale(1.04) rotate(-1deg)', filter: 'none', offset: 0.8 },\n { transform: 'none' },\n ],\n { duration: o.duration, easing: 'ease-in-out' }\n )?.finished.catch(() => undefined);\n },\n },\n];\n\n/** Register paper-unfold, pencil-sketch, watercolor and crumple (8.5). */\nexport function registerPaperPack(): void {\n registerEffects(PAPER_FX);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ var registry = require('../chunks/registry-BVklOepd.cjs');
4
+ require('../chunks/base-DoRUZBy-.cjs');
5
+
6
+ /** The built-in surface themes of the 8.6 theme system. */
7
+ const SURFACE_THEMES = ['light', 'dark', 'neon', 'glass', 'neu'];
8
+ /** Set `data-usa-surface` on `target` (default `<html>`) and return the theme actually applied (unknown → `light`) (8.6). */
9
+ function applySurfaceTheme(name, target = typeof document !== 'undefined' ? document.documentElement : null) {
10
+ const t = (SURFACE_THEMES.includes(name) ? name : 'light');
11
+ target?.setAttribute('data-usa-surface', t);
12
+ return t;
13
+ }
14
+ const glow = (c, k) => `0 0 ${4 * k}px ${c}, 0 0 ${12 * k}px ${c}`;
15
+ const SURFACE_FX = [
16
+ {
17
+ name: 'neon-ignite',
18
+ kind: 'enter',
19
+ description: 'The element powers on like a neon tube — stuttering flickers, then a steady glow (`color`).',
20
+ defaults: { color: '#f0abfc', duration: 1100 },
21
+ run: (el, o, ctx) => {
22
+ if (ctx.reduced)
23
+ return;
24
+ const on = { opacity: 1, textShadow: glow(o.color, 1), filter: 'brightness(1.15)' };
25
+ const off = { opacity: 0.15, textShadow: 'none', filter: 'brightness(.6)' };
26
+ return ctx.animate(el, [{ ...off, offset: 0 }, { ...on, offset: 0.1 }, { ...off, offset: 0.14 }, { ...on, offset: 0.3 }, { ...off, offset: 0.34 }, { ...off, offset: 0.5 }, { ...on, offset: 0.56 }, { ...on, textShadow: glow(o.color, 1.6), offset: 0.8 }, { opacity: 1, textShadow: glow(o.color, 1), filter: 'none', offset: 1 }], { duration: o.duration, fill: 'backwards' })?.finished.catch(() => undefined);
27
+ },
28
+ },
29
+ {
30
+ name: 'neon-pulse',
31
+ kind: 'loop',
32
+ description: 'A slow breathing neon glow until the cleanup runs (`color`).',
33
+ defaults: { color: '#22d3ee', duration: 2200 },
34
+ run: (el, o, ctx) => {
35
+ if (ctx.reduced)
36
+ return;
37
+ const a = ctx.animate(el, [{ boxShadow: glow(o.color, 0.6) }, { boxShadow: glow(o.color, 1.6) }, { boxShadow: glow(o.color, 0.6) }], { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });
38
+ return () => a?.cancel();
39
+ },
40
+ },
41
+ {
42
+ name: 'glass-frost',
43
+ kind: 'enter',
44
+ description: 'Frosted glass condenses: blur and transparency settle into a crisp glass panel, with a shine passing over it.',
45
+ defaults: { duration: 1000 },
46
+ run: (el, o, ctx) => {
47
+ if (ctx.reduced)
48
+ return;
49
+ const runs = [];
50
+ runs.push(ctx.animate(el, [{ opacity: 0, filter: 'blur(12px)', transform: 'scale(.96)' }, { opacity: 1, filter: 'blur(0)', transform: 'none' }], { duration: o.duration, easing: 'cubic-bezier(.2,.8,.2,1)', fill: 'backwards' })?.finished.catch(() => undefined));
51
+ if (getComputedStyle(el).position === 'static') {
52
+ const prev = el.style.position;
53
+ el.style.position = 'relative';
54
+ ctx.onCleanup(() => (el.style.position = prev));
55
+ }
56
+ const s = document.createElement('span');
57
+ s.setAttribute('aria-hidden', 'true');
58
+ Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', borderRadius: 'inherit', background: 'linear-gradient(110deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', backgroundSize: '250% 100%' });
59
+ el.appendChild(s);
60
+ ctx.onCleanup(() => s.remove());
61
+ const sh = ctx.animate(s, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-60% 0' }], { duration: o.duration * 0.9, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' });
62
+ runs.push(sh ? sh.finished.then(() => s.remove(), () => s.remove()) : (s.remove(), undefined));
63
+ return Promise.all(runs).then(() => undefined);
64
+ },
65
+ },
66
+ {
67
+ name: 'neu-press',
68
+ kind: 'attention',
69
+ description: 'A soft neumorphic press: the raised shadow flips to an inset one and pops back.',
70
+ defaults: { duration: 450 },
71
+ run: (el, o, ctx) => {
72
+ if (ctx.reduced)
73
+ return;
74
+ const up = '6px 6px 12px rgba(163,177,198,.7), -6px -6px 12px rgba(255,255,255,.9)';
75
+ const down = 'inset 4px 4px 8px rgba(163,177,198,.8), inset -4px -4px 8px rgba(255,255,255,.9)';
76
+ return ctx.animate(el, [{ boxShadow: up, transform: 'none' }, { boxShadow: down, transform: 'scale(.97)', offset: 0.4 }, { boxShadow: up, transform: 'none' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);
77
+ },
78
+ },
79
+ ];
80
+ /** Register neon-ignite, neon-pulse, glass-frost and neu-press (8.6). */
81
+ function registerSurfacePack() {
82
+ registry.registerEffects(SURFACE_FX);
83
+ }
84
+
85
+ exports.SURFACE_FX = SURFACE_FX;
86
+ exports.SURFACE_THEMES = SURFACE_THEMES;
87
+ exports.applySurfaceTheme = applySurfaceTheme;
88
+ exports.registerSurfacePack = registerSurfacePack;
89
+ //# sourceMappingURL=fx-surface.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fx-surface.cjs","sources":["../../src/components/fx2/themefx.ts"],"sourcesContent":["/**\n * 8.6 — Surface theme pack (`motionary/fx/surface`, also `motionary/components/fx-surface`):\n *\n * - `neon-ignite` (enter) — the element powers on like a neon tube: a few\n * stuttering flickers, then a steady glow (`color`).\n * - `neon-pulse` (loop) — a slow breathing neon glow; the cleanup stops it\n * (`color`).\n * - `glass-frost` (enter) — frosted glass condenses: blur and transparency\n * settle into a crisp glass panel, with a shine passing over it.\n * - `neu-press` (attention) — a soft neumorphic press: the raised shadow\n * flips to an inset one and pops back.\n *\n * Reduced motion: neon-ignite / glass-frost just show, neon-pulse is\n * skipped, neu-press does nothing.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** The built-in surface themes of the 8.6 theme system. */\nexport const SURFACE_THEMES = ['light', 'dark', 'neon', 'glass', 'neu'] as const;\nexport type SurfaceTheme = (typeof SURFACE_THEMES)[number];\n\n/** Set `data-usa-surface` on `target` (default `<html>`) and return the theme actually applied (unknown → `light`) (8.6). */\nexport function applySurfaceTheme(name: string, target: Element | null = typeof document !== 'undefined' ? document.documentElement : null): SurfaceTheme {\n const t = ((SURFACE_THEMES as readonly string[]).includes(name) ? name : 'light') as SurfaceTheme;\n target?.setAttribute('data-usa-surface', t);\n return t;\n}\n\nconst glow = (c: string, k: number) => `0 0 ${4 * k}px ${c}, 0 0 ${12 * k}px ${c}`;\n\nexport const SURFACE_FX: EffectDefinition[] = [\n {\n name: 'neon-ignite',\n kind: 'enter',\n description: 'The element powers on like a neon tube — stuttering flickers, then a steady glow (`color`).',\n defaults: { color: '#f0abfc', duration: 1100 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const on = { opacity: 1, textShadow: glow(o.color, 1), filter: 'brightness(1.15)' };\n const off = { opacity: 0.15, textShadow: 'none', filter: 'brightness(.6)' };\n return ctx.animate(el, [{ ...off, offset: 0 }, { ...on, offset: 0.1 }, { ...off, offset: 0.14 }, { ...on, offset: 0.3 }, { ...off, offset: 0.34 }, { ...off, offset: 0.5 }, { ...on, offset: 0.56 }, { ...on, textShadow: glow(o.color, 1.6), offset: 0.8 }, { opacity: 1, textShadow: glow(o.color, 1), filter: 'none', offset: 1 }], { duration: o.duration, fill: 'backwards' })?.finished.catch(() => undefined);\n },\n },\n {\n name: 'neon-pulse',\n kind: 'loop',\n description: 'A slow breathing neon glow until the cleanup runs (`color`).',\n defaults: { color: '#22d3ee', duration: 2200 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const a = ctx.animate(el, [{ boxShadow: glow(o.color, 0.6) }, { boxShadow: glow(o.color, 1.6) }, { boxShadow: glow(o.color, 0.6) }], { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });\n return () => a?.cancel();\n },\n },\n {\n name: 'glass-frost',\n kind: 'enter',\n description: 'Frosted glass condenses: blur and transparency settle into a crisp glass panel, with a shine passing over it.',\n defaults: { duration: 1000 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const runs: (Promise<unknown> | undefined)[] = [];\n runs.push(ctx.animate(el, [{ opacity: 0, filter: 'blur(12px)', transform: 'scale(.96)' }, { opacity: 1, filter: 'blur(0)', transform: 'none' }], { duration: o.duration, easing: 'cubic-bezier(.2,.8,.2,1)', fill: 'backwards' })?.finished.catch(() => undefined));\n if (getComputedStyle(el).position === 'static') {\n const prev = el.style.position;\n el.style.position = 'relative';\n ctx.onCleanup(() => (el.style.position = prev));\n }\n const s = document.createElement('span');\n s.setAttribute('aria-hidden', 'true');\n Object.assign(s.style, { position: 'absolute', inset: '0', pointerEvents: 'none', borderRadius: 'inherit', background: 'linear-gradient(110deg,transparent 30%,rgba(255,255,255,.55) 50%,transparent 70%)', backgroundSize: '250% 100%' });\n el.appendChild(s);\n ctx.onCleanup(() => s.remove());\n const sh = ctx.animate(s, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-60% 0' }], { duration: o.duration * 0.9, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' });\n runs.push(sh ? sh.finished.then(() => s.remove(), () => s.remove()) : (s.remove(), undefined));\n return Promise.all(runs).then(() => undefined);\n },\n },\n {\n name: 'neu-press',\n kind: 'attention',\n description: 'A soft neumorphic press: the raised shadow flips to an inset one and pops back.',\n defaults: { duration: 450 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const up = '6px 6px 12px rgba(163,177,198,.7), -6px -6px 12px rgba(255,255,255,.9)';\n const down = 'inset 4px 4px 8px rgba(163,177,198,.8), inset -4px -4px 8px rgba(255,255,255,.9)';\n return ctx.animate(el, [{ boxShadow: up, transform: 'none' }, { boxShadow: down, transform: 'scale(.97)', offset: 0.4 }, { boxShadow: up, transform: 'none' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);\n },\n },\n];\n\n/** Register neon-ignite, neon-pulse, glass-frost and neu-press (8.6). */\nexport function registerSurfacePack(): void {\n registerEffects(SURFACE_FX);\n}\n"],"names":["registerEffects"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ type MotionSensitivity = 'full' | 'gentle' | 'minimal' | 'static';
2
+ type Cleanup = () => void;
3
+
4
+ /**
5
+ * 5.0 — unified plugin-style effect registration. Every effect (built-in or
6
+ * yours) is a plain object registered once and played the same way:
7
+ * `playEffect(el, name)`, `bindEffect(el, name, { trigger })` or
8
+ * `<usa-fx effect="name" trigger="click">`. Effects get a context that
9
+ * already applies reduced motion, motion sensitivity, intensity and the
10
+ * animation budget.
11
+ */
12
+
13
+ declare const EFFECT_KINDS: readonly ["enter", "exit", "attention", "click", "hover", "card", "loop", "page", "background", "text", "cursor", "scroll"];
14
+ type EffectKind = (typeof EFFECT_KINDS)[number];
15
+ interface EffectContext {
16
+ /** Reduced motion applies (OS setting, `minimal` / `static` sensitivity). */
17
+ readonly reduced: boolean;
18
+ readonly sensitivity: MotionSensitivity;
19
+ /** The triggering event (pointer position for click effects), if any. */
20
+ readonly event?: Event;
21
+ /** `el.animate()` with the library's motion rules (may return `null`). */
22
+ animate(el: Element, keyframes: Keyframe[], options: KeyframeAnimationOptions): Animation | null;
23
+ /** Register teardown for long-running effects (loops, listeners). */
24
+ onCleanup(fn: Cleanup): void;
25
+ }
26
+ interface EffectDefinition<O extends Record<string, unknown> = Record<string, any>> {
27
+ /** Unique, kebab-case. */
28
+ name: string;
29
+ kind: EffectKind;
30
+ /** One line for docs and the gallery. */
31
+ description?: string;
32
+ /** Option defaults (merged under the caller's options). */
33
+ defaults?: Partial<O>;
34
+ /**
35
+ * Under reduced motion: `'skip'` (do nothing — default for loop, background
36
+ * and cursor effects) or `'run'` (run with `ctx.reduced === true`, the
37
+ * effect degrades itself — default for everything else).
38
+ */
39
+ reduced?: 'skip' | 'run';
40
+ /** Play the effect. Return an Animation / Promise to be awaited, or a cleanup. */
41
+ run(el: HTMLElement, options: O, ctx: EffectContext): void | Cleanup | Animation | null | Promise<unknown>;
42
+ }
43
+
44
+ /**
45
+ * 8.6 — Surface theme pack (`motionary/fx/surface`, also `motionary/components/fx-surface`):
46
+ *
47
+ * - `neon-ignite` (enter) — the element powers on like a neon tube: a few
48
+ * stuttering flickers, then a steady glow (`color`).
49
+ * - `neon-pulse` (loop) — a slow breathing neon glow; the cleanup stops it
50
+ * (`color`).
51
+ * - `glass-frost` (enter) — frosted glass condenses: blur and transparency
52
+ * settle into a crisp glass panel, with a shine passing over it.
53
+ * - `neu-press` (attention) — a soft neumorphic press: the raised shadow
54
+ * flips to an inset one and pops back.
55
+ *
56
+ * Reduced motion: neon-ignite / glass-frost just show, neon-pulse is
57
+ * skipped, neu-press does nothing.
58
+ */
59
+
60
+ /** The built-in surface themes of the 8.6 theme system. */
61
+ declare const SURFACE_THEMES: readonly ["light", "dark", "neon", "glass", "neu"];
62
+ type SurfaceTheme = (typeof SURFACE_THEMES)[number];
63
+ /** Set `data-usa-surface` on `target` (default `<html>`) and return the theme actually applied (unknown → `light`) (8.6). */
64
+ declare function applySurfaceTheme(name: string, target?: Element | null): SurfaceTheme;
65
+ declare const SURFACE_FX: EffectDefinition[];
66
+ /** Register neon-ignite, neon-pulse, glass-frost and neu-press (8.6). */
67
+ declare function registerSurfacePack(): void;
68
+
69
+ export { SURFACE_FX, SURFACE_THEMES, applySurfaceTheme, registerSurfacePack };
70
+ export type { SurfaceTheme };