motionary 7.3.0 → 7.5.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 +38 -0
- package/dist/components/fx-game.cjs +127 -0
- package/dist/components/fx-game.cjs.map +1 -0
- package/dist/components/fx-game.d.cts +70 -0
- package/dist/components/fx-game.d.ts +70 -0
- package/dist/components/fx-game.js +123 -0
- package/dist/components/fx-game.js.map +1 -0
- package/dist/components/fx-social.cjs +121 -0
- package/dist/components/fx-social.cjs.map +1 -0
- package/dist/components/fx-social.d.cts +66 -0
- package/dist/components/fx-social.d.ts +66 -0
- package/dist/components/fx-social.js +117 -0
- package/dist/components/fx-social.js.map +1 -0
- package/dist/components/fx2.cjs +12 -0
- package/dist/components/fx2.cjs.map +1 -1
- package/dist/components/fx2.d.cts +49 -1
- package/dist/components/fx2.d.ts +49 -1
- package/dist/components/fx2.js +9 -1
- package/dist/components/fx2.js.map +1 -1
- package/dist/components/widgets.cjs +833 -85
- package/dist/components/widgets.cjs.map +1 -1
- package/dist/components/widgets.d.cts +182 -2
- package/dist/components/widgets.d.ts +182 -2
- package/dist/components/widgets.js +819 -86
- 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 +2 -2
- package/docs/components.md +48 -0
- package/package.json +41 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [7.5.0] - 2026-10-08
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **4 new components (7.5)** in `motionary/components/widgets` (also in `dist/widgets.umd.js`):
|
|
14
|
+
- `<usa-leaderboard>` — ranked list from `<li data-score>` children or `rows`: on score changes rows glide to their new rank (FLIP), climbers flash green with ▲n, fallers red with ▼n, scores roll; 🥇🥈🥉 for the top three; `limit`, `me`; `setScore()`; `usa:rank`. `rankRows()`.
|
|
15
|
+
- `<usa-xp-bar>` — experience bar (`level`, `xp`, `per`): `add(n)` fills smoothly; overflow fills to the end, the level badge pops and the bar restarts with the remainder (multi-level); `usa:xp`, `usa:levelup`. `levelFor()`.
|
|
16
|
+
- `<usa-badge-wall>` — achievement grid from `<li data-icon data-locked>`: locked badges are grey with 🔒; `unlock(name)` flips the badge to colour with a shine and updates the “n / m unlocked” counter; `badges`, `usa:unlock`. `badgeProgress()`.
|
|
17
|
+
- `<usa-prize-wheel>` — lottery wheel from `segments`: Spin whirls it, it eases out on a random result (or `spin(index)`), the pointer ticks, the wheel glows; `duration`, `turns`, `result`, `spinning`; `usa:result`. `wheelAngle()`.
|
|
18
|
+
- **Gamification motion — `motionary/fx/game`** (= `motionary/components/fx-game`, `registerGamePack()`, also in `registerEffectPacks()`): `achievement-unlock` (attention), `level-up` (attention), `chest-open` (click), `coin-burst` (click), `xp-gain` (enter). `throwPath()`.
|
|
19
|
+
- Showcase: 6 new gallery cards with copyable code and live demos; Animation Store 311 → 317 items.
|
|
20
|
+
- Note: the plan's “lottery” ships as `<usa-prize-wheel>` (wheel + lottery in one component).
|
|
21
|
+
|
|
22
|
+
### Accessibility
|
|
23
|
+
- Leaderboard = labelled ordered list ("1. Ada, 980 points"), rank changes announced politely; XP bar = `progressbar` labelled "Level 3, 40 of 100 XP", level-ups announced; badge wall = labelled list, each badge "First win, locked/unlocked", unlocks announced; prize wheel = real button (disabled while spinning), result announced. Reduced motion: rows jump, no flash or roll; bar and level change at once; badges change without flip or shine; the wheel jumps to the result; `achievement-unlock` / `level-up` fade, `chest-open` sets the lid open, `coin-burst` / `xp-gain` do nothing.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **Store thumbnails are live demos (user report, mobile ~390px).** Cards in “组件 6.x” (now “Components 6.x–7.x”, 90 items incl. every 7.x widget/effect pack) and “框架 / Frameworks” (5) showed only a generic purple tile with a bouncing emoji or letter. Every component card now renders the real `<usa-*>` element with its gallery demo markup + wiring in a lazily mounted frame (`showcase/thumb.html`, mounted by IntersectionObserver near the viewport, dropped 4 s after leaving it, scaled to fit with no overflow, inert on cards, interactive in the detail view and its “related” minis). Framework cards show a live scroll-reveal demo driven through the real adapter (React hooks / Vue composables via minimal hook stand-ins, the Svelte action, `<scroll-animate>`; Solid via the core) next to its code snippet. Reduced motion: the demos are still, the components follow their own reduced-motion paths. Audit: no Store item (all 317) uses the placeholder any more.
|
|
27
|
+
- Showcase: the global icon rule `svg:not([width]) { width: 1.25em }` in `showcase/styles.css` shrank the SVGs inside live demos — `<usa-gauge>` and `<usa-sparkline>` (and the KPI trend) rendered as a 15 px speck in the component gallery. Scoped to UI icons with `:where(…)`.
|
|
28
|
+
- Store detail for components: dropped the meaningless duration/easing controls, keyframes and scroll-test mode; Replay remounts the live demo; the note no longer says “preview only”.
|
|
29
|
+
|
|
30
|
+
## [7.4.0] - 2026-10-08
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
- **4 new components (7.4)** in `motionary/components/widgets` (also in `dist/widgets.umd.js`):
|
|
34
|
+
- `<usa-message-list>` — chat thread from `<p data-from data-me data-time>` children or `push(msg)`: bubbles pop in from their side, consecutive messages group, the list sticks to the bottom (smooth) or shows a “↓ New messages” pill when you scrolled up; `typing(name)` shows animated typing dots until the next message; `messages`, `usa:message`. `role="log"` + `aria-live="polite"`.
|
|
35
|
+
- `<usa-reactions>` — emoji reaction bar (`emojis`, `counts`, `picker`): clicking toggles your reaction (emoji pop, count roll, floating copies), + springs open a picker; `counts`, `mine`, `toggle()`, `usa:react`. `parseReactions()`.
|
|
36
|
+
- `<usa-notification-bell>` — bell + unread badge + dropdown (`<li data-time data-read>` children): `notify()` swings the bell, bumps the badge and slides the notice in; `markAllRead()` shrinks the badge away; `unread`, `notices`, `open`, `ring()`; Esc / outside click close; `usa:notify`, `usa:read`.
|
|
37
|
+
- `<usa-presence>` — avatar + status dot (`status` online | away | busy | offline, `name`, `src`): coming online sends a ripple, `speaking` pulses a ring, `story` spins a gradient ring; initials fallback. `PRESENCE_STATES`, `initials()`.
|
|
38
|
+
- **Chat & social motion — `motionary/fx/social`** (= `motionary/components/fx-social`, `registerSocialPack()`, also in `registerEffectPacks()`): `typing-dots` (loop), `message-in` (enter), `reaction-burst` (click), `read-receipt` (enter), `mention-glow` (attention). `fanAngles()`.
|
|
39
|
+
- Showcase: 6 new gallery cards with copyable code and live demos; Animation Store 305 → 311 items.
|
|
40
|
+
- Note: the plan's “avatar stack” already ships as `<usa-avatar-stack>` (unchanged), so 7.4 adds `<usa-presence>` instead.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- `<usa-reactions>` (pre-release staging): two type errors broke `tsc` — `picker.hidden` (now `boolean | "until-found"` in the DOM lib) passed to a boolean toggle, and `.type` set on an `HTMLElement` — fixed (`=== true`, `setAttribute('type','button')`).
|
|
44
|
+
|
|
45
|
+
### Accessibility
|
|
46
|
+
- Message list = `log` (polite) with a labelled typing bubble; reactions = labelled `group` of `aria-pressed` toggle buttons with counts in their labels; bell = `button` with `aria-expanded` and the unread count in its label, list = labelled region, Esc returns focus; presence = labelled `img` ("Ada Lovelace, online"). Reduced motion: no pop, smooth scroll, roll, float, swing, bump, slide, ripple, pulse or ring spin; typing dots are static; `reaction-burst` does nothing, `read-receipt` / `mention-glow` show their end state.
|
|
47
|
+
|
|
10
48
|
## [7.3.0] - 2026-10-08
|
|
11
49
|
|
|
12
50
|
### Added
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var registry = require('../chunks/registry-DehBVRDV.cjs');
|
|
4
|
+
require('../chunks/base-BaQV-2ha.cjs');
|
|
5
|
+
|
|
6
|
+
/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */
|
|
7
|
+
function throwPath(deg, power = 120, steps = 6, g = 2.2) {
|
|
8
|
+
const r = (deg * Math.PI) / 180;
|
|
9
|
+
const vx = Math.sin(r) * power;
|
|
10
|
+
const vy = -Math.cos(r) * power;
|
|
11
|
+
return Array.from({ length: steps + 1 }, (_, i) => {
|
|
12
|
+
const t = i / steps;
|
|
13
|
+
return { x: Math.round(vx * t), y: Math.round(vy * t + g * power * t * t * 0.5) };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const floater = (el, text, css) => {
|
|
17
|
+
const r = el.getBoundingClientRect();
|
|
18
|
+
const s = document.createElement('span');
|
|
19
|
+
s.setAttribute('aria-hidden', 'true');
|
|
20
|
+
s.textContent = text;
|
|
21
|
+
Object.assign(s.style, { position: 'fixed', left: `${r.left + r.width / 2}px`, top: `${r.top + r.height / 2}px`, pointerEvents: 'none', zIndex: '2147483000', translate: '-50% -50%' }, css);
|
|
22
|
+
document.body.appendChild(s);
|
|
23
|
+
return s;
|
|
24
|
+
};
|
|
25
|
+
const fin = (a, el, ctx) => {
|
|
26
|
+
const end = () => el.remove();
|
|
27
|
+
if (a)
|
|
28
|
+
a.finished.then(end, end);
|
|
29
|
+
else
|
|
30
|
+
end();
|
|
31
|
+
ctx.onCleanup(end);
|
|
32
|
+
return a?.finished.catch(() => undefined);
|
|
33
|
+
};
|
|
34
|
+
const GAME_FX = [
|
|
35
|
+
{
|
|
36
|
+
name: 'achievement-unlock',
|
|
37
|
+
kind: 'attention',
|
|
38
|
+
description: 'The element slides in, a light sweep crosses it and its icon (`[data-icon]` or first child) pops (`duration`).',
|
|
39
|
+
defaults: { duration: 900 },
|
|
40
|
+
run: (el, o, ctx) => {
|
|
41
|
+
if (ctx.reduced)
|
|
42
|
+
return ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
43
|
+
const icon = (el.querySelector('[data-icon]') || el.firstElementChild);
|
|
44
|
+
const a = ctx.animate(el, [{ transform: 'translateY(30px) scale(.9)', opacity: 0 }, { transform: 'translateY(-4px) scale(1.02)', opacity: 1, offset: 0.5 }, { transform: 'none', opacity: 1 }], { duration: o.duration * 0.6, easing: 'cubic-bezier(.2,.9,.3,1)' });
|
|
45
|
+
if (icon)
|
|
46
|
+
ctx.animate(icon, [{ transform: 'scale(0) rotate(-30deg)' }, { transform: 'scale(1.4) rotate(10deg)', offset: 0.6 }, { transform: 'none' }], { duration: o.duration * 0.6, delay: o.duration * 0.3, easing: 'ease-out', fill: 'backwards' });
|
|
47
|
+
const pos = getComputedStyle(el).position;
|
|
48
|
+
if (pos === 'static')
|
|
49
|
+
el.style.position = 'relative';
|
|
50
|
+
const sh = document.createElement('span');
|
|
51
|
+
sh.setAttribute('aria-hidden', 'true');
|
|
52
|
+
Object.assign(sh.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(110deg,transparent 35%,rgba(255,255,255,.7) 50%,transparent 65%)', backgroundSize: '250% 100%' });
|
|
53
|
+
el.appendChild(sh);
|
|
54
|
+
fin(ctx.animate(sh, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: o.duration * 0.6, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' }), sh, ctx);
|
|
55
|
+
return a?.finished.catch(() => undefined);
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'level-up',
|
|
60
|
+
kind: 'attention',
|
|
61
|
+
description: 'A scale-up with a ring shockwave in `color` (`color`, `duration`).',
|
|
62
|
+
defaults: { color: '#facc15', duration: 800 },
|
|
63
|
+
run: (el, o, ctx) => {
|
|
64
|
+
if (ctx.reduced)
|
|
65
|
+
return ctx.animate(el, [{ opacity: 0.5 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
66
|
+
const r = el.getBoundingClientRect();
|
|
67
|
+
const ring = floater(el, '', { width: `${Math.max(r.width, r.height)}px`, height: `${Math.max(r.width, r.height)}px`, borderRadius: '50%', border: `3px solid ${o.color}` });
|
|
68
|
+
fin(ctx.animate(ring, [{ transform: 'scale(.4)', opacity: 1 }, { transform: 'scale(1.8)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), ring, ctx);
|
|
69
|
+
return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.3 }, { transform: 'scale(.95)', offset: 0.6 }, { transform: 'scale(1)' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'chest-open',
|
|
74
|
+
kind: 'click',
|
|
75
|
+
description: 'The lid (`[data-lid]` or first child) flips open and sparks (`spark`) fly out (`count`).',
|
|
76
|
+
defaults: { spark: '✨', count: 6, duration: 700 },
|
|
77
|
+
run: (el, o, ctx) => {
|
|
78
|
+
const lid = (el.querySelector('[data-lid]') || el.firstElementChild);
|
|
79
|
+
el.setAttribute('data-open', '');
|
|
80
|
+
if (lid)
|
|
81
|
+
lid.style.transformOrigin = '50% 100%';
|
|
82
|
+
if (ctx.reduced)
|
|
83
|
+
return void (lid && (lid.style.transform = 'rotateX(110deg)'));
|
|
84
|
+
if (lid)
|
|
85
|
+
ctx.animate(lid, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(125deg)', offset: 0.6 }, { transform: 'rotateX(110deg)' }], { duration: o.duration, easing: 'cubic-bezier(.3,1.5,.6,1)', fill: 'forwards' });
|
|
86
|
+
const parts = Array.from({ length: o.count }, (_, i) => {
|
|
87
|
+
const s = floater(el, o.spark, { fontSize: '18px' });
|
|
88
|
+
const deg = -60 + (120 * i) / Math.max(1, o.count - 1);
|
|
89
|
+
const p = throwPath(deg, 90, 6, 1.2);
|
|
90
|
+
return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) scale(${(1 - k / 12).toFixed(2)})`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: 150 + i * 30, easing: 'linear' }), s, ctx);
|
|
91
|
+
});
|
|
92
|
+
return Promise.all(parts);
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'coin-burst',
|
|
97
|
+
kind: 'click',
|
|
98
|
+
description: 'Coins (`coin`) arc up out of the element and fall away (`count`, `power`).',
|
|
99
|
+
defaults: { coin: '🪙', count: 8, power: 140, duration: 900 },
|
|
100
|
+
reduced: 'skip',
|
|
101
|
+
run: (el, o, ctx) => Promise.all(Array.from({ length: o.count }, (_, i) => {
|
|
102
|
+
const s = floater(el, o.coin, { fontSize: '20px' });
|
|
103
|
+
const p = throwPath(-50 + (100 * i) / Math.max(1, o.count - 1) + (Math.random() * 10 - 5), o.power * (0.8 + Math.random() * 0.4));
|
|
104
|
+
return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) rotate(${k * 60}deg)`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: i * 25, easing: 'linear' }), s, ctx);
|
|
105
|
+
})),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'xp-gain',
|
|
109
|
+
kind: 'enter',
|
|
110
|
+
description: 'A “+50 XP” label (`text`, or `data-xp`) floats up from the element and fades (`color`).',
|
|
111
|
+
defaults: { text: '', color: '#7c5cff', duration: 1100 },
|
|
112
|
+
reduced: 'skip',
|
|
113
|
+
run: (el, o, ctx) => {
|
|
114
|
+
const s = floater(el, o.text || `+${el.dataset.xp || 10} XP`, { font: '800 16px/1 system-ui,sans-serif', color: o.color, textShadow: '0 1px 0 #fff' });
|
|
115
|
+
return fin(ctx.animate(s, [{ transform: 'translateY(0) scale(.6)', opacity: 0 }, { transform: 'translateY(-18px) scale(1.15)', opacity: 1, offset: 0.25 }, { transform: 'translateY(-50px) scale(1)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), s, ctx);
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
/** Register the 7.5 gamification pack (idempotent). */
|
|
120
|
+
function registerGamePack() {
|
|
121
|
+
registry.registerEffects(GAME_FX);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
exports.GAME_FX = GAME_FX;
|
|
125
|
+
exports.registerGamePack = registerGamePack;
|
|
126
|
+
exports.throwPath = throwPath;
|
|
127
|
+
//# sourceMappingURL=fx-game.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-game.cjs","sources":["../../src/components/fx2/game.ts"],"sourcesContent":["/**\n * 7.5 — Gamification motion (`motionary/fx/game`, also\n * `motionary/components/fx-game`):\n *\n * - `achievement-unlock` (attention) — the element slides in, a light sweep\n * crosses it and its icon (`[data-icon]` or first child) pops.\n * - `level-up` (attention) — a scale-up with a ring shockwave.\n * - `chest-open` (click) — the lid (`[data-lid]` or first child) flips open\n * and sparks fly out.\n * - `coin-burst` (click) — coins (`coin`, default 🪙) arc up and fall.\n * - `xp-gain` (enter) — a “+50 XP” label (`text` or `data-xp`) floats up and\n * fades.\n *\n * Reduced motion: unlock / level-up fade, chest-open sets the lid open,\n * coin-burst and xp-gain do nothing.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */\nexport function throwPath(deg: number, power = 120, steps = 6, g = 2.2): { x: number; y: number }[] {\n const r = (deg * Math.PI) / 180;\n const vx = Math.sin(r) * power;\n const vy = -Math.cos(r) * power;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const t = i / steps;\n return { x: Math.round(vx * t), y: Math.round(vy * t + g * power * t * t * 0.5) };\n });\n}\n\nconst floater = (el: HTMLElement, text: string, css: Partial<CSSStyleDeclaration>): HTMLSpanElement => {\n const r = el.getBoundingClientRect();\n const s = document.createElement('span');\n s.setAttribute('aria-hidden', 'true');\n s.textContent = text;\n Object.assign(s.style, { position: 'fixed', left: `${r.left + r.width / 2}px`, top: `${r.top + r.height / 2}px`, pointerEvents: 'none', zIndex: '2147483000', translate: '-50% -50%' }, css);\n document.body.appendChild(s);\n return s;\n};\n\nconst fin = (a: Animation | null | undefined, el: Element, ctx: EffectContext) => {\n const end = () => el.remove();\n if (a) a.finished.then(end, end);\n else end();\n ctx.onCleanup(end);\n return a?.finished.catch(() => undefined);\n};\n\nexport const GAME_FX: EffectDefinition[] = [\n {\n name: 'achievement-unlock',\n kind: 'attention',\n description: 'The element slides in, a light sweep crosses it and its icon (`[data-icon]` or first child) pops (`duration`).',\n defaults: { duration: 900 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n const icon = (el.querySelector('[data-icon]') || el.firstElementChild) as HTMLElement | null;\n const a = ctx.animate(el, [{ transform: 'translateY(30px) scale(.9)', opacity: 0 }, { transform: 'translateY(-4px) scale(1.02)', opacity: 1, offset: 0.5 }, { transform: 'none', opacity: 1 }], { duration: o.duration * 0.6, easing: 'cubic-bezier(.2,.9,.3,1)' });\n if (icon) ctx.animate(icon, [{ transform: 'scale(0) rotate(-30deg)' }, { transform: 'scale(1.4) rotate(10deg)', offset: 0.6 }, { transform: 'none' }], { duration: o.duration * 0.6, delay: o.duration * 0.3, easing: 'ease-out', fill: 'backwards' });\n const pos = getComputedStyle(el).position;\n if (pos === 'static') el.style.position = 'relative';\n const sh = document.createElement('span');\n sh.setAttribute('aria-hidden', 'true');\n Object.assign(sh.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(110deg,transparent 35%,rgba(255,255,255,.7) 50%,transparent 65%)', backgroundSize: '250% 100%' });\n el.appendChild(sh);\n fin(ctx.animate(sh, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: o.duration * 0.6, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' }), sh, ctx);\n return a?.finished.catch(() => undefined);\n },\n },\n {\n name: 'level-up',\n kind: 'attention',\n description: 'A scale-up with a ring shockwave in `color` (`color`, `duration`).',\n defaults: { color: '#facc15', duration: 800 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return ctx.animate(el, [{ opacity: 0.5 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n const r = el.getBoundingClientRect();\n const ring = floater(el, '', { width: `${Math.max(r.width, r.height)}px`, height: `${Math.max(r.width, r.height)}px`, borderRadius: '50%', border: `3px solid ${o.color}` });\n fin(ctx.animate(ring, [{ transform: 'scale(.4)', opacity: 1 }, { transform: 'scale(1.8)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), ring, ctx);\n return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.3 }, { transform: 'scale(.95)', offset: 0.6 }, { transform: 'scale(1)' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);\n },\n },\n {\n name: 'chest-open',\n kind: 'click',\n description: 'The lid (`[data-lid]` or first child) flips open and sparks (`spark`) fly out (`count`).',\n defaults: { spark: '✨', count: 6, duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const lid = (el.querySelector('[data-lid]') || el.firstElementChild) as HTMLElement | null;\n el.setAttribute('data-open', '');\n if (lid) lid.style.transformOrigin = '50% 100%';\n if (ctx.reduced) return void (lid && (lid.style.transform = 'rotateX(110deg)'));\n if (lid) ctx.animate(lid, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(125deg)', offset: 0.6 }, { transform: 'rotateX(110deg)' }], { duration: o.duration, easing: 'cubic-bezier(.3,1.5,.6,1)', fill: 'forwards' });\n const parts = Array.from({ length: o.count }, (_, i) => {\n const s = floater(el, o.spark, { fontSize: '18px' });\n const deg = -60 + (120 * i) / Math.max(1, o.count - 1);\n const p = throwPath(deg, 90, 6, 1.2);\n return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) scale(${(1 - k / 12).toFixed(2)})`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: 150 + i * 30, easing: 'linear' }), s, ctx);\n });\n return Promise.all(parts);\n },\n },\n {\n name: 'coin-burst',\n kind: 'click',\n description: 'Coins (`coin`) arc up out of the element and fall away (`count`, `power`).',\n defaults: { coin: '🪙', count: 8, power: 140, duration: 900 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) =>\n Promise.all(\n Array.from({ length: o.count }, (_, i) => {\n const s = floater(el, o.coin, { fontSize: '20px' });\n const p = throwPath(-50 + (100 * i) / Math.max(1, o.count - 1) + (Math.random() * 10 - 5), o.power * (0.8 + Math.random() * 0.4));\n return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) rotate(${k * 60}deg)`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: i * 25, easing: 'linear' }), s, ctx);\n })\n ),\n },\n {\n name: 'xp-gain',\n kind: 'enter',\n description: 'A “+50 XP” label (`text`, or `data-xp`) floats up from the element and fades (`color`).',\n defaults: { text: '', color: '#7c5cff', duration: 1100 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const s = floater(el, o.text || `+${el.dataset.xp || 10} XP`, { font: '800 16px/1 system-ui,sans-serif', color: o.color, textShadow: '0 1px 0 #fff' });\n return fin(ctx.animate(s, [{ transform: 'translateY(0) scale(.6)', opacity: 0 }, { transform: 'translateY(-18px) scale(1.15)', opacity: 1, offset: 0.25 }, { transform: 'translateY(-50px) scale(1)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), s, ctx);\n },\n },\n];\n\n/** Register the 7.5 gamification pack (idempotent). */\nexport function registerGamePack(): void {\n registerEffects(GAME_FX);\n}\n"],"names":["registerEffects"],"mappings":";;;;;AAmBA;AACM,SAAU,SAAS,CAAC,GAAW,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAA;IACpE,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,IAAI,GAAG;IAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK;IAC9B,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK;AAC/B,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAI;AAChD,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;AACnB,QAAA,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AACnF,IAAA,CAAC,CAAC;AACJ;AAEA,MAAM,OAAO,GAAG,CAAC,EAAe,EAAE,IAAY,EAAE,GAAiC,KAAqB;AACpG,IAAA,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE;IACpC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACxC,IAAA,CAAC,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC;AACrC,IAAA,CAAC,CAAC,WAAW,GAAG,IAAI;IACpB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA,EAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAA,EAAA,CAAI,EAAE,GAAG,EAAE,CAAA,EAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAA,EAAA,CAAI,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,GAAG,CAAC;AAC5L,IAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;AAC5B,IAAA,OAAO,CAAC;AACV,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,CAA+B,EAAE,EAAW,EAAE,GAAkB,KAAI;IAC/E,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE;AAC7B,IAAA,IAAI,CAAC;QAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC;;AAC3B,QAAA,GAAG,EAAE;AACV,IAAA,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC3C,CAAC;AAEM,MAAM,OAAO,GAAuB;AACzC,IAAA;AACE,QAAA,IAAI,EAAE,oBAAoB;AAC1B,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,gHAAgH;AAC7H,QAAA,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;QAC3B,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;AAAE,gBAAA,OAAO,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;AAC7H,YAAA,MAAM,IAAI,IAAI,EAAE,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,iBAAiB,CAAuB;YAC5F,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,4BAA4B,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,8BAA8B,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;AACnQ,YAAA,IAAI,IAAI;gBAAE,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,yBAAyB,EAAE,EAAE,EAAE,SAAS,EAAE,0BAA0B,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;YACtP,MAAM,GAAG,GAAG,gBAAgB,CAAC,EAAE,CAAC,CAAC,QAAQ;YACzC,IAAI,GAAG,KAAK,QAAQ;AAAE,gBAAA,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,UAAU;YACpD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACzC,YAAA,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC;AACtC,YAAA,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,kFAAkF,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AAC1O,YAAA,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;YAClB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,kBAAkB,EAAE,QAAQ,EAAE,EAAE,EAAE,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC;YACtM,OAAO,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QAC3C,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,UAAU;AAChB,QAAA,IAAI,EAAE,WAAW;AACjB,QAAA,WAAW,EAAE,oEAAoE;QACjF,QAAQ,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE;QAC7C,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;YACnD,IAAI,GAAG,CAAC,OAAO;AAAE,gBAAA,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;AAC/H,YAAA,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,EAAE;YACpC,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA,EAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA,EAAA,CAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA,EAAA,CAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,KAAK,CAAA,CAAE,EAAE,CAAC;YAC5K,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC;AAClK,YAAA,OAAO,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,SAAS,CAAC;QACpP,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,0FAA0F;AACvG,QAAA,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;QACjD,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;AACnD,YAAA,MAAM,GAAG,IAAI,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,iBAAiB,CAAuB;AAC1F,YAAA,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,CAAC;AAChC,YAAA,IAAI,GAAG;AAAE,gBAAA,GAAG,CAAC,KAAK,CAAC,eAAe,GAAG,UAAU;YAC/C,IAAI,GAAG,CAAC,OAAO;AAAE,gBAAA,OAAO,MAAM,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,SAAS,GAAG,iBAAiB,CAAC,CAAC;AAC/E,YAAA,IAAI,GAAG;gBAAE,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,2BAA2B,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC1N,YAAA,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAI;AACrD,gBAAA,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;gBACpD,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AACtD,gBAAA,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;gBACpC,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,CAAC,CAAA,GAAA,EAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,CAAA,CAAG,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AAC9O,YAAA,CAAC,CAAC;AACF,YAAA,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;QAC3B,CAAC;AACF,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,4EAA4E;AACzF,QAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;AAC7D,QAAA,OAAO,EAAE,MAAM;AACf,QAAA,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAC/C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAI;AACvC,YAAA,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;YACnD,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;AACjI,YAAA,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,CAAA,UAAA,EAAa,CAAC,CAAC,CAAC,CAAA,GAAA,EAAM,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,CAAA,IAAA,CAAM,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;AAC3N,QAAA,CAAC,CAAC,CACH;AACJ,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,IAAI,EAAE,OAAO;AACb,QAAA,WAAW,EAAE,yFAAyF;AACtG,QAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;AACxD,QAAA,OAAO,EAAE,MAAM;QACf,GAAG,EAAE,CAAC,EAAe,EAAE,CAAM,EAAE,GAAkB,KAAI;AACnD,YAAA,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAA,GAAA,CAAK,EAAE,EAAE,IAAI,EAAE,iCAAiC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AACtJ,YAAA,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,yBAAyB,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,+BAA+B,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,4BAA4B,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC;QAC7Q,CAAC;AACF,KAAA;;AAGH;SACgB,gBAAgB,GAAA;IAC9BA,wBAAe,CAAC,OAAO,CAAC;AAC1B;;;;;;"}
|
|
@@ -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
|
+
* 7.5 — Gamification motion (`motionary/fx/game`, also
|
|
46
|
+
* `motionary/components/fx-game`):
|
|
47
|
+
*
|
|
48
|
+
* - `achievement-unlock` (attention) — the element slides in, a light sweep
|
|
49
|
+
* crosses it and its icon (`[data-icon]` or first child) pops.
|
|
50
|
+
* - `level-up` (attention) — a scale-up with a ring shockwave.
|
|
51
|
+
* - `chest-open` (click) — the lid (`[data-lid]` or first child) flips open
|
|
52
|
+
* and sparks fly out.
|
|
53
|
+
* - `coin-burst` (click) — coins (`coin`, default 🪙) arc up and fall.
|
|
54
|
+
* - `xp-gain` (enter) — a “+50 XP” label (`text` or `data-xp`) floats up and
|
|
55
|
+
* fades.
|
|
56
|
+
*
|
|
57
|
+
* Reduced motion: unlock / level-up fade, chest-open sets the lid open,
|
|
58
|
+
* coin-burst and xp-gain do nothing.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */
|
|
62
|
+
declare function throwPath(deg: number, power?: number, steps?: number, g?: number): {
|
|
63
|
+
x: number;
|
|
64
|
+
y: number;
|
|
65
|
+
}[];
|
|
66
|
+
declare const GAME_FX: EffectDefinition[];
|
|
67
|
+
/** Register the 7.5 gamification pack (idempotent). */
|
|
68
|
+
declare function registerGamePack(): void;
|
|
69
|
+
|
|
70
|
+
export { GAME_FX, registerGamePack, throwPath };
|
|
@@ -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
|
+
* 7.5 — Gamification motion (`motionary/fx/game`, also
|
|
46
|
+
* `motionary/components/fx-game`):
|
|
47
|
+
*
|
|
48
|
+
* - `achievement-unlock` (attention) — the element slides in, a light sweep
|
|
49
|
+
* crosses it and its icon (`[data-icon]` or first child) pops.
|
|
50
|
+
* - `level-up` (attention) — a scale-up with a ring shockwave.
|
|
51
|
+
* - `chest-open` (click) — the lid (`[data-lid]` or first child) flips open
|
|
52
|
+
* and sparks fly out.
|
|
53
|
+
* - `coin-burst` (click) — coins (`coin`, default 🪙) arc up and fall.
|
|
54
|
+
* - `xp-gain` (enter) — a “+50 XP” label (`text` or `data-xp`) floats up and
|
|
55
|
+
* fades.
|
|
56
|
+
*
|
|
57
|
+
* Reduced motion: unlock / level-up fade, chest-open sets the lid open,
|
|
58
|
+
* coin-burst and xp-gain do nothing.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */
|
|
62
|
+
declare function throwPath(deg: number, power?: number, steps?: number, g?: number): {
|
|
63
|
+
x: number;
|
|
64
|
+
y: number;
|
|
65
|
+
}[];
|
|
66
|
+
declare const GAME_FX: EffectDefinition[];
|
|
67
|
+
/** Register the 7.5 gamification pack (idempotent). */
|
|
68
|
+
declare function registerGamePack(): void;
|
|
69
|
+
|
|
70
|
+
export { GAME_FX, registerGamePack, throwPath };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { registerEffects } from '../chunks/registry-CyKExAmE.js';
|
|
2
|
+
import '../chunks/base-2-yYc93C.js';
|
|
3
|
+
|
|
4
|
+
/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */
|
|
5
|
+
function throwPath(deg, power = 120, steps = 6, g = 2.2) {
|
|
6
|
+
const r = (deg * Math.PI) / 180;
|
|
7
|
+
const vx = Math.sin(r) * power;
|
|
8
|
+
const vy = -Math.cos(r) * power;
|
|
9
|
+
return Array.from({ length: steps + 1 }, (_, i) => {
|
|
10
|
+
const t = i / steps;
|
|
11
|
+
return { x: Math.round(vx * t), y: Math.round(vy * t + g * power * t * t * 0.5) };
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const floater = (el, text, css) => {
|
|
15
|
+
const r = el.getBoundingClientRect();
|
|
16
|
+
const s = document.createElement('span');
|
|
17
|
+
s.setAttribute('aria-hidden', 'true');
|
|
18
|
+
s.textContent = text;
|
|
19
|
+
Object.assign(s.style, { position: 'fixed', left: `${r.left + r.width / 2}px`, top: `${r.top + r.height / 2}px`, pointerEvents: 'none', zIndex: '2147483000', translate: '-50% -50%' }, css);
|
|
20
|
+
document.body.appendChild(s);
|
|
21
|
+
return s;
|
|
22
|
+
};
|
|
23
|
+
const fin = (a, el, ctx) => {
|
|
24
|
+
const end = () => el.remove();
|
|
25
|
+
if (a)
|
|
26
|
+
a.finished.then(end, end);
|
|
27
|
+
else
|
|
28
|
+
end();
|
|
29
|
+
ctx.onCleanup(end);
|
|
30
|
+
return a?.finished.catch(() => undefined);
|
|
31
|
+
};
|
|
32
|
+
const GAME_FX = [
|
|
33
|
+
{
|
|
34
|
+
name: 'achievement-unlock',
|
|
35
|
+
kind: 'attention',
|
|
36
|
+
description: 'The element slides in, a light sweep crosses it and its icon (`[data-icon]` or first child) pops (`duration`).',
|
|
37
|
+
defaults: { duration: 900 },
|
|
38
|
+
run: (el, o, ctx) => {
|
|
39
|
+
if (ctx.reduced)
|
|
40
|
+
return ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
41
|
+
const icon = (el.querySelector('[data-icon]') || el.firstElementChild);
|
|
42
|
+
const a = ctx.animate(el, [{ transform: 'translateY(30px) scale(.9)', opacity: 0 }, { transform: 'translateY(-4px) scale(1.02)', opacity: 1, offset: 0.5 }, { transform: 'none', opacity: 1 }], { duration: o.duration * 0.6, easing: 'cubic-bezier(.2,.9,.3,1)' });
|
|
43
|
+
if (icon)
|
|
44
|
+
ctx.animate(icon, [{ transform: 'scale(0) rotate(-30deg)' }, { transform: 'scale(1.4) rotate(10deg)', offset: 0.6 }, { transform: 'none' }], { duration: o.duration * 0.6, delay: o.duration * 0.3, easing: 'ease-out', fill: 'backwards' });
|
|
45
|
+
const pos = getComputedStyle(el).position;
|
|
46
|
+
if (pos === 'static')
|
|
47
|
+
el.style.position = 'relative';
|
|
48
|
+
const sh = document.createElement('span');
|
|
49
|
+
sh.setAttribute('aria-hidden', 'true');
|
|
50
|
+
Object.assign(sh.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(110deg,transparent 35%,rgba(255,255,255,.7) 50%,transparent 65%)', backgroundSize: '250% 100%' });
|
|
51
|
+
el.appendChild(sh);
|
|
52
|
+
fin(ctx.animate(sh, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: o.duration * 0.6, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' }), sh, ctx);
|
|
53
|
+
return a?.finished.catch(() => undefined);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'level-up',
|
|
58
|
+
kind: 'attention',
|
|
59
|
+
description: 'A scale-up with a ring shockwave in `color` (`color`, `duration`).',
|
|
60
|
+
defaults: { color: '#facc15', duration: 800 },
|
|
61
|
+
run: (el, o, ctx) => {
|
|
62
|
+
if (ctx.reduced)
|
|
63
|
+
return ctx.animate(el, [{ opacity: 0.5 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);
|
|
64
|
+
const r = el.getBoundingClientRect();
|
|
65
|
+
const ring = floater(el, '', { width: `${Math.max(r.width, r.height)}px`, height: `${Math.max(r.width, r.height)}px`, borderRadius: '50%', border: `3px solid ${o.color}` });
|
|
66
|
+
fin(ctx.animate(ring, [{ transform: 'scale(.4)', opacity: 1 }, { transform: 'scale(1.8)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), ring, ctx);
|
|
67
|
+
return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.3 }, { transform: 'scale(.95)', offset: 0.6 }, { transform: 'scale(1)' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'chest-open',
|
|
72
|
+
kind: 'click',
|
|
73
|
+
description: 'The lid (`[data-lid]` or first child) flips open and sparks (`spark`) fly out (`count`).',
|
|
74
|
+
defaults: { spark: '✨', count: 6, duration: 700 },
|
|
75
|
+
run: (el, o, ctx) => {
|
|
76
|
+
const lid = (el.querySelector('[data-lid]') || el.firstElementChild);
|
|
77
|
+
el.setAttribute('data-open', '');
|
|
78
|
+
if (lid)
|
|
79
|
+
lid.style.transformOrigin = '50% 100%';
|
|
80
|
+
if (ctx.reduced)
|
|
81
|
+
return void (lid && (lid.style.transform = 'rotateX(110deg)'));
|
|
82
|
+
if (lid)
|
|
83
|
+
ctx.animate(lid, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(125deg)', offset: 0.6 }, { transform: 'rotateX(110deg)' }], { duration: o.duration, easing: 'cubic-bezier(.3,1.5,.6,1)', fill: 'forwards' });
|
|
84
|
+
const parts = Array.from({ length: o.count }, (_, i) => {
|
|
85
|
+
const s = floater(el, o.spark, { fontSize: '18px' });
|
|
86
|
+
const deg = -60 + (120 * i) / Math.max(1, o.count - 1);
|
|
87
|
+
const p = throwPath(deg, 90, 6, 1.2);
|
|
88
|
+
return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) scale(${(1 - k / 12).toFixed(2)})`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: 150 + i * 30, easing: 'linear' }), s, ctx);
|
|
89
|
+
});
|
|
90
|
+
return Promise.all(parts);
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'coin-burst',
|
|
95
|
+
kind: 'click',
|
|
96
|
+
description: 'Coins (`coin`) arc up out of the element and fall away (`count`, `power`).',
|
|
97
|
+
defaults: { coin: '🪙', count: 8, power: 140, duration: 900 },
|
|
98
|
+
reduced: 'skip',
|
|
99
|
+
run: (el, o, ctx) => Promise.all(Array.from({ length: o.count }, (_, i) => {
|
|
100
|
+
const s = floater(el, o.coin, { fontSize: '20px' });
|
|
101
|
+
const p = throwPath(-50 + (100 * i) / Math.max(1, o.count - 1) + (Math.random() * 10 - 5), o.power * (0.8 + Math.random() * 0.4));
|
|
102
|
+
return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) rotate(${k * 60}deg)`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: i * 25, easing: 'linear' }), s, ctx);
|
|
103
|
+
})),
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'xp-gain',
|
|
107
|
+
kind: 'enter',
|
|
108
|
+
description: 'A “+50 XP” label (`text`, or `data-xp`) floats up from the element and fades (`color`).',
|
|
109
|
+
defaults: { text: '', color: '#7c5cff', duration: 1100 },
|
|
110
|
+
reduced: 'skip',
|
|
111
|
+
run: (el, o, ctx) => {
|
|
112
|
+
const s = floater(el, o.text || `+${el.dataset.xp || 10} XP`, { font: '800 16px/1 system-ui,sans-serif', color: o.color, textShadow: '0 1px 0 #fff' });
|
|
113
|
+
return fin(ctx.animate(s, [{ transform: 'translateY(0) scale(.6)', opacity: 0 }, { transform: 'translateY(-18px) scale(1.15)', opacity: 1, offset: 0.25 }, { transform: 'translateY(-50px) scale(1)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), s, ctx);
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
/** Register the 7.5 gamification pack (idempotent). */
|
|
118
|
+
function registerGamePack() {
|
|
119
|
+
registerEffects(GAME_FX);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { GAME_FX, registerGamePack, throwPath };
|
|
123
|
+
//# sourceMappingURL=fx-game.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fx-game.js","sources":["../../src/components/fx2/game.ts"],"sourcesContent":["/**\n * 7.5 — Gamification motion (`motionary/fx/game`, also\n * `motionary/components/fx-game`):\n *\n * - `achievement-unlock` (attention) — the element slides in, a light sweep\n * crosses it and its icon (`[data-icon]` or first child) pops.\n * - `level-up` (attention) — a scale-up with a ring shockwave.\n * - `chest-open` (click) — the lid (`[data-lid]` or first child) flips open\n * and sparks fly out.\n * - `coin-burst` (click) — coins (`coin`, default 🪙) arc up and fall.\n * - `xp-gain` (enter) — a “+50 XP” label (`text` or `data-xp`) floats up and\n * fades.\n *\n * Reduced motion: unlock / level-up fade, chest-open sets the lid open,\n * coin-burst and xp-gain do nothing.\n */\nimport type { EffectContext, EffectDefinition } from '../fx/registry';\nimport { registerEffects } from '../fx/registry';\n\n/** Ballistic keyframe points for a coin thrown at `deg` with `power` (7.5). */\nexport function throwPath(deg: number, power = 120, steps = 6, g = 2.2): { x: number; y: number }[] {\n const r = (deg * Math.PI) / 180;\n const vx = Math.sin(r) * power;\n const vy = -Math.cos(r) * power;\n return Array.from({ length: steps + 1 }, (_, i) => {\n const t = i / steps;\n return { x: Math.round(vx * t), y: Math.round(vy * t + g * power * t * t * 0.5) };\n });\n}\n\nconst floater = (el: HTMLElement, text: string, css: Partial<CSSStyleDeclaration>): HTMLSpanElement => {\n const r = el.getBoundingClientRect();\n const s = document.createElement('span');\n s.setAttribute('aria-hidden', 'true');\n s.textContent = text;\n Object.assign(s.style, { position: 'fixed', left: `${r.left + r.width / 2}px`, top: `${r.top + r.height / 2}px`, pointerEvents: 'none', zIndex: '2147483000', translate: '-50% -50%' }, css);\n document.body.appendChild(s);\n return s;\n};\n\nconst fin = (a: Animation | null | undefined, el: Element, ctx: EffectContext) => {\n const end = () => el.remove();\n if (a) a.finished.then(end, end);\n else end();\n ctx.onCleanup(end);\n return a?.finished.catch(() => undefined);\n};\n\nexport const GAME_FX: EffectDefinition[] = [\n {\n name: 'achievement-unlock',\n kind: 'attention',\n description: 'The element slides in, a light sweep crosses it and its icon (`[data-icon]` or first child) pops (`duration`).',\n defaults: { duration: 900 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return ctx.animate(el, [{ opacity: 0 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n const icon = (el.querySelector('[data-icon]') || el.firstElementChild) as HTMLElement | null;\n const a = ctx.animate(el, [{ transform: 'translateY(30px) scale(.9)', opacity: 0 }, { transform: 'translateY(-4px) scale(1.02)', opacity: 1, offset: 0.5 }, { transform: 'none', opacity: 1 }], { duration: o.duration * 0.6, easing: 'cubic-bezier(.2,.9,.3,1)' });\n if (icon) ctx.animate(icon, [{ transform: 'scale(0) rotate(-30deg)' }, { transform: 'scale(1.4) rotate(10deg)', offset: 0.6 }, { transform: 'none' }], { duration: o.duration * 0.6, delay: o.duration * 0.3, easing: 'ease-out', fill: 'backwards' });\n const pos = getComputedStyle(el).position;\n if (pos === 'static') el.style.position = 'relative';\n const sh = document.createElement('span');\n sh.setAttribute('aria-hidden', 'true');\n Object.assign(sh.style, { position: 'absolute', inset: '0', borderRadius: 'inherit', pointerEvents: 'none', background: 'linear-gradient(110deg,transparent 35%,rgba(255,255,255,.7) 50%,transparent 65%)', backgroundSize: '250% 100%' });\n el.appendChild(sh);\n fin(ctx.animate(sh, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: o.duration * 0.6, delay: o.duration * 0.4, easing: 'ease-in-out', fill: 'backwards' }), sh, ctx);\n return a?.finished.catch(() => undefined);\n },\n },\n {\n name: 'level-up',\n kind: 'attention',\n description: 'A scale-up with a ring shockwave in `color` (`color`, `duration`).',\n defaults: { color: '#facc15', duration: 800 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n if (ctx.reduced) return ctx.animate(el, [{ opacity: 0.5 }, { opacity: 1 }], { duration: 250 })?.finished.catch(() => undefined);\n const r = el.getBoundingClientRect();\n const ring = floater(el, '', { width: `${Math.max(r.width, r.height)}px`, height: `${Math.max(r.width, r.height)}px`, borderRadius: '50%', border: `3px solid ${o.color}` });\n fin(ctx.animate(ring, [{ transform: 'scale(.4)', opacity: 1 }, { transform: 'scale(1.8)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), ring, ctx);\n return ctx.animate(el, [{ transform: 'scale(1)' }, { transform: 'scale(1.25)', offset: 0.3 }, { transform: 'scale(.95)', offset: 0.6 }, { transform: 'scale(1)' }], { duration: o.duration, easing: 'ease-out' })?.finished.catch(() => undefined);\n },\n },\n {\n name: 'chest-open',\n kind: 'click',\n description: 'The lid (`[data-lid]` or first child) flips open and sparks (`spark`) fly out (`count`).',\n defaults: { spark: '✨', count: 6, duration: 700 },\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const lid = (el.querySelector('[data-lid]') || el.firstElementChild) as HTMLElement | null;\n el.setAttribute('data-open', '');\n if (lid) lid.style.transformOrigin = '50% 100%';\n if (ctx.reduced) return void (lid && (lid.style.transform = 'rotateX(110deg)'));\n if (lid) ctx.animate(lid, [{ transform: 'rotateX(0)' }, { transform: 'rotateX(125deg)', offset: 0.6 }, { transform: 'rotateX(110deg)' }], { duration: o.duration, easing: 'cubic-bezier(.3,1.5,.6,1)', fill: 'forwards' });\n const parts = Array.from({ length: o.count }, (_, i) => {\n const s = floater(el, o.spark, { fontSize: '18px' });\n const deg = -60 + (120 * i) / Math.max(1, o.count - 1);\n const p = throwPath(deg, 90, 6, 1.2);\n return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) scale(${(1 - k / 12).toFixed(2)})`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: 150 + i * 30, easing: 'linear' }), s, ctx);\n });\n return Promise.all(parts);\n },\n },\n {\n name: 'coin-burst',\n kind: 'click',\n description: 'Coins (`coin`) arc up out of the element and fall away (`count`, `power`).',\n defaults: { coin: '🪙', count: 8, power: 140, duration: 900 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) =>\n Promise.all(\n Array.from({ length: o.count }, (_, i) => {\n const s = floater(el, o.coin, { fontSize: '20px' });\n const p = throwPath(-50 + (100 * i) / Math.max(1, o.count - 1) + (Math.random() * 10 - 5), o.power * (0.8 + Math.random() * 0.4));\n return fin(ctx.animate(s, p.map((q, k) => ({ transform: `translate(${q.x}px,${q.y}px) rotate(${k * 60}deg)`, opacity: k === p.length - 1 ? 0 : 1 })), { duration: o.duration, delay: i * 25, easing: 'linear' }), s, ctx);\n })\n ),\n },\n {\n name: 'xp-gain',\n kind: 'enter',\n description: 'A “+50 XP” label (`text`, or `data-xp`) floats up from the element and fades (`color`).',\n defaults: { text: '', color: '#7c5cff', duration: 1100 },\n reduced: 'skip',\n run: (el: HTMLElement, o: any, ctx: EffectContext) => {\n const s = floater(el, o.text || `+${el.dataset.xp || 10} XP`, { font: '800 16px/1 system-ui,sans-serif', color: o.color, textShadow: '0 1px 0 #fff' });\n return fin(ctx.animate(s, [{ transform: 'translateY(0) scale(.6)', opacity: 0 }, { transform: 'translateY(-18px) scale(1.15)', opacity: 1, offset: 0.25 }, { transform: 'translateY(-50px) scale(1)', opacity: 0 }], { duration: o.duration, easing: 'ease-out' }), s, ctx);\n },\n },\n];\n\n/** Register the 7.5 gamification pack (idempotent). */\nexport function registerGamePack(): void {\n registerEffects(GAME_FX);\n}\n"],"names":[],"mappings":"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"}
|