use-scroll-animate 5.8.0 → 6.0.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 +31 -0
- package/README.md +3 -2
- package/README_ja.md +1 -0
- package/README_zh.md +2 -1
- package/bin/usa-codemod-6.mjs +146 -0
- package/dist/components/angular.d.cts +5 -3
- package/dist/components/angular.d.ts +5 -3
- package/dist/components/click.cjs +2 -4
- package/dist/components/click.cjs.map +1 -1
- package/dist/components/click.d.cts +3 -8
- package/dist/components/click.d.ts +3 -8
- package/dist/components/click.js +3 -2
- package/dist/components/click.js.map +1 -1
- package/dist/components/effects.cjs +306 -1
- package/dist/components/effects.cjs.map +1 -1
- package/dist/components/effects.d.cts +66 -2
- package/dist/components/effects.d.ts +66 -2
- package/dist/components/effects.js +303 -2
- package/dist/components/effects.js.map +1 -1
- package/dist/components/fx.cjs +2 -2
- package/dist/components/fx.cjs.map +1 -1
- package/dist/components/fx.js +2 -2
- package/dist/components/fx.js.map +1 -1
- package/dist/components/lite.cjs +9 -10
- package/dist/components/lite.cjs.map +1 -1
- package/dist/components/lite.js +10 -8
- package/dist/components/lite.js.map +1 -1
- package/dist/components/page.cjs +6 -5
- package/dist/components/page.cjs.map +1 -1
- package/dist/components/page.css +1 -1
- package/dist/components/page.d.cts +4 -3
- package/dist/components/page.d.ts +4 -3
- package/dist/components/page.js +6 -5
- package/dist/components/page.js.map +1 -1
- package/dist/components/solid.d.cts +5 -3
- package/dist/components/solid.d.ts +5 -3
- package/dist/components/svelte.d.cts +5 -3
- package/dist/components/svelte.d.ts +5 -3
- package/dist/components/vue.d.cts +5 -3
- package/dist/components/vue.d.ts +5 -3
- package/dist/components.cjs +2 -5
- package/dist/components.cjs.map +1 -1
- package/dist/components.css +1 -1
- package/dist/components.d.cts +7 -11
- package/dist/components.d.ts +7 -11
- package/dist/components.js +1 -1
- package/dist/components.umd.js +2 -2
- package/dist/components.umd.js.map +1 -1
- package/docs/ROADMAP.md +12 -12
- package/docs/components.md +29 -3
- package/docs/deprecations.md +4 -0
- package/docs/performance.md +1 -1
- package/docs/upgrading-6.md +32 -0
- package/package.json +3 -2
|
@@ -414,6 +414,70 @@ interface UsaThemeElement extends UsaElement {
|
|
|
414
414
|
/** `<usa-theme name="neon | paper | glass | retro | brutalist">` — a themed subtree. */
|
|
415
415
|
declare function defineTheme(tag?: string): CustomElementConstructor | undefined;
|
|
416
416
|
|
|
417
|
+
interface AnimationTrack {
|
|
418
|
+
/** Selector inside the player (`:scope` = the player). */
|
|
419
|
+
target?: string;
|
|
420
|
+
/** Start time in ms. */
|
|
421
|
+
start?: number;
|
|
422
|
+
duration?: number;
|
|
423
|
+
/** A timeline preset (`fade-up`, `scale`, `blur`…). */
|
|
424
|
+
preset?: string;
|
|
425
|
+
keyframes?: Keyframe[];
|
|
426
|
+
easing?: string;
|
|
427
|
+
/** A registered effect fired at `start` (instead of keyframes). */
|
|
428
|
+
effect?: string;
|
|
429
|
+
options?: Record<string, unknown>;
|
|
430
|
+
label?: string;
|
|
431
|
+
}
|
|
432
|
+
interface AnimationJSON {
|
|
433
|
+
format?: string;
|
|
434
|
+
version?: number;
|
|
435
|
+
name?: string;
|
|
436
|
+
loop?: boolean;
|
|
437
|
+
/** Total length; defaults to the end of the last track. */
|
|
438
|
+
duration?: number;
|
|
439
|
+
tracks: AnimationTrack[];
|
|
440
|
+
}
|
|
441
|
+
declare const ANIMATION_FORMAT = "use-scroll-animate/animation";
|
|
442
|
+
/** Validate / normalise an animation (object or JSON text). Throws on anything unusable. */
|
|
443
|
+
declare function normalizeAnimation(input: string | AnimationJSON | Record<string, any>): Required<Pick<AnimationJSON, 'tracks' | 'duration' | 'loop' | 'name'>>;
|
|
444
|
+
interface Player {
|
|
445
|
+
readonly duration: number;
|
|
446
|
+
readonly currentTime: number;
|
|
447
|
+
readonly playing: boolean;
|
|
448
|
+
play(): void;
|
|
449
|
+
pause(): void;
|
|
450
|
+
/** Jump to `ms` (effects between are not replayed). */
|
|
451
|
+
seek(ms: number): void;
|
|
452
|
+
/** Playback rate (default 1). */
|
|
453
|
+
rate: number;
|
|
454
|
+
/** Resolves each time the animation reaches its end (not when looping). */
|
|
455
|
+
readonly finished: Promise<void>;
|
|
456
|
+
destroy(): void;
|
|
457
|
+
}
|
|
458
|
+
/** Bind an animation to `root` and return its controller (paused at 0 unless `autoplay`). */
|
|
459
|
+
declare function createPlayer(root: HTMLElement, animation: string | AnimationJSON, o?: {
|
|
460
|
+
autoplay?: boolean;
|
|
461
|
+
loop?: boolean;
|
|
462
|
+
rate?: number;
|
|
463
|
+
onFinish?: () => void;
|
|
464
|
+
}): Player;
|
|
465
|
+
interface UsaPlayerElement extends UsaElement {
|
|
466
|
+
readonly player: Player | null;
|
|
467
|
+
/** Load an animation (object or JSON text) and restart. */
|
|
468
|
+
load(animation: string | AnimationJSON): void;
|
|
469
|
+
play(): void;
|
|
470
|
+
pause(): void;
|
|
471
|
+
seek(ms: number): void;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* `<usa-player src="hero.json" | <script type="application/json"> child
|
|
475
|
+
* trigger="load | view | scroll | click | manual" loop rate controls>`.
|
|
476
|
+
* Emits `usa-player-ready` and `usa-player-finish`; sets `data-error` when the
|
|
477
|
+
* animation cannot be loaded.
|
|
478
|
+
*/
|
|
479
|
+
declare function definePlayer(tag?: string): CustomElementConstructor | undefined;
|
|
480
|
+
|
|
417
481
|
/**
|
|
418
482
|
* 5.4 — `<usa-story template="…">` scroll-storytelling templates.
|
|
419
483
|
*
|
|
@@ -477,5 +541,5 @@ declare function defineEffectElements(): void;
|
|
|
477
541
|
/** Register the built-ins and every pack (idempotent). */
|
|
478
542
|
declare function registerAllEffects(): void;
|
|
479
543
|
|
|
480
|
-
export { AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, defineAudio, defineEffectElements, defineGestureFx, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
481
|
-
export type { AudioInput, AudioReactive, AudioSample, BeatOptions, GenFrame, GenerativeSpec, GestureDetail, GestureFxOptions, GestureName, SpringOptions, StoryTemplate, ThemePack, ThemeRole, UsaAudioElement, UsaGestureFxElement, UsaStoryElement, UsaThemeElement };
|
|
544
|
+
export { ANIMATION_FORMAT, AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, createPlayer, defineAudio, defineEffectElements, defineGestureFx, definePlayer, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, normalizeAnimation, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
545
|
+
export type { AnimationJSON, AnimationTrack, AudioInput, AudioReactive, AudioSample, BeatOptions, GenFrame, GenerativeSpec, GestureDetail, GestureFxOptions, GestureName, Player, SpringOptions, StoryTemplate, ThemePack, ThemeRole, UsaAudioElement, UsaGestureFxElement, UsaPlayerElement, UsaStoryElement, UsaThemeElement };
|
|
@@ -414,6 +414,70 @@ interface UsaThemeElement extends UsaElement {
|
|
|
414
414
|
/** `<usa-theme name="neon | paper | glass | retro | brutalist">` — a themed subtree. */
|
|
415
415
|
declare function defineTheme(tag?: string): CustomElementConstructor | undefined;
|
|
416
416
|
|
|
417
|
+
interface AnimationTrack {
|
|
418
|
+
/** Selector inside the player (`:scope` = the player). */
|
|
419
|
+
target?: string;
|
|
420
|
+
/** Start time in ms. */
|
|
421
|
+
start?: number;
|
|
422
|
+
duration?: number;
|
|
423
|
+
/** A timeline preset (`fade-up`, `scale`, `blur`…). */
|
|
424
|
+
preset?: string;
|
|
425
|
+
keyframes?: Keyframe[];
|
|
426
|
+
easing?: string;
|
|
427
|
+
/** A registered effect fired at `start` (instead of keyframes). */
|
|
428
|
+
effect?: string;
|
|
429
|
+
options?: Record<string, unknown>;
|
|
430
|
+
label?: string;
|
|
431
|
+
}
|
|
432
|
+
interface AnimationJSON {
|
|
433
|
+
format?: string;
|
|
434
|
+
version?: number;
|
|
435
|
+
name?: string;
|
|
436
|
+
loop?: boolean;
|
|
437
|
+
/** Total length; defaults to the end of the last track. */
|
|
438
|
+
duration?: number;
|
|
439
|
+
tracks: AnimationTrack[];
|
|
440
|
+
}
|
|
441
|
+
declare const ANIMATION_FORMAT = "use-scroll-animate/animation";
|
|
442
|
+
/** Validate / normalise an animation (object or JSON text). Throws on anything unusable. */
|
|
443
|
+
declare function normalizeAnimation(input: string | AnimationJSON | Record<string, any>): Required<Pick<AnimationJSON, 'tracks' | 'duration' | 'loop' | 'name'>>;
|
|
444
|
+
interface Player {
|
|
445
|
+
readonly duration: number;
|
|
446
|
+
readonly currentTime: number;
|
|
447
|
+
readonly playing: boolean;
|
|
448
|
+
play(): void;
|
|
449
|
+
pause(): void;
|
|
450
|
+
/** Jump to `ms` (effects between are not replayed). */
|
|
451
|
+
seek(ms: number): void;
|
|
452
|
+
/** Playback rate (default 1). */
|
|
453
|
+
rate: number;
|
|
454
|
+
/** Resolves each time the animation reaches its end (not when looping). */
|
|
455
|
+
readonly finished: Promise<void>;
|
|
456
|
+
destroy(): void;
|
|
457
|
+
}
|
|
458
|
+
/** Bind an animation to `root` and return its controller (paused at 0 unless `autoplay`). */
|
|
459
|
+
declare function createPlayer(root: HTMLElement, animation: string | AnimationJSON, o?: {
|
|
460
|
+
autoplay?: boolean;
|
|
461
|
+
loop?: boolean;
|
|
462
|
+
rate?: number;
|
|
463
|
+
onFinish?: () => void;
|
|
464
|
+
}): Player;
|
|
465
|
+
interface UsaPlayerElement extends UsaElement {
|
|
466
|
+
readonly player: Player | null;
|
|
467
|
+
/** Load an animation (object or JSON text) and restart. */
|
|
468
|
+
load(animation: string | AnimationJSON): void;
|
|
469
|
+
play(): void;
|
|
470
|
+
pause(): void;
|
|
471
|
+
seek(ms: number): void;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* `<usa-player src="hero.json" | <script type="application/json"> child
|
|
475
|
+
* trigger="load | view | scroll | click | manual" loop rate controls>`.
|
|
476
|
+
* Emits `usa-player-ready` and `usa-player-finish`; sets `data-error` when the
|
|
477
|
+
* animation cannot be loaded.
|
|
478
|
+
*/
|
|
479
|
+
declare function definePlayer(tag?: string): CustomElementConstructor | undefined;
|
|
480
|
+
|
|
417
481
|
/**
|
|
418
482
|
* 5.4 — `<usa-story template="…">` scroll-storytelling templates.
|
|
419
483
|
*
|
|
@@ -477,5 +541,5 @@ declare function defineEffectElements(): void;
|
|
|
477
541
|
/** Register the built-ins and every pack (idempotent). */
|
|
478
542
|
declare function registerAllEffects(): void;
|
|
479
543
|
|
|
480
|
-
export { AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, defineAudio, defineEffectElements, defineGestureFx, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
481
|
-
export type { AudioInput, AudioReactive, AudioSample, BeatOptions, GenFrame, GenerativeSpec, GestureDetail, GestureFxOptions, GestureName, SpringOptions, StoryTemplate, ThemePack, ThemeRole, UsaAudioElement, UsaGestureFxElement, UsaStoryElement, UsaThemeElement };
|
|
544
|
+
export { ANIMATION_FORMAT, AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, createPlayer, defineAudio, defineEffectElements, defineGestureFx, definePlayer, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, normalizeAnimation, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
545
|
+
export type { AnimationJSON, AnimationTrack, AudioInput, AudioReactive, AudioSample, BeatOptions, GenFrame, GenerativeSpec, GestureDetail, GestureFxOptions, GestureName, Player, SpringOptions, StoryTemplate, ThemePack, ThemeRole, UsaAudioElement, UsaGestureFxElement, UsaPlayerElement, UsaStoryElement, UsaThemeElement };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { playEffect, bindEffect, registerBuiltinEffects, registerEffects } from './fx.js';
|
|
2
2
|
import { x as defineElement, p as prefersReducedMotion, u as adoptStyles } from '../chunks/base-C3Sw9sAO.js';
|
|
3
3
|
import { applyMotionTokens, motionTokensToVars, mergeMotionTokens } from './tokens.js';
|
|
4
|
-
import '../chunks/core-DN3hHbHh.js';
|
|
4
|
+
import { T as TIMELINE_PRESETS } from '../chunks/core-DN3hHbHh.js';
|
|
5
5
|
import '../chunks/fx-ChjxrMBo.js';
|
|
6
6
|
|
|
7
7
|
let layer = null;
|
|
@@ -2160,6 +2160,306 @@ function defineTheme(tag = 'usa-theme') {
|
|
|
2160
2160
|
}, { id: 'usa-theme-el', text: 'usa-theme{display:block}' });
|
|
2161
2161
|
}
|
|
2162
2162
|
|
|
2163
|
+
/**
|
|
2164
|
+
* 5.9 — `<usa-player>`: plays JSON animations.
|
|
2165
|
+
*
|
|
2166
|
+
* Format `use-scroll-animate/animation` v1:
|
|
2167
|
+
*
|
|
2168
|
+
* ```json
|
|
2169
|
+
* { "format": "use-scroll-animate/animation", "version": 1, "name": "Hero",
|
|
2170
|
+
* "loop": false,
|
|
2171
|
+
* "tracks": [
|
|
2172
|
+
* { "target": "h1", "start": 0, "duration": 600, "preset": "fade-up" },
|
|
2173
|
+
* { "target": ".cta", "start": 500, "duration": 500, "keyframes": [{ "opacity": 0 }, { "opacity": 1 }], "easing": "ease-out" },
|
|
2174
|
+
* { "target": ".cta", "start": 1100, "effect": "jelly", "options": {} }
|
|
2175
|
+
* ] }
|
|
2176
|
+
* ```
|
|
2177
|
+
*
|
|
2178
|
+
* A track animates `target` (a selector inside the player; `:scope` for the
|
|
2179
|
+
* player itself) with a timeline preset, its own keyframes, or fires any
|
|
2180
|
+
* registered effect at `start`. Playground presets (format
|
|
2181
|
+
* `use-scroll-animate/playground`) are accepted too — their tracks map to the
|
|
2182
|
+
* player's children in order.
|
|
2183
|
+
*
|
|
2184
|
+
* Keyframe tracks are WAAPI animations driven by one clock, so the player can
|
|
2185
|
+
* play, pause, seek, change rate and be scrubbed by scroll
|
|
2186
|
+
* (`trigger="scroll"`). Reduced motion: jumps to the end state, effects skipped.
|
|
2187
|
+
*/
|
|
2188
|
+
const ANIMATION_FORMAT = 'use-scroll-animate/animation';
|
|
2189
|
+
function decodePlayground(state) {
|
|
2190
|
+
try {
|
|
2191
|
+
const b64 = state.replace(/-/g, '+').replace(/_/g, '/');
|
|
2192
|
+
const json = decodeURIComponent(escape(atob(b64)));
|
|
2193
|
+
const t = (JSON.parse(json).t || []);
|
|
2194
|
+
return t.map(([preset, start, duration, label], i) => ({ target: `:scope > :nth-child(${i + 1})`, preset, start, duration, label }));
|
|
2195
|
+
}
|
|
2196
|
+
catch {
|
|
2197
|
+
return [];
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
/** Validate / normalise an animation (object or JSON text). Throws on anything unusable. */
|
|
2201
|
+
function normalizeAnimation(input) {
|
|
2202
|
+
const d = typeof input === 'string' ? JSON.parse(input) : input;
|
|
2203
|
+
if (!d || typeof d !== 'object')
|
|
2204
|
+
throw new Error('[use-scroll-animate] animation: expected an object');
|
|
2205
|
+
let tracks;
|
|
2206
|
+
if (d.format === 'use-scroll-animate/playground')
|
|
2207
|
+
tracks = decodePlayground(String(d.state || ''));
|
|
2208
|
+
else if (Array.isArray(d.tracks))
|
|
2209
|
+
tracks = d.tracks;
|
|
2210
|
+
else
|
|
2211
|
+
throw new Error('[use-scroll-animate] animation: missing "tracks"');
|
|
2212
|
+
if (d.format && d.format !== ANIMATION_FORMAT && d.format !== 'use-scroll-animate/playground')
|
|
2213
|
+
throw new Error(`[use-scroll-animate] animation: unknown format "${d.format}"`);
|
|
2214
|
+
if (d.version && d.version > 1 && d.format === ANIMATION_FORMAT)
|
|
2215
|
+
throw new Error(`[use-scroll-animate] animation: version ${d.version} needs a newer use-scroll-animate`);
|
|
2216
|
+
const out = tracks
|
|
2217
|
+
.filter((t) => t && (t.effect || t.preset || Array.isArray(t.keyframes)))
|
|
2218
|
+
.map((t) => ({ ...t, target: t.target || ':scope', start: Math.max(0, Number(t.start) || 0), duration: t.effect ? 0 : Math.max(1, Number(t.duration) || 600) }));
|
|
2219
|
+
const end = out.reduce((m, t) => Math.max(m, t.start + t.duration), 0);
|
|
2220
|
+
return { tracks: out, duration: Math.max(end, Number(d.duration) || 0), loop: !!d.loop, name: String(d.name || 'animation') };
|
|
2221
|
+
}
|
|
2222
|
+
const pick = (root, sel) => {
|
|
2223
|
+
if (sel === ':scope')
|
|
2224
|
+
return [root];
|
|
2225
|
+
try {
|
|
2226
|
+
return Array.from(root.querySelectorAll(sel));
|
|
2227
|
+
}
|
|
2228
|
+
catch {
|
|
2229
|
+
return [];
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
/** Bind an animation to `root` and return its controller (paused at 0 unless `autoplay`). */
|
|
2233
|
+
function createPlayer(root, animation, o = {}) {
|
|
2234
|
+
const a = normalizeAnimation(animation);
|
|
2235
|
+
const loop = o.loop ?? a.loop;
|
|
2236
|
+
const anims = [];
|
|
2237
|
+
const effects = [];
|
|
2238
|
+
for (const t of a.tracks) {
|
|
2239
|
+
const els = pick(root, t.target);
|
|
2240
|
+
if (t.effect)
|
|
2241
|
+
effects.push({ els, t, fired: false });
|
|
2242
|
+
else {
|
|
2243
|
+
const kf = t.keyframes || TIMELINE_PRESETS[t.preset] || TIMELINE_PRESETS.fade;
|
|
2244
|
+
for (const el of els) {
|
|
2245
|
+
if (typeof el.animate !== 'function')
|
|
2246
|
+
continue;
|
|
2247
|
+
const an = el.animate(kf, { duration: t.duration, delay: t.start, easing: t.easing || 'cubic-bezier(0.22, 1, 0.36, 1)', fill: 'both' });
|
|
2248
|
+
an.pause();
|
|
2249
|
+
an.currentTime = 0;
|
|
2250
|
+
anims.push(an);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
let time = 0;
|
|
2255
|
+
let playing = false;
|
|
2256
|
+
let raf = 0;
|
|
2257
|
+
let last = 0;
|
|
2258
|
+
let resolve;
|
|
2259
|
+
let finished = new Promise((r) => (resolve = r));
|
|
2260
|
+
const set = (ms) => {
|
|
2261
|
+
time = Math.min(a.duration, Math.max(0, ms));
|
|
2262
|
+
for (const an of anims)
|
|
2263
|
+
an.currentTime = time;
|
|
2264
|
+
};
|
|
2265
|
+
const fireDue = () => {
|
|
2266
|
+
if (prefersReducedMotion())
|
|
2267
|
+
return;
|
|
2268
|
+
for (const e of effects)
|
|
2269
|
+
if (!e.fired && time >= e.t.start) {
|
|
2270
|
+
e.fired = true;
|
|
2271
|
+
for (const el of e.els)
|
|
2272
|
+
playEffect(el, e.t.effect, e.t.options || {}).catch(() => undefined);
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
const done = () => {
|
|
2276
|
+
resolve();
|
|
2277
|
+
o.onFinish?.();
|
|
2278
|
+
finished = new Promise((r) => (resolve = r));
|
|
2279
|
+
};
|
|
2280
|
+
const frame = (now) => {
|
|
2281
|
+
raf = 0;
|
|
2282
|
+
if (!playing)
|
|
2283
|
+
return;
|
|
2284
|
+
set(time + (now - last) * player.rate);
|
|
2285
|
+
last = now;
|
|
2286
|
+
fireDue();
|
|
2287
|
+
if (time >= a.duration) {
|
|
2288
|
+
if (loop) {
|
|
2289
|
+
effects.forEach((e) => (e.fired = false));
|
|
2290
|
+
set(0);
|
|
2291
|
+
}
|
|
2292
|
+
else {
|
|
2293
|
+
playing = false;
|
|
2294
|
+
done();
|
|
2295
|
+
return;
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
raf = requestAnimationFrame(frame);
|
|
2299
|
+
};
|
|
2300
|
+
const player = {
|
|
2301
|
+
get duration() {
|
|
2302
|
+
return a.duration;
|
|
2303
|
+
},
|
|
2304
|
+
get currentTime() {
|
|
2305
|
+
return time;
|
|
2306
|
+
},
|
|
2307
|
+
get playing() {
|
|
2308
|
+
return playing;
|
|
2309
|
+
},
|
|
2310
|
+
rate: o.rate ?? 1,
|
|
2311
|
+
get finished() {
|
|
2312
|
+
return finished;
|
|
2313
|
+
},
|
|
2314
|
+
play() {
|
|
2315
|
+
if (prefersReducedMotion()) {
|
|
2316
|
+
set(a.duration);
|
|
2317
|
+
effects.forEach((e) => (e.fired = true));
|
|
2318
|
+
done();
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
if (playing)
|
|
2322
|
+
return;
|
|
2323
|
+
if (time >= a.duration) {
|
|
2324
|
+
effects.forEach((e) => (e.fired = false));
|
|
2325
|
+
set(0);
|
|
2326
|
+
}
|
|
2327
|
+
playing = true;
|
|
2328
|
+
last = performance.now();
|
|
2329
|
+
fireDue();
|
|
2330
|
+
raf = requestAnimationFrame(frame);
|
|
2331
|
+
},
|
|
2332
|
+
pause() {
|
|
2333
|
+
playing = false;
|
|
2334
|
+
cancelAnimationFrame(raf);
|
|
2335
|
+
raf = 0;
|
|
2336
|
+
},
|
|
2337
|
+
seek(ms) {
|
|
2338
|
+
set(ms);
|
|
2339
|
+
effects.forEach((e) => (e.fired = e.t.start < time));
|
|
2340
|
+
},
|
|
2341
|
+
destroy() {
|
|
2342
|
+
player.pause();
|
|
2343
|
+
anims.forEach((an) => an.cancel());
|
|
2344
|
+
},
|
|
2345
|
+
};
|
|
2346
|
+
if (o.autoplay)
|
|
2347
|
+
player.play();
|
|
2348
|
+
return player;
|
|
2349
|
+
}
|
|
2350
|
+
/**
|
|
2351
|
+
* `<usa-player src="hero.json" | <script type="application/json"> child
|
|
2352
|
+
* trigger="load | view | scroll | click | manual" loop rate controls>`.
|
|
2353
|
+
* Emits `usa-player-ready` and `usa-player-finish`; sets `data-error` when the
|
|
2354
|
+
* animation cannot be loaded.
|
|
2355
|
+
*/
|
|
2356
|
+
function definePlayer(tag = 'usa-player') {
|
|
2357
|
+
return defineElement(tag, (Base) => class UsaPlayer extends Base {
|
|
2358
|
+
constructor() {
|
|
2359
|
+
super(...arguments);
|
|
2360
|
+
this.player = null;
|
|
2361
|
+
this.json = null;
|
|
2362
|
+
}
|
|
2363
|
+
static get observedAttributes() {
|
|
2364
|
+
return ['src', 'trigger', 'loop', 'rate'];
|
|
2365
|
+
}
|
|
2366
|
+
load(animation) {
|
|
2367
|
+
this.json = animation;
|
|
2368
|
+
this.start();
|
|
2369
|
+
}
|
|
2370
|
+
play() {
|
|
2371
|
+
this.player?.play();
|
|
2372
|
+
}
|
|
2373
|
+
pause() {
|
|
2374
|
+
this.player?.pause();
|
|
2375
|
+
}
|
|
2376
|
+
seek(ms) {
|
|
2377
|
+
this.player?.seek(ms);
|
|
2378
|
+
}
|
|
2379
|
+
start() {
|
|
2380
|
+
this.player?.destroy();
|
|
2381
|
+
this.player = null;
|
|
2382
|
+
if (!this.json)
|
|
2383
|
+
return;
|
|
2384
|
+
try {
|
|
2385
|
+
this.player = createPlayer(this, this.json, {
|
|
2386
|
+
loop: this.hasAttribute('loop') ? true : undefined,
|
|
2387
|
+
rate: this.num('rate', 1),
|
|
2388
|
+
onFinish: () => this.dispatchEvent(new CustomEvent('usa-player-finish', { bubbles: true })),
|
|
2389
|
+
});
|
|
2390
|
+
this.removeAttribute('data-error');
|
|
2391
|
+
}
|
|
2392
|
+
catch (err) {
|
|
2393
|
+
this.setAttribute('data-error', String(err.message || err));
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
const p = this.player;
|
|
2397
|
+
this.dispatchEvent(new CustomEvent('usa-player-ready', { detail: { duration: p.duration }, bubbles: true }));
|
|
2398
|
+
const trig = this.str('trigger', 'view');
|
|
2399
|
+
if (trig === 'load')
|
|
2400
|
+
p.play();
|
|
2401
|
+
else if (trig === 'view')
|
|
2402
|
+
this.inView((v) => v && p.play(), { threshold: 0.25 });
|
|
2403
|
+
else if (trig === 'click')
|
|
2404
|
+
this.listen(this, 'click', () => (p.playing ? p.pause() : p.play()));
|
|
2405
|
+
else if (trig === 'scroll') {
|
|
2406
|
+
let f = 0;
|
|
2407
|
+
const upd = () => {
|
|
2408
|
+
f = 0;
|
|
2409
|
+
p.seek(storyProgress(this) * p.duration);
|
|
2410
|
+
};
|
|
2411
|
+
const kick = () => void (f || (f = requestAnimationFrame(upd)));
|
|
2412
|
+
this.listen(window, 'scroll', kick, { passive: true });
|
|
2413
|
+
this.listen(window, 'resize', kick);
|
|
2414
|
+
this.onCleanup(() => cancelAnimationFrame(f));
|
|
2415
|
+
upd();
|
|
2416
|
+
}
|
|
2417
|
+
if (this.flag('controls'))
|
|
2418
|
+
this.mountControls(p);
|
|
2419
|
+
}
|
|
2420
|
+
mountControls(p) {
|
|
2421
|
+
const b = document.createElement('button');
|
|
2422
|
+
b.type = 'button';
|
|
2423
|
+
b.setAttribute('data-player-toggle', '');
|
|
2424
|
+
b.textContent = '▶︎ / ❚❚';
|
|
2425
|
+
b.setAttribute('aria-label', 'Play / pause animation');
|
|
2426
|
+
this.listen(b, 'click', (e) => {
|
|
2427
|
+
e.stopPropagation();
|
|
2428
|
+
if (p.playing)
|
|
2429
|
+
p.pause();
|
|
2430
|
+
else
|
|
2431
|
+
p.play();
|
|
2432
|
+
b.setAttribute('aria-pressed', String(p.playing));
|
|
2433
|
+
});
|
|
2434
|
+
this.append(b);
|
|
2435
|
+
this.onCleanup(() => b.remove());
|
|
2436
|
+
}
|
|
2437
|
+
changed(name) {
|
|
2438
|
+
if (name === 'src')
|
|
2439
|
+
this.json = null;
|
|
2440
|
+
super.changed(name);
|
|
2441
|
+
}
|
|
2442
|
+
mount() {
|
|
2443
|
+
this.onCleanup(() => {
|
|
2444
|
+
this.player?.destroy();
|
|
2445
|
+
this.player = null;
|
|
2446
|
+
});
|
|
2447
|
+
const inline = this.querySelector('script[type="application/json"]');
|
|
2448
|
+
const src = this.str('src');
|
|
2449
|
+
if (inline && !this.json)
|
|
2450
|
+
this.json = inline.textContent || '';
|
|
2451
|
+
if (src && !this.json) {
|
|
2452
|
+
fetch(src)
|
|
2453
|
+
.then((r) => (r.ok ? r.text() : Promise.reject(new Error(`HTTP ${r.status}`))))
|
|
2454
|
+
.then((t) => this.isConnected && this.load(t))
|
|
2455
|
+
.catch((err) => this.setAttribute('data-error', String(err.message || err)));
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
this.start();
|
|
2459
|
+
}
|
|
2460
|
+
}, { id: 'usa-player', text: 'usa-player{display:block;position:relative}usa-player>script{display:none}usa-player [data-player-toggle]{position:absolute;right:8px;bottom:8px}' });
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2163
2463
|
/**
|
|
2164
2464
|
* use-scroll-animate/components/effects — the 5.x effect packs, all
|
|
2165
2465
|
* registered through `registerEffect()` (5.0) and playable with
|
|
@@ -2218,6 +2518,7 @@ function defineEffectElements() {
|
|
|
2218
2518
|
defineAudio();
|
|
2219
2519
|
defineGestureFx();
|
|
2220
2520
|
defineTheme();
|
|
2521
|
+
definePlayer();
|
|
2221
2522
|
}
|
|
2222
2523
|
/** Register the built-ins and every pack (idempotent). */
|
|
2223
2524
|
function registerAllEffects() {
|
|
@@ -2226,5 +2527,5 @@ function registerAllEffects() {
|
|
|
2226
2527
|
registerEffects(defs);
|
|
2227
2528
|
}
|
|
2228
2529
|
|
|
2229
|
-
export { AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, defineAudio, defineEffectElements, defineGestureFx, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
2530
|
+
export { ANIMATION_FORMAT, AUDIO_FX, CARD_FX, CLICK_FX, CURSOR_FX, EFFECT_PACKS, GENERATIVE_FX, GESTURES, MICRO_FX, PAGE_FX, PHYSICS_FX, STORY_TEMPLATES, THEMES, THEME_FX, THEME_NAMES, THEME_ROLES, angleDelta, applyTheme, bindBeat, bindGesture, bounceKeyframes, bumpCount, canvasBackground, createBeatDetector, createPlayer, defineAudio, defineEffectElements, defineGestureFx, definePlayer, defineStory, defineTheme, disableAudio, enableAudio, flingVelocity, formatCount, fxLayer, getAudio, hexRgb, noise2, normalizeAnimation, onBeat, playThemeEffect, registerAllEffects, registerAudioEffects, registerCardClickEffects, registerCursorEffects, registerGenerativeEffects, registerMicroEffects, registerPageEffects, registerPhysicsEffects, solveSpring, springKeyframes, storyProgress, swapLabel, themeCss, themePreset, themeVars, togglePressed };
|
|
2230
2531
|
//# sourceMappingURL=effects.js.map
|