use-scroll-animate 7.7.0 → 7.8.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 +13 -0
- package/dist/components/fx-ai.cjs +130 -0
- package/dist/components/fx-ai.cjs.map +1 -0
- package/dist/components/fx-ai.d.cts +66 -0
- package/dist/components/fx-ai.d.ts +66 -0
- package/dist/components/fx-ai.js +126 -0
- package/dist/components/fx-ai.js.map +1 -0
- package/dist/components/fx2.cjs +6 -0
- package/dist/components/fx2.cjs.map +1 -1
- package/dist/components/fx2.d.cts +23 -1
- package/dist/components/fx2.d.ts +23 -1
- package/dist/components/fx2.js +5 -1
- package/dist/components/fx2.js.map +1 -1
- package/dist/components/widgets.cjs +388 -118
- package/dist/components/widgets.cjs.map +1 -1
- package/dist/components/widgets.d.cts +57 -2
- package/dist/components/widgets.d.ts +57 -2
- package/dist/components/widgets.js +384 -119
- package/dist/components/widgets.js.map +1 -1
- package/dist/widgets.umd.js +1 -1
- package/dist/widgets.umd.js.map +1 -1
- package/docs/ROADMAP.md +1 -1
- package/docs/components.md +23 -0
- package/package.json +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [7.8.0] - 2026-10-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **3 new components (7.8)** in `motionary/components/widgets` (also in `dist/widgets.umd.js`):
|
|
14
|
+
- `<usa-chat-composer>` — AI chat input: the textarea grows with its text (up to `rows`, default 6), Enter sends / Shift+Enter new line, the send button pops when there is text and morphs into Stop while `busy`, when a conic "thinking" glow runs round the composer. `usa:send` { text } (cancelable), `usa:stop`; `placeholder`, `label`, `value`, `busy`, `send()`, `clear()`.
|
|
15
|
+
- `<usa-suggestion-chips>` — follow-up prompt chips from `items="a|b|c"` (or child elements): slide in one after another, picking pulses the chip and emits `usa:pick` { text, index }; `dismiss` fades the others; `setItems()` / `items`; arrow keys. `parseChips()`.
|
|
16
|
+
- `<usa-voice-button>` — push-to-talk mic: toggles `listening` (`usa:start` / `usa:stop`), a halo breathes and `bars` (3–9) wave; set `level` (0–1) from an analyser / speech API and both follow it. `toggle()`; `waveBars()`.
|
|
17
|
+
- **AI UI motion — `motionary/fx/ai`** (= `motionary/components/fx-ai`, `registerAiPack()`, also in `registerEffectPacks()`): `stream-text` (enter), `thinking-glow` (loop), `voice-wave` (attention), `gen-skeleton` (enter). `splitWords()`.
|
|
18
|
+
- Showcase: 5 new gallery cards with copyable code, live demos and live Store thumbnails; Animation Store 326 → 331 items.
|
|
19
|
+
|
|
20
|
+
### Accessibility
|
|
21
|
+
- Composer: labelled textarea, the button's `aria-label` switches Send ↔ Stop generating. Chips: labelled list of real buttons, arrow-key navigation, dismissed chips are disabled. Voice button: a real `<button aria-pressed>`. `stream-text` restores the original text nodes when it finishes (screen readers read the full text). Reduced motion: no glow, pop, slide, halo or wave; `stream-text` shows the text at once, `thinking-glow` is skipped, `voice-wave` does nothing, `gen-skeleton` fades in.
|
|
22
|
+
|
|
10
23
|
## [7.7.0] - 2026-10-08
|
|
11
24
|
|
|
12
25
|
### Added
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var registry = require('../chunks/registry-DehBVRDV.cjs');
|
|
4
|
+
require('../chunks/base-BaQV-2ha.cjs');
|
|
5
|
+
|
|
6
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
7
|
+
function splitWords(text) {
|
|
8
|
+
return text.match(/\S+\s*|\s+/g) || [];
|
|
9
|
+
}
|
|
10
|
+
const fade = (el, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
11
|
+
function textNodes(el) {
|
|
12
|
+
const out = [];
|
|
13
|
+
const walk = (n) => n.childNodes.forEach((c) => (c.nodeType === 3 ? (c.textContent || '').trim() && out.push(c) : c.nodeType === 1 && walk(c)));
|
|
14
|
+
walk(el);
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
const AI_FX = [
|
|
18
|
+
{
|
|
19
|
+
name: 'stream-text',
|
|
20
|
+
kind: 'enter',
|
|
21
|
+
description: 'The text appears word by word like a streamed LLM reply, with a blinking caret (`speed` ms per word).',
|
|
22
|
+
defaults: { speed: 45 },
|
|
23
|
+
run: (el, o, ctx) => {
|
|
24
|
+
if (ctx.reduced)
|
|
25
|
+
return;
|
|
26
|
+
const speed = Math.max(5, Number(o.speed) || 45);
|
|
27
|
+
const spans = [];
|
|
28
|
+
const restores = [];
|
|
29
|
+
for (const t of textNodes(el)) {
|
|
30
|
+
const wrap = document.createElement('span');
|
|
31
|
+
wrap.setAttribute('data-usa-stream', '');
|
|
32
|
+
for (const w of splitWords(t.textContent || '')) {
|
|
33
|
+
const s = document.createElement('span');
|
|
34
|
+
s.textContent = w;
|
|
35
|
+
s.style.opacity = '0';
|
|
36
|
+
wrap.appendChild(s);
|
|
37
|
+
spans.push(s);
|
|
38
|
+
}
|
|
39
|
+
t.parentNode.replaceChild(wrap, t);
|
|
40
|
+
restores.push(() => wrap.isConnected && wrap.replaceWith(t));
|
|
41
|
+
}
|
|
42
|
+
const caret = document.createElement('span');
|
|
43
|
+
caret.setAttribute('aria-hidden', 'true');
|
|
44
|
+
caret.textContent = '▍';
|
|
45
|
+
Object.assign(caret.style, { opacity: '.7', marginLeft: '1px' });
|
|
46
|
+
el.appendChild(caret);
|
|
47
|
+
const blink = ctx.animate(caret, [{ opacity: 0.8 }, { opacity: 0 }], { duration: 500, iterations: Infinity, direction: 'alternate' });
|
|
48
|
+
let done = false;
|
|
49
|
+
const finish = () => {
|
|
50
|
+
if (done)
|
|
51
|
+
return;
|
|
52
|
+
done = true;
|
|
53
|
+
blink?.cancel();
|
|
54
|
+
caret.remove();
|
|
55
|
+
restores.forEach((r) => r());
|
|
56
|
+
};
|
|
57
|
+
ctx.onCleanup(finish);
|
|
58
|
+
const runs = spans.map((s, i) => {
|
|
59
|
+
const a = ctx.animate(s, [{ opacity: 0, filter: 'blur(3px)' }, { opacity: 1, filter: 'none' }], { duration: 220, delay: i * speed, fill: 'both', easing: 'ease-out' });
|
|
60
|
+
if (!a)
|
|
61
|
+
s.style.opacity = '';
|
|
62
|
+
return a?.finished.catch(() => undefined);
|
|
63
|
+
});
|
|
64
|
+
return Promise.all(runs).then(finish);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'thinking-glow',
|
|
69
|
+
kind: 'loop',
|
|
70
|
+
description: 'A soft colour glow breathes and drifts round the element while a model is "thinking" (`colors`, comma-separated). Stops on cleanup.',
|
|
71
|
+
defaults: { colors: '#6366f1,#ec4899,#22d3ee', duration: 2400 },
|
|
72
|
+
run: (el, o, ctx) => {
|
|
73
|
+
const cs = String(o.colors).split(',').map((c) => c.trim()).filter(Boolean);
|
|
74
|
+
const c = cs.length ? cs : ['#6366f1'];
|
|
75
|
+
const frames = c.map((col, i) => ({ boxShadow: `0 0 ${i % 2 ? 26 : 14}px ${i % 2 ? 4 : 1}px ${col}`, offset: i / c.length }));
|
|
76
|
+
frames.push({ boxShadow: `0 0 14px 1px ${c[0]}`, offset: 1 });
|
|
77
|
+
const a = ctx.animate(el, frames, { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });
|
|
78
|
+
return () => a?.cancel();
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'voice-wave',
|
|
83
|
+
kind: 'attention',
|
|
84
|
+
description: "The element's children bounce in a wave like voice level bars, or the element pulses when it has none (`cycles`).",
|
|
85
|
+
defaults: { cycles: 2, duration: 700 },
|
|
86
|
+
run: (el, o, ctx) => {
|
|
87
|
+
if (ctx.reduced)
|
|
88
|
+
return;
|
|
89
|
+
const kids = Array.from(el.children);
|
|
90
|
+
const n = Math.max(1, Math.min(6, Number(o.cycles) || 2));
|
|
91
|
+
if (!kids.length)
|
|
92
|
+
return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.12)' }, { transform: 'scale(1)' }], { duration: o.duration, iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined);
|
|
93
|
+
return Promise.all(kids.map((k, i) => ctx.animate(k, [{ transform: 'scaleY(1)' }, { transform: 'scaleY(1.9)' }, { transform: 'scaleY(.6)' }, { transform: 'scaleY(1)' }], { duration: o.duration, delay: i * (o.duration / (kids.length * 2)), iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined))).then(() => undefined);
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'gen-skeleton',
|
|
98
|
+
kind: 'enter',
|
|
99
|
+
description: 'A shimmering skeleton covers the element, then dissolves to reveal the generated content (`hold` ms).',
|
|
100
|
+
defaults: { hold: 900, duration: 500 },
|
|
101
|
+
run: (el, o, ctx) => {
|
|
102
|
+
if (ctx.reduced)
|
|
103
|
+
return fade(el, ctx);
|
|
104
|
+
if (getComputedStyle(el).position === 'static') {
|
|
105
|
+
const prev = el.style.position;
|
|
106
|
+
el.style.position = 'relative';
|
|
107
|
+
ctx.onCleanup(() => (el.style.position = prev));
|
|
108
|
+
}
|
|
109
|
+
const sk = document.createElement('span');
|
|
110
|
+
sk.setAttribute('aria-hidden', 'true');
|
|
111
|
+
Object.assign(sk.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(100deg,#e2e8f0 30%,#f8fafc 50%,#e2e8f0 70%)', backgroundSize: '200% 100%', zIndex: '1' });
|
|
112
|
+
el.appendChild(sk);
|
|
113
|
+
const end = () => sk.remove();
|
|
114
|
+
ctx.onCleanup(end);
|
|
115
|
+
const hold = Math.max(0, Number(o.hold) || 0);
|
|
116
|
+
ctx.animate(sk, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: 900, iterations: Math.max(1, Math.ceil(hold / 900)) });
|
|
117
|
+
const a = ctx.animate(sk, [{ opacity: 1 }, { opacity: 0 }], { duration: o.duration, delay: hold, fill: 'both', easing: 'ease-out' });
|
|
118
|
+
return a ? a.finished.then(end, end) : (end(), undefined);
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
123
|
+
function registerAiPack() {
|
|
124
|
+
registry.registerEffects(AI_FX);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
exports.AI_FX = AI_FX;
|
|
128
|
+
exports.registerAiPack = registerAiPack;
|
|
129
|
+
exports.splitWords = splitWords;
|
|
130
|
+
//# sourceMappingURL=fx-ai.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-ai.cjs","sources":["../../src/components/fx2/ai.ts"],"sourcesContent":["/**\n * 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):\n *\n * - `stream-text` (enter) — the element's text appears word by word, like a\n * streamed LLM reply, with a blinking caret at the end (`speed` ms/word).\n * - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the\n * element while a model is \"thinking\" (`colors`); the cleanup stops it.\n * - `voice-wave` (attention) — the element's children bounce in a wave like\n * voice level bars (or the element pulses when it has none) (`cycles`).\n * - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then\n * dissolves to reveal the generated content (`hold`).\n *\n * Reduced motion: stream-text shows the text, thinking-glow is skipped,\n * voice-wave does nothing, gen-skeleton fades in.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Split text into words, keeping the whitespace after each (7.8). */\nexport function splitWords(text: string): string[] {\n return text.match(/\\S+\\s*|\\s+/g) || [];\n}\n\nconst fade = (el: HTMLElement, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n\nfunction textNodes(el: Node): Text[] {\n const out: Text[] = [];\n const walk = (n: Node) => n.childNodes.forEach((c) => (c.nodeType === 3 ? (c.textContent || '').trim() && out.push(c as Text) : c.nodeType === 1 && walk(c)));\n walk(el);\n return out;\n}\n\nexport const AI_FX: EffectDefinition[] = [\n {\n name: 'stream-text',\n kind: 'enter',\n description: 'The text appears word by word like a streamed LLM reply, with a blinking caret (`speed` ms per word).',\n defaults: { speed: 45 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const speed = Math.max(5, Number(o.speed) || 45);\n const spans: HTMLElement[] = [];\n const restores: (() => void)[] = [];\n for (const t of textNodes(el)) {\n const wrap = document.createElement('span');\n wrap.setAttribute('data-usa-stream', '');\n for (const w of splitWords(t.textContent || '')) {\n const s = document.createElement('span');\n s.textContent = w;\n s.style.opacity = '0';\n wrap.appendChild(s);\n spans.push(s);\n }\n (t.parentNode as Node).replaceChild(wrap, t);\n restores.push(() => wrap.isConnected && wrap.replaceWith(t));\n }\n const caret = document.createElement('span');\n caret.setAttribute('aria-hidden', 'true');\n caret.textContent = '▍';\n Object.assign(caret.style, { opacity: '.7', marginLeft: '1px' });\n el.appendChild(caret);\n const blink = ctx.animate(caret, [{ opacity: 0.8 }, { opacity: 0 }], { duration: 500, iterations: Infinity, direction: 'alternate' });\n let done = false;\n const finish = () => {\n if (done) return;\n done = true;\n blink?.cancel();\n caret.remove();\n restores.forEach((r) => r());\n };\n ctx.onCleanup(finish);\n const runs = spans.map((s, i) => {\n const a = ctx.animate(s, [{ opacity: 0, filter: 'blur(3px)' }, { opacity: 1, filter: 'none' }], { duration: 220, delay: i * speed, fill: 'both', easing: 'ease-out' });\n if (!a) s.style.opacity = '';\n return a?.finished.catch(() => undefined);\n });\n return Promise.all(runs).then(finish);\n },\n },\n {\n name: 'thinking-glow',\n kind: 'loop',\n description: 'A soft colour glow breathes and drifts round the element while a model is \"thinking\" (`colors`, comma-separated). Stops on cleanup.',\n defaults: { colors: '#6366f1,#ec4899,#22d3ee', duration: 2400 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const cs = String(o.colors).split(',').map((c) => c.trim()).filter(Boolean);\n const c = cs.length ? cs : ['#6366f1'];\n const frames: Keyframe[] = c.map((col, i) => ({ boxShadow: `0 0 ${i % 2 ? 26 : 14}px ${i % 2 ? 4 : 1}px ${col}`, offset: i / c.length }));\n frames.push({ boxShadow: `0 0 14px 1px ${c[0]}`, offset: 1 });\n const a = ctx.animate(el, frames, { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });\n return () => a?.cancel();\n },\n },\n {\n name: 'voice-wave',\n kind: 'attention',\n description: \"The element's children bounce in a wave like voice level bars, or the element pulses when it has none (`cycles`).\",\n defaults: { cycles: 2, duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const kids = Array.from(el.children) as HTMLElement[];\n const n = Math.max(1, Math.min(6, Number(o.cycles) || 2));\n if (!kids.length) return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.12)' }, { transform: 'scale(1)' }], { duration: o.duration, iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined);\n return Promise.all(\n kids.map((k, i) =>\n ctx.animate(k, [{ transform: 'scaleY(1)' }, { transform: 'scaleY(1.9)' }, { transform: 'scaleY(.6)' }, { transform: 'scaleY(1)' }], { duration: o.duration, delay: i * (o.duration / (kids.length * 2)), iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined)\n )\n ).then(() => undefined);\n },\n },\n {\n name: 'gen-skeleton',\n kind: 'enter',\n description: 'A shimmering skeleton covers the element, then dissolves to reveal the generated content (`hold` ms).',\n defaults: { hold: 900, duration: 500 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\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 sk = document.createElement('span');\n sk.setAttribute('aria-hidden', 'true');\n Object.assign(sk.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(100deg,#e2e8f0 30%,#f8fafc 50%,#e2e8f0 70%)', backgroundSize: '200% 100%', zIndex: '1' });\n el.appendChild(sk);\n const end = () => sk.remove();\n ctx.onCleanup(end);\n const hold = Math.max(0, Number(o.hold) || 0);\n ctx.animate(sk, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: 900, iterations: Math.max(1, Math.ceil(hold / 900)) });\n const a = ctx.animate(sk, [{ opacity: 1 }, { opacity: 0 }], { duration: o.duration, delay: hold, fill: 'both', easing: 'ease-out' });\n return a ? a.finished.then(end, end) : (end(), undefined);\n },\n },\n];\n\n/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */\nexport function registerAiPack(): void {\n registerEffects(AI_FX);\n}\n"],"names":["registerEffects"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
* 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):
|
|
46
|
+
*
|
|
47
|
+
* - `stream-text` (enter) — the element's text appears word by word, like a
|
|
48
|
+
* streamed LLM reply, with a blinking caret at the end (`speed` ms/word).
|
|
49
|
+
* - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the
|
|
50
|
+
* element while a model is "thinking" (`colors`); the cleanup stops it.
|
|
51
|
+
* - `voice-wave` (attention) — the element's children bounce in a wave like
|
|
52
|
+
* voice level bars (or the element pulses when it has none) (`cycles`).
|
|
53
|
+
* - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then
|
|
54
|
+
* dissolves to reveal the generated content (`hold`).
|
|
55
|
+
*
|
|
56
|
+
* Reduced motion: stream-text shows the text, thinking-glow is skipped,
|
|
57
|
+
* voice-wave does nothing, gen-skeleton fades in.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
61
|
+
declare function splitWords(text: string): string[];
|
|
62
|
+
declare const AI_FX: EffectDefinition[];
|
|
63
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
64
|
+
declare function registerAiPack(): void;
|
|
65
|
+
|
|
66
|
+
export { AI_FX, registerAiPack, splitWords };
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
* 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):
|
|
46
|
+
*
|
|
47
|
+
* - `stream-text` (enter) — the element's text appears word by word, like a
|
|
48
|
+
* streamed LLM reply, with a blinking caret at the end (`speed` ms/word).
|
|
49
|
+
* - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the
|
|
50
|
+
* element while a model is "thinking" (`colors`); the cleanup stops it.
|
|
51
|
+
* - `voice-wave` (attention) — the element's children bounce in a wave like
|
|
52
|
+
* voice level bars (or the element pulses when it has none) (`cycles`).
|
|
53
|
+
* - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then
|
|
54
|
+
* dissolves to reveal the generated content (`hold`).
|
|
55
|
+
*
|
|
56
|
+
* Reduced motion: stream-text shows the text, thinking-glow is skipped,
|
|
57
|
+
* voice-wave does nothing, gen-skeleton fades in.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
61
|
+
declare function splitWords(text: string): string[];
|
|
62
|
+
declare const AI_FX: EffectDefinition[];
|
|
63
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
64
|
+
declare function registerAiPack(): void;
|
|
65
|
+
|
|
66
|
+
export { AI_FX, registerAiPack, splitWords };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { registerEffects } from '../chunks/registry-CyKExAmE.js';
|
|
2
|
+
import '../chunks/base-2-yYc93C.js';
|
|
3
|
+
|
|
4
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
5
|
+
function splitWords(text) {
|
|
6
|
+
return text.match(/\S+\s*|\s+/g) || [];
|
|
7
|
+
}
|
|
8
|
+
const fade = (el, ctx) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
9
|
+
function textNodes(el) {
|
|
10
|
+
const out = [];
|
|
11
|
+
const walk = (n) => n.childNodes.forEach((c) => (c.nodeType === 3 ? (c.textContent || '').trim() && out.push(c) : c.nodeType === 1 && walk(c)));
|
|
12
|
+
walk(el);
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
const AI_FX = [
|
|
16
|
+
{
|
|
17
|
+
name: 'stream-text',
|
|
18
|
+
kind: 'enter',
|
|
19
|
+
description: 'The text appears word by word like a streamed LLM reply, with a blinking caret (`speed` ms per word).',
|
|
20
|
+
defaults: { speed: 45 },
|
|
21
|
+
run: (el, o, ctx) => {
|
|
22
|
+
if (ctx.reduced)
|
|
23
|
+
return;
|
|
24
|
+
const speed = Math.max(5, Number(o.speed) || 45);
|
|
25
|
+
const spans = [];
|
|
26
|
+
const restores = [];
|
|
27
|
+
for (const t of textNodes(el)) {
|
|
28
|
+
const wrap = document.createElement('span');
|
|
29
|
+
wrap.setAttribute('data-usa-stream', '');
|
|
30
|
+
for (const w of splitWords(t.textContent || '')) {
|
|
31
|
+
const s = document.createElement('span');
|
|
32
|
+
s.textContent = w;
|
|
33
|
+
s.style.opacity = '0';
|
|
34
|
+
wrap.appendChild(s);
|
|
35
|
+
spans.push(s);
|
|
36
|
+
}
|
|
37
|
+
t.parentNode.replaceChild(wrap, t);
|
|
38
|
+
restores.push(() => wrap.isConnected && wrap.replaceWith(t));
|
|
39
|
+
}
|
|
40
|
+
const caret = document.createElement('span');
|
|
41
|
+
caret.setAttribute('aria-hidden', 'true');
|
|
42
|
+
caret.textContent = '▍';
|
|
43
|
+
Object.assign(caret.style, { opacity: '.7', marginLeft: '1px' });
|
|
44
|
+
el.appendChild(caret);
|
|
45
|
+
const blink = ctx.animate(caret, [{ opacity: 0.8 }, { opacity: 0 }], { duration: 500, iterations: Infinity, direction: 'alternate' });
|
|
46
|
+
let done = false;
|
|
47
|
+
const finish = () => {
|
|
48
|
+
if (done)
|
|
49
|
+
return;
|
|
50
|
+
done = true;
|
|
51
|
+
blink?.cancel();
|
|
52
|
+
caret.remove();
|
|
53
|
+
restores.forEach((r) => r());
|
|
54
|
+
};
|
|
55
|
+
ctx.onCleanup(finish);
|
|
56
|
+
const runs = spans.map((s, i) => {
|
|
57
|
+
const a = ctx.animate(s, [{ opacity: 0, filter: 'blur(3px)' }, { opacity: 1, filter: 'none' }], { duration: 220, delay: i * speed, fill: 'both', easing: 'ease-out' });
|
|
58
|
+
if (!a)
|
|
59
|
+
s.style.opacity = '';
|
|
60
|
+
return a?.finished.catch(() => undefined);
|
|
61
|
+
});
|
|
62
|
+
return Promise.all(runs).then(finish);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'thinking-glow',
|
|
67
|
+
kind: 'loop',
|
|
68
|
+
description: 'A soft colour glow breathes and drifts round the element while a model is "thinking" (`colors`, comma-separated). Stops on cleanup.',
|
|
69
|
+
defaults: { colors: '#6366f1,#ec4899,#22d3ee', duration: 2400 },
|
|
70
|
+
run: (el, o, ctx) => {
|
|
71
|
+
const cs = String(o.colors).split(',').map((c) => c.trim()).filter(Boolean);
|
|
72
|
+
const c = cs.length ? cs : ['#6366f1'];
|
|
73
|
+
const frames = c.map((col, i) => ({ boxShadow: `0 0 ${i % 2 ? 26 : 14}px ${i % 2 ? 4 : 1}px ${col}`, offset: i / c.length }));
|
|
74
|
+
frames.push({ boxShadow: `0 0 14px 1px ${c[0]}`, offset: 1 });
|
|
75
|
+
const a = ctx.animate(el, frames, { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });
|
|
76
|
+
return () => a?.cancel();
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'voice-wave',
|
|
81
|
+
kind: 'attention',
|
|
82
|
+
description: "The element's children bounce in a wave like voice level bars, or the element pulses when it has none (`cycles`).",
|
|
83
|
+
defaults: { cycles: 2, duration: 700 },
|
|
84
|
+
run: (el, o, ctx) => {
|
|
85
|
+
if (ctx.reduced)
|
|
86
|
+
return;
|
|
87
|
+
const kids = Array.from(el.children);
|
|
88
|
+
const n = Math.max(1, Math.min(6, Number(o.cycles) || 2));
|
|
89
|
+
if (!kids.length)
|
|
90
|
+
return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.12)' }, { transform: 'scale(1)' }], { duration: o.duration, iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined);
|
|
91
|
+
return Promise.all(kids.map((k, i) => ctx.animate(k, [{ transform: 'scaleY(1)' }, { transform: 'scaleY(1.9)' }, { transform: 'scaleY(.6)' }, { transform: 'scaleY(1)' }], { duration: o.duration, delay: i * (o.duration / (kids.length * 2)), iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined))).then(() => undefined);
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'gen-skeleton',
|
|
96
|
+
kind: 'enter',
|
|
97
|
+
description: 'A shimmering skeleton covers the element, then dissolves to reveal the generated content (`hold` ms).',
|
|
98
|
+
defaults: { hold: 900, duration: 500 },
|
|
99
|
+
run: (el, o, ctx) => {
|
|
100
|
+
if (ctx.reduced)
|
|
101
|
+
return fade(el, ctx);
|
|
102
|
+
if (getComputedStyle(el).position === 'static') {
|
|
103
|
+
const prev = el.style.position;
|
|
104
|
+
el.style.position = 'relative';
|
|
105
|
+
ctx.onCleanup(() => (el.style.position = prev));
|
|
106
|
+
}
|
|
107
|
+
const sk = document.createElement('span');
|
|
108
|
+
sk.setAttribute('aria-hidden', 'true');
|
|
109
|
+
Object.assign(sk.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(100deg,#e2e8f0 30%,#f8fafc 50%,#e2e8f0 70%)', backgroundSize: '200% 100%', zIndex: '1' });
|
|
110
|
+
el.appendChild(sk);
|
|
111
|
+
const end = () => sk.remove();
|
|
112
|
+
ctx.onCleanup(end);
|
|
113
|
+
const hold = Math.max(0, Number(o.hold) || 0);
|
|
114
|
+
ctx.animate(sk, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: 900, iterations: Math.max(1, Math.ceil(hold / 900)) });
|
|
115
|
+
const a = ctx.animate(sk, [{ opacity: 1 }, { opacity: 0 }], { duration: o.duration, delay: hold, fill: 'both', easing: 'ease-out' });
|
|
116
|
+
return a ? a.finished.then(end, end) : (end(), undefined);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
121
|
+
function registerAiPack() {
|
|
122
|
+
registerEffects(AI_FX);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { AI_FX, registerAiPack, splitWords };
|
|
126
|
+
//# sourceMappingURL=fx-ai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-ai.js","sources":["../../src/components/fx2/ai.ts"],"sourcesContent":["/**\n * 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):\n *\n * - `stream-text` (enter) — the element's text appears word by word, like a\n * streamed LLM reply, with a blinking caret at the end (`speed` ms/word).\n * - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the\n * element while a model is \"thinking\" (`colors`); the cleanup stops it.\n * - `voice-wave` (attention) — the element's children bounce in a wave like\n * voice level bars (or the element pulses when it has none) (`cycles`).\n * - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then\n * dissolves to reveal the generated content (`hold`).\n *\n * Reduced motion: stream-text shows the text, thinking-glow is skipped,\n * voice-wave does nothing, gen-skeleton fades in.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Split text into words, keeping the whitespace after each (7.8). */\nexport function splitWords(text: string): string[] {\n return text.match(/\\S+\\s*|\\s+/g) || [];\n}\n\nconst fade = (el: HTMLElement, ctx: EffectContext) => ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n\nfunction textNodes(el: Node): Text[] {\n const out: Text[] = [];\n const walk = (n: Node) => n.childNodes.forEach((c) => (c.nodeType === 3 ? (c.textContent || '').trim() && out.push(c as Text) : c.nodeType === 1 && walk(c)));\n walk(el);\n return out;\n}\n\nexport const AI_FX: EffectDefinition[] = [\n {\n name: 'stream-text',\n kind: 'enter',\n description: 'The text appears word by word like a streamed LLM reply, with a blinking caret (`speed` ms per word).',\n defaults: { speed: 45 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const speed = Math.max(5, Number(o.speed) || 45);\n const spans: HTMLElement[] = [];\n const restores: (() => void)[] = [];\n for (const t of textNodes(el)) {\n const wrap = document.createElement('span');\n wrap.setAttribute('data-usa-stream', '');\n for (const w of splitWords(t.textContent || '')) {\n const s = document.createElement('span');\n s.textContent = w;\n s.style.opacity = '0';\n wrap.appendChild(s);\n spans.push(s);\n }\n (t.parentNode as Node).replaceChild(wrap, t);\n restores.push(() => wrap.isConnected && wrap.replaceWith(t));\n }\n const caret = document.createElement('span');\n caret.setAttribute('aria-hidden', 'true');\n caret.textContent = '▍';\n Object.assign(caret.style, { opacity: '.7', marginLeft: '1px' });\n el.appendChild(caret);\n const blink = ctx.animate(caret, [{ opacity: 0.8 }, { opacity: 0 }], { duration: 500, iterations: Infinity, direction: 'alternate' });\n let done = false;\n const finish = () => {\n if (done) return;\n done = true;\n blink?.cancel();\n caret.remove();\n restores.forEach((r) => r());\n };\n ctx.onCleanup(finish);\n const runs = spans.map((s, i) => {\n const a = ctx.animate(s, [{ opacity: 0, filter: 'blur(3px)' }, { opacity: 1, filter: 'none' }], { duration: 220, delay: i * speed, fill: 'both', easing: 'ease-out' });\n if (!a) s.style.opacity = '';\n return a?.finished.catch(() => undefined);\n });\n return Promise.all(runs).then(finish);\n },\n },\n {\n name: 'thinking-glow',\n kind: 'loop',\n description: 'A soft colour glow breathes and drifts round the element while a model is \"thinking\" (`colors`, comma-separated). Stops on cleanup.',\n defaults: { colors: '#6366f1,#ec4899,#22d3ee', duration: 2400 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const cs = String(o.colors).split(',').map((c) => c.trim()).filter(Boolean);\n const c = cs.length ? cs : ['#6366f1'];\n const frames: Keyframe[] = c.map((col, i) => ({ boxShadow: `0 0 ${i % 2 ? 26 : 14}px ${i % 2 ? 4 : 1}px ${col}`, offset: i / c.length }));\n frames.push({ boxShadow: `0 0 14px 1px ${c[0]}`, offset: 1 });\n const a = ctx.animate(el, frames, { duration: o.duration, iterations: Infinity, easing: 'ease-in-out' });\n return () => a?.cancel();\n },\n },\n {\n name: 'voice-wave',\n kind: 'attention',\n description: \"The element's children bounce in a wave like voice level bars, or the element pulses when it has none (`cycles`).\",\n defaults: { cycles: 2, duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return;\n const kids = Array.from(el.children) as HTMLElement[];\n const n = Math.max(1, Math.min(6, Number(o.cycles) || 2));\n if (!kids.length) return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.12)' }, { transform: 'scale(1)' }], { duration: o.duration, iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined);\n return Promise.all(\n kids.map((k, i) =>\n ctx.animate(k, [{ transform: 'scaleY(1)' }, { transform: 'scaleY(1.9)' }, { transform: 'scaleY(.6)' }, { transform: 'scaleY(1)' }], { duration: o.duration, delay: i * (o.duration / (kids.length * 2)), iterations: n, easing: 'ease-in-out' })?.finished.catch(() => undefined)\n )\n ).then(() => undefined);\n },\n },\n {\n name: 'gen-skeleton',\n kind: 'enter',\n description: 'A shimmering skeleton covers the element, then dissolves to reveal the generated content (`hold` ms).',\n defaults: { hold: 900, duration: 500 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return fade(el, ctx);\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 sk = document.createElement('span');\n sk.setAttribute('aria-hidden', 'true');\n Object.assign(sk.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(100deg,#e2e8f0 30%,#f8fafc 50%,#e2e8f0 70%)', backgroundSize: '200% 100%', zIndex: '1' });\n el.appendChild(sk);\n const end = () => sk.remove();\n ctx.onCleanup(end);\n const hold = Math.max(0, Number(o.hold) || 0);\n ctx.animate(sk, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: 900, iterations: Math.max(1, Math.ceil(hold / 900)) });\n const a = ctx.animate(sk, [{ opacity: 1 }, { opacity: 0 }], { duration: o.duration, delay: hold, fill: 'both', easing: 'ease-out' });\n return a ? a.finished.then(end, end) : (end(), undefined);\n },\n },\n];\n\n/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */\nexport function registerAiPack(): void {\n registerEffects(AI_FX);\n}\n"],"names":[],"mappings":"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"}
|
package/dist/components/fx2.cjs
CHANGED
|
@@ -17,6 +17,7 @@ var components_fxSocial = require('./fx-social.cjs');
|
|
|
17
17
|
var components_fxGame = require('./fx-game.cjs');
|
|
18
18
|
var components_fxGeo = require('./fx-geo.cjs');
|
|
19
19
|
var components_fxForm = require('./fx-form.cjs');
|
|
20
|
+
var components_fxAi = require('./fx-ai.cjs');
|
|
20
21
|
require('../chunks/registry-DehBVRDV.cjs');
|
|
21
22
|
require('../chunks/base-BaQV-2ha.cjs');
|
|
22
23
|
require('../chunks/generative-BHIj-NU0.cjs');
|
|
@@ -41,6 +42,7 @@ const EFFECT_PACKS = {
|
|
|
41
42
|
game: components_fxGame.GAME_FX,
|
|
42
43
|
geo: components_fxGeo.GEO_FX,
|
|
43
44
|
form: components_fxForm.FORM_FX,
|
|
45
|
+
ai: components_fxAi.AI_FX,
|
|
44
46
|
};
|
|
45
47
|
/** Register every 6.x effect pack (idempotent). */
|
|
46
48
|
function registerEffectPacks() {
|
|
@@ -60,6 +62,7 @@ function registerEffectPacks() {
|
|
|
60
62
|
components_fxGame.registerGamePack();
|
|
61
63
|
components_fxGeo.registerGeoPack();
|
|
62
64
|
components_fxForm.registerFormPack();
|
|
65
|
+
components_fxAi.registerAiPack();
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
exports.EFFECT_PACK_FORMAT = components_marketplace.EFFECT_PACK_FORMAT;
|
|
@@ -123,6 +126,9 @@ exports.routeLength = components_fxGeo.routeLength;
|
|
|
123
126
|
exports.FORM_FX = components_fxForm.FORM_FX;
|
|
124
127
|
exports.registerFormPack = components_fxForm.registerFormPack;
|
|
125
128
|
exports.shakeFrames = components_fxForm.shakeFrames;
|
|
129
|
+
exports.AI_FX = components_fxAi.AI_FX;
|
|
130
|
+
exports.registerAiPack = components_fxAi.registerAiPack;
|
|
131
|
+
exports.splitWords = components_fxAi.splitWords;
|
|
126
132
|
exports.EFFECT_PACKS = EFFECT_PACKS;
|
|
127
133
|
exports.registerEffectPacks = registerEffectPacks;
|
|
128
134
|
//# sourceMappingURL=fx2.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fx2.cjs","sources":["../../src/components/fx2/index.ts"],"sourcesContent":["/**\n * The 6.x effect packs, one entry each (`motionary/components/fx-gpu`, …) so\n * their size budgets stay separate. This module (`registerFx2()`) registers\n * them all — used by dist/widgets.umd.js and the showcase.\n */\nimport type { EffectDefinition } from '../fx/registry';\nexport { EFFECT_PACK_FORMAT, packManifest, validateManifest, loadEffectPack } from './manifest';\nexport type { EffectPackManifest } from './manifest';\nimport { GPU_FX, registerGpuPack } from './gpu';\nimport { TEXT3_FX, registerTextPack, splitChars } from './text3';\nimport { LIGHT_FX, registerLightPack, trackPointer } from './light';\nimport { DEPTH3_FX, register3dPack } from './depth3';\nimport { MORPH2_FX, registerMorphPack, samplePath, pointsToPath } from './morph2';\nimport { TRANSITIONS2_FX, registerTransitionsPack, pageTransition, crossDocumentTransitions } from './transitions2';\nimport { WEATHER_FX, registerWeatherPack, skyAt } from './weather';\nimport { PHYSICS2_FX, registerPhysicsPack, VerletWorld } from './physics2';\nimport { FOCUS_FX, registerFocusPack } from './focus';\nimport { MUSIC_FX, registerMusicPack, syntheticSample, musicSample } from './music';\nimport { CHART_FX, registerChartPack, parseFigure } from './chart';\nimport { SHOP_FX, registerShopPack, arcPath } from './shop';\nimport { SOCIAL_FX, registerSocialPack, fanAngles } from './social';\nimport { GAME_FX, registerGamePack, throwPath } from './game';\nimport { GEO_FX, registerGeoPack, routeLength } from './geo';\nimport { FORM_FX, registerFormPack, shakeFrames } from './form';\n\nexport { GPU_FX, registerGpuPack, TEXT3_FX, registerTextPack, splitChars };\nexport { shaderBackground, supportsWebGL2, fieldFallback, GLSL_HEAD } from './gl';\nexport { supportsWebGPU, glslToWgsl, wgslModule, webgpuBackground, WGSL_HEAD } from './webgpu';\nexport type { ShaderSpec } from './gl';\n\nexport { LIGHT_FX, registerLightPack, trackPointer };\n\nexport { DEPTH3_FX, register3dPack };\n\nexport { MORPH2_FX, registerMorphPack, samplePath, pointsToPath };\n\nexport { TRANSITIONS2_FX, registerTransitionsPack, pageTransition, crossDocumentTransitions };\n\nexport { WEATHER_FX, registerWeatherPack, skyAt };\n\nexport { PHYSICS2_FX, registerPhysicsPack, VerletWorld };\n\nexport { FOCUS_FX, registerFocusPack };\n\nexport { MUSIC_FX, registerMusicPack, syntheticSample, musicSample };\n\nexport { CHART_FX, registerChartPack, parseFigure };\n\nexport { SHOP_FX, registerShopPack, arcPath };\n\nexport { SOCIAL_FX, registerSocialPack, fanAngles };\n\nexport { GAME_FX, registerGamePack, throwPath };\n\nexport { GEO_FX, registerGeoPack, routeLength };\n\nexport { FORM_FX, registerFormPack, shakeFrames };\n\n/** The 6.x effect packs by name. */\nexport const EFFECT_PACKS: Record<string, EffectDefinition[]> = {\n gpu: GPU_FX,\n text: TEXT3_FX,\n light: LIGHT_FX,\n depth: DEPTH3_FX,\n morph: MORPH2_FX,\n transitions: TRANSITIONS2_FX,\n weather: WEATHER_FX,\n physics: PHYSICS2_FX,\n focus: FOCUS_FX,\n music: MUSIC_FX,\n chart: CHART_FX,\n shop: SHOP_FX,\n social: SOCIAL_FX,\n game: GAME_FX,\n geo: GEO_FX,\n form: FORM_FX,\n};\n\n/** Register every 6.x effect pack (idempotent). */\nexport function registerEffectPacks(): void {\n registerGpuPack();\n registerTextPack();\n registerLightPack();\n register3dPack();\n registerMorphPack();\n registerTransitionsPack();\n registerWeatherPack();\n registerPhysicsPack();\n registerFocusPack();\n registerMusicPack();\n registerChartPack();\n registerShopPack();\n registerSocialPack();\n registerGamePack();\n registerGeoPack();\n registerFormPack();\n}\n\n\n"],"names":["GPU_FX","TEXT3_FX","LIGHT_FX","DEPTH3_FX","MORPH2_FX","TRANSITIONS2_FX","WEATHER_FX","PHYSICS2_FX","FOCUS_FX","MUSIC_FX","CHART_FX","SHOP_FX","SOCIAL_FX","GAME_FX","GEO_FX","FORM_FX","registerGpuPack","registerTextPack","registerLightPack","register3dPack","registerMorphPack","registerTransitionsPack","registerWeatherPack","registerPhysicsPack","registerFocusPack","registerMusicPack","registerChartPack","registerShopPack","registerSocialPack","registerGamePack","registerGeoPack","registerFormPack"],"mappings":"
|
|
1
|
+
{"version":3,"file":"fx2.cjs","sources":["../../src/components/fx2/index.ts"],"sourcesContent":["/**\n * The 6.x effect packs, one entry each (`motionary/components/fx-gpu`, …) so\n * their size budgets stay separate. This module (`registerFx2()`) registers\n * them all — used by dist/widgets.umd.js and the showcase.\n */\nimport type { EffectDefinition } from '../fx/registry';\nexport { EFFECT_PACK_FORMAT, packManifest, validateManifest, loadEffectPack } from './manifest';\nexport type { EffectPackManifest } from './manifest';\nimport { GPU_FX, registerGpuPack } from './gpu';\nimport { TEXT3_FX, registerTextPack, splitChars } from './text3';\nimport { LIGHT_FX, registerLightPack, trackPointer } from './light';\nimport { DEPTH3_FX, register3dPack } from './depth3';\nimport { MORPH2_FX, registerMorphPack, samplePath, pointsToPath } from './morph2';\nimport { TRANSITIONS2_FX, registerTransitionsPack, pageTransition, crossDocumentTransitions } from './transitions2';\nimport { WEATHER_FX, registerWeatherPack, skyAt } from './weather';\nimport { PHYSICS2_FX, registerPhysicsPack, VerletWorld } from './physics2';\nimport { FOCUS_FX, registerFocusPack } from './focus';\nimport { MUSIC_FX, registerMusicPack, syntheticSample, musicSample } from './music';\nimport { CHART_FX, registerChartPack, parseFigure } from './chart';\nimport { SHOP_FX, registerShopPack, arcPath } from './shop';\nimport { SOCIAL_FX, registerSocialPack, fanAngles } from './social';\nimport { GAME_FX, registerGamePack, throwPath } from './game';\nimport { GEO_FX, registerGeoPack, routeLength } from './geo';\nimport { FORM_FX, registerFormPack, shakeFrames } from './form';\nimport { AI_FX, registerAiPack, splitWords } from './ai';\n\nexport { GPU_FX, registerGpuPack, TEXT3_FX, registerTextPack, splitChars };\nexport { shaderBackground, supportsWebGL2, fieldFallback, GLSL_HEAD } from './gl';\nexport { supportsWebGPU, glslToWgsl, wgslModule, webgpuBackground, WGSL_HEAD } from './webgpu';\nexport type { ShaderSpec } from './gl';\n\nexport { LIGHT_FX, registerLightPack, trackPointer };\n\nexport { DEPTH3_FX, register3dPack };\n\nexport { MORPH2_FX, registerMorphPack, samplePath, pointsToPath };\n\nexport { TRANSITIONS2_FX, registerTransitionsPack, pageTransition, crossDocumentTransitions };\n\nexport { WEATHER_FX, registerWeatherPack, skyAt };\n\nexport { PHYSICS2_FX, registerPhysicsPack, VerletWorld };\n\nexport { FOCUS_FX, registerFocusPack };\n\nexport { MUSIC_FX, registerMusicPack, syntheticSample, musicSample };\n\nexport { CHART_FX, registerChartPack, parseFigure };\n\nexport { SHOP_FX, registerShopPack, arcPath };\n\nexport { SOCIAL_FX, registerSocialPack, fanAngles };\n\nexport { GAME_FX, registerGamePack, throwPath };\n\nexport { GEO_FX, registerGeoPack, routeLength };\n\nexport { FORM_FX, registerFormPack, shakeFrames };\n\nexport { AI_FX, registerAiPack, splitWords };\n\n/** The 6.x effect packs by name. */\nexport const EFFECT_PACKS: Record<string, EffectDefinition[]> = {\n gpu: GPU_FX,\n text: TEXT3_FX,\n light: LIGHT_FX,\n depth: DEPTH3_FX,\n morph: MORPH2_FX,\n transitions: TRANSITIONS2_FX,\n weather: WEATHER_FX,\n physics: PHYSICS2_FX,\n focus: FOCUS_FX,\n music: MUSIC_FX,\n chart: CHART_FX,\n shop: SHOP_FX,\n social: SOCIAL_FX,\n game: GAME_FX,\n geo: GEO_FX,\n form: FORM_FX,\n ai: AI_FX,\n};\n\n/** Register every 6.x effect pack (idempotent). */\nexport function registerEffectPacks(): void {\n registerGpuPack();\n registerTextPack();\n registerLightPack();\n register3dPack();\n registerMorphPack();\n registerTransitionsPack();\n registerWeatherPack();\n registerPhysicsPack();\n registerFocusPack();\n registerMusicPack();\n registerChartPack();\n registerShopPack();\n registerSocialPack();\n registerGamePack();\n registerGeoPack();\n registerFormPack();\n registerAiPack();\n}\n\n\n"],"names":["GPU_FX","TEXT3_FX","LIGHT_FX","DEPTH3_FX","MORPH2_FX","TRANSITIONS2_FX","WEATHER_FX","PHYSICS2_FX","FOCUS_FX","MUSIC_FX","CHART_FX","SHOP_FX","SOCIAL_FX","GAME_FX","GEO_FX","FORM_FX","AI_FX","registerGpuPack","registerTextPack","registerLightPack","register3dPack","registerMorphPack","registerTransitionsPack","registerWeatherPack","registerPhysicsPack","registerFocusPack","registerMusicPack","registerChartPack","registerShopPack","registerSocialPack","registerGamePack","registerGeoPack","registerFormPack","registerAiPack"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA;AACO,MAAM,YAAY,GAAuC;AAC9D,IAAA,GAAG,EAAEA,uBAAM;AACX,IAAA,IAAI,EAAEC,0BAAQ;AACd,IAAA,KAAK,EAAEC,2BAAQ;AACf,IAAA,KAAK,EAAEC,yBAAS;AAChB,IAAA,KAAK,EAAEC,4BAAS;AAChB,IAAA,WAAW,EAAEC,wCAAe;AAC5B,IAAA,OAAO,EAAEC,+BAAU;AACnB,IAAA,OAAO,EAAEC,gCAAW;AACpB,IAAA,KAAK,EAAEC,2BAAQ;AACf,IAAA,KAAK,EAAEC,2BAAQ;AACf,IAAA,KAAK,EAAEC,2BAAQ;AACf,IAAA,IAAI,EAAEC,yBAAO;AACb,IAAA,MAAM,EAAEC,6BAAS;AACjB,IAAA,IAAI,EAAEC,yBAAO;AACb,IAAA,GAAG,EAAEC,uBAAM;AACX,IAAA,IAAI,EAAEC,yBAAO;AACb,IAAA,EAAE,EAAEC,qBAAK;;AAGX;SACgB,mBAAmB,GAAA;AACjC,IAAAC,gCAAe,EAAE;AACjB,IAAAC,kCAAgB,EAAE;AAClB,IAAAC,oCAAiB,EAAE;AACnB,IAAAC,8BAAc,EAAE;AAChB,IAAAC,oCAAiB,EAAE;AACnB,IAAAC,gDAAuB,EAAE;AACzB,IAAAC,wCAAmB,EAAE;AACrB,IAAAC,wCAAmB,EAAE;AACrB,IAAAC,oCAAiB,EAAE;AACnB,IAAAC,oCAAiB,EAAE;AACnB,IAAAC,oCAAiB,EAAE;AACnB,IAAAC,kCAAgB,EAAE;AAClB,IAAAC,sCAAkB,EAAE;AACpB,IAAAC,kCAAgB,EAAE;AAClB,IAAAC,gCAAe,EAAE;AACjB,IAAAC,kCAAgB,EAAE;AAClB,IAAAC,8BAAc,EAAE;AAClB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -563,6 +563,28 @@ declare const FORM_FX: EffectDefinition[];
|
|
|
563
563
|
/** Register field-shake, field-success, label-float and form-cascade (7.7). */
|
|
564
564
|
declare function registerFormPack(): void;
|
|
565
565
|
|
|
566
|
+
/**
|
|
567
|
+
* 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):
|
|
568
|
+
*
|
|
569
|
+
* - `stream-text` (enter) — the element's text appears word by word, like a
|
|
570
|
+
* streamed LLM reply, with a blinking caret at the end (`speed` ms/word).
|
|
571
|
+
* - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the
|
|
572
|
+
* element while a model is "thinking" (`colors`); the cleanup stops it.
|
|
573
|
+
* - `voice-wave` (attention) — the element's children bounce in a wave like
|
|
574
|
+
* voice level bars (or the element pulses when it has none) (`cycles`).
|
|
575
|
+
* - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then
|
|
576
|
+
* dissolves to reveal the generated content (`hold`).
|
|
577
|
+
*
|
|
578
|
+
* Reduced motion: stream-text shows the text, thinking-glow is skipped,
|
|
579
|
+
* voice-wave does nothing, gen-skeleton fades in.
|
|
580
|
+
*/
|
|
581
|
+
|
|
582
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
583
|
+
declare function splitWords(text: string): string[];
|
|
584
|
+
declare const AI_FX: EffectDefinition[];
|
|
585
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
586
|
+
declare function registerAiPack(): void;
|
|
587
|
+
|
|
566
588
|
/**
|
|
567
589
|
* 5.5 — generative backgrounds on Canvas 2D, registered through
|
|
568
590
|
* `registerEffect()` (kind `background`): `flow-field`, `voronoi`,
|
|
@@ -672,5 +694,5 @@ declare const EFFECT_PACKS: Record<string, EffectDefinition[]>;
|
|
|
672
694
|
/** Register every 6.x effect pack (idempotent). */
|
|
673
695
|
declare function registerEffectPacks(): void;
|
|
674
696
|
|
|
675
|
-
export { CHART_FX, DEPTH3_FX, EFFECT_PACKS, EFFECT_PACK_FORMAT, FOCUS_FX, FORM_FX, GAME_FX, GEO_FX, GLSL_HEAD, GPU_FX, LIGHT_FX, MORPH2_FX, MUSIC_FX, PHYSICS2_FX, SHOP_FX, SOCIAL_FX, TEXT3_FX, TRANSITIONS2_FX, VerletWorld, WEATHER_FX, WGSL_HEAD, arcPath, crossDocumentTransitions, fanAngles, fieldFallback, glslToWgsl, loadEffectPack, musicSample, packManifest, pageTransition, parseFigure, pointsToPath, register3dPack, registerChartPack, registerEffectPacks, registerFocusPack, registerFormPack, registerGamePack, registerGeoPack, registerGpuPack, registerLightPack, registerMorphPack, registerMusicPack, registerPhysicsPack, registerShopPack, registerSocialPack, registerTextPack, registerTransitionsPack, registerWeatherPack, routeLength, samplePath, shaderBackground, shakeFrames, skyAt, splitChars, supportsWebGL2, supportsWebGPU, syntheticSample, throwPath, trackPointer, validateManifest, webgpuBackground, wgslModule };
|
|
697
|
+
export { AI_FX, CHART_FX, DEPTH3_FX, EFFECT_PACKS, EFFECT_PACK_FORMAT, FOCUS_FX, FORM_FX, GAME_FX, GEO_FX, GLSL_HEAD, GPU_FX, LIGHT_FX, MORPH2_FX, MUSIC_FX, PHYSICS2_FX, SHOP_FX, SOCIAL_FX, TEXT3_FX, TRANSITIONS2_FX, VerletWorld, WEATHER_FX, WGSL_HEAD, arcPath, crossDocumentTransitions, fanAngles, fieldFallback, glslToWgsl, loadEffectPack, musicSample, packManifest, pageTransition, parseFigure, pointsToPath, register3dPack, registerAiPack, registerChartPack, registerEffectPacks, registerFocusPack, registerFormPack, registerGamePack, registerGeoPack, registerGpuPack, registerLightPack, registerMorphPack, registerMusicPack, registerPhysicsPack, registerShopPack, registerSocialPack, registerTextPack, registerTransitionsPack, registerWeatherPack, routeLength, samplePath, shaderBackground, shakeFrames, skyAt, splitChars, splitWords, supportsWebGL2, supportsWebGPU, syntheticSample, throwPath, trackPointer, validateManifest, webgpuBackground, wgslModule };
|
|
676
698
|
export type { EffectPackManifest, ShaderSpec };
|
package/dist/components/fx2.d.ts
CHANGED
|
@@ -563,6 +563,28 @@ declare const FORM_FX: EffectDefinition[];
|
|
|
563
563
|
/** Register field-shake, field-success, label-float and form-cascade (7.7). */
|
|
564
564
|
declare function registerFormPack(): void;
|
|
565
565
|
|
|
566
|
+
/**
|
|
567
|
+
* 7.8 — AI UI motion (`motionary/fx/ai`, also `motionary/components/fx-ai`):
|
|
568
|
+
*
|
|
569
|
+
* - `stream-text` (enter) — the element's text appears word by word, like a
|
|
570
|
+
* streamed LLM reply, with a blinking caret at the end (`speed` ms/word).
|
|
571
|
+
* - `thinking-glow` (loop) — a soft colour glow breathes and drifts round the
|
|
572
|
+
* element while a model is "thinking" (`colors`); the cleanup stops it.
|
|
573
|
+
* - `voice-wave` (attention) — the element's children bounce in a wave like
|
|
574
|
+
* voice level bars (or the element pulses when it has none) (`cycles`).
|
|
575
|
+
* - `gen-skeleton` (enter) — a shimmering skeleton covers the element, then
|
|
576
|
+
* dissolves to reveal the generated content (`hold`).
|
|
577
|
+
*
|
|
578
|
+
* Reduced motion: stream-text shows the text, thinking-glow is skipped,
|
|
579
|
+
* voice-wave does nothing, gen-skeleton fades in.
|
|
580
|
+
*/
|
|
581
|
+
|
|
582
|
+
/** Split text into words, keeping the whitespace after each (7.8). */
|
|
583
|
+
declare function splitWords(text: string): string[];
|
|
584
|
+
declare const AI_FX: EffectDefinition[];
|
|
585
|
+
/** Register stream-text, thinking-glow, voice-wave and gen-skeleton (7.8). */
|
|
586
|
+
declare function registerAiPack(): void;
|
|
587
|
+
|
|
566
588
|
/**
|
|
567
589
|
* 5.5 — generative backgrounds on Canvas 2D, registered through
|
|
568
590
|
* `registerEffect()` (kind `background`): `flow-field`, `voronoi`,
|
|
@@ -672,5 +694,5 @@ declare const EFFECT_PACKS: Record<string, EffectDefinition[]>;
|
|
|
672
694
|
/** Register every 6.x effect pack (idempotent). */
|
|
673
695
|
declare function registerEffectPacks(): void;
|
|
674
696
|
|
|
675
|
-
export { CHART_FX, DEPTH3_FX, EFFECT_PACKS, EFFECT_PACK_FORMAT, FOCUS_FX, FORM_FX, GAME_FX, GEO_FX, GLSL_HEAD, GPU_FX, LIGHT_FX, MORPH2_FX, MUSIC_FX, PHYSICS2_FX, SHOP_FX, SOCIAL_FX, TEXT3_FX, TRANSITIONS2_FX, VerletWorld, WEATHER_FX, WGSL_HEAD, arcPath, crossDocumentTransitions, fanAngles, fieldFallback, glslToWgsl, loadEffectPack, musicSample, packManifest, pageTransition, parseFigure, pointsToPath, register3dPack, registerChartPack, registerEffectPacks, registerFocusPack, registerFormPack, registerGamePack, registerGeoPack, registerGpuPack, registerLightPack, registerMorphPack, registerMusicPack, registerPhysicsPack, registerShopPack, registerSocialPack, registerTextPack, registerTransitionsPack, registerWeatherPack, routeLength, samplePath, shaderBackground, shakeFrames, skyAt, splitChars, supportsWebGL2, supportsWebGPU, syntheticSample, throwPath, trackPointer, validateManifest, webgpuBackground, wgslModule };
|
|
697
|
+
export { AI_FX, CHART_FX, DEPTH3_FX, EFFECT_PACKS, EFFECT_PACK_FORMAT, FOCUS_FX, FORM_FX, GAME_FX, GEO_FX, GLSL_HEAD, GPU_FX, LIGHT_FX, MORPH2_FX, MUSIC_FX, PHYSICS2_FX, SHOP_FX, SOCIAL_FX, TEXT3_FX, TRANSITIONS2_FX, VerletWorld, WEATHER_FX, WGSL_HEAD, arcPath, crossDocumentTransitions, fanAngles, fieldFallback, glslToWgsl, loadEffectPack, musicSample, packManifest, pageTransition, parseFigure, pointsToPath, register3dPack, registerAiPack, registerChartPack, registerEffectPacks, registerFocusPack, registerFormPack, registerGamePack, registerGeoPack, registerGpuPack, registerLightPack, registerMorphPack, registerMusicPack, registerPhysicsPack, registerShopPack, registerSocialPack, registerTextPack, registerTransitionsPack, registerWeatherPack, routeLength, samplePath, shaderBackground, shakeFrames, skyAt, splitChars, splitWords, supportsWebGL2, supportsWebGPU, syntheticSample, throwPath, trackPointer, validateManifest, webgpuBackground, wgslModule };
|
|
676
698
|
export type { EffectPackManifest, ShaderSpec };
|