motionary 6.9.0 → 7.1.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.
Files changed (204) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -2
  3. package/README_ja.md +2 -2
  4. package/README_zh.md +2 -2
  5. package/dist/chunks/audio-DcPvT2Kh.js +333 -0
  6. package/dist/chunks/audio-DcPvT2Kh.js.map +1 -0
  7. package/dist/chunks/audio-EXUoijsG.cjs +342 -0
  8. package/dist/chunks/audio-EXUoijsG.cjs.map +1 -0
  9. package/dist/chunks/{base-D5MHqeDd.js → base-2-yYc93C.js} +2 -2
  10. package/dist/chunks/{base-D5MHqeDd.js.map → base-2-yYc93C.js.map} +1 -1
  11. package/dist/chunks/{core-DyJu5r5a.js → core-D5rU0CV6.js} +2 -2
  12. package/dist/chunks/{core-DyJu5r5a.js.map → core-D5rU0CV6.js.map} +1 -1
  13. package/dist/chunks/{core-ZGo4hOEk.js → core-DuO-AVXL.js} +2 -2
  14. package/dist/chunks/{core-ZGo4hOEk.js.map → core-DuO-AVXL.js.map} +1 -1
  15. package/dist/chunks/{fx-DlGRMJ-Z.js → fx-CMxWNwH8.js} +2 -2
  16. package/dist/chunks/{fx-DlGRMJ-Z.js.map → fx-CMxWNwH8.js.map} +1 -1
  17. package/dist/chunks/{gpu-DPhMkJq6.js → gpu-DLPghVWr.js} +183 -11
  18. package/dist/chunks/gpu-DLPghVWr.js.map +1 -0
  19. package/dist/chunks/{gpu-C2D4T9Q-.cjs → gpu-Dx0H875w.cjs} +185 -9
  20. package/dist/chunks/gpu-Dx0H875w.cjs.map +1 -0
  21. package/dist/chunks/{index-tags-wv0R_vkO.cjs → index-tags-BTMwrfgV.cjs} +3 -3
  22. package/dist/chunks/index-tags-BTMwrfgV.cjs.map +1 -0
  23. package/dist/chunks/{index-tags-DucKMQr_.js → index-tags-C04JP8g4.js} +3 -3
  24. package/dist/chunks/index-tags-C04JP8g4.js.map +1 -0
  25. package/dist/chunks/{player-DH3TIz-t.js → player-DxvCYo7Q.js} +4 -4
  26. package/dist/chunks/{player-DH3TIz-t.js.map → player-DxvCYo7Q.js.map} +1 -1
  27. package/dist/chunks/{registry-CTLWeg-J.js → registry-CyKExAmE.js} +2 -2
  28. package/dist/chunks/{registry-CTLWeg-J.js.map → registry-CyKExAmE.js.map} +1 -1
  29. package/dist/chunks/{spring-B-9MZOrW.js → spring-BK8DiezC.js} +2 -2
  30. package/dist/chunks/{spring-B-9MZOrW.js.map → spring-BK8DiezC.js.map} +1 -1
  31. package/dist/chunks/{variants-CoZn3k_5.js → variants-BQ6bhzn4.js} +2 -2
  32. package/dist/chunks/{variants-CoZn3k_5.js.map → variants-BQ6bhzn4.js.map} +1 -1
  33. package/dist/components/a11y.cjs +1 -1
  34. package/dist/components/a11y.d.cts +2 -2
  35. package/dist/components/a11y.d.ts +2 -2
  36. package/dist/components/a11y.js +3 -3
  37. package/dist/components/angular.cjs +2 -2
  38. package/dist/components/angular.cjs.map +1 -1
  39. package/dist/components/angular.d.cts +5 -36
  40. package/dist/components/angular.d.ts +5 -36
  41. package/dist/components/angular.js +9 -9
  42. package/dist/components/angular.js.map +1 -1
  43. package/dist/components/background.js +2 -2
  44. package/dist/components/bridge.js +1 -1
  45. package/dist/components/cards.js +2 -2
  46. package/dist/components/click.js +3 -3
  47. package/dist/components/depth.js +3 -3
  48. package/dist/components/effects.cjs +11 -336
  49. package/dist/components/effects.cjs.map +1 -1
  50. package/dist/components/effects.js +9 -333
  51. package/dist/components/effects.js.map +1 -1
  52. package/dist/components/feedback.js +1 -1
  53. package/dist/components/fx-3d.cjs +1 -7
  54. package/dist/components/fx-3d.cjs.map +1 -1
  55. package/dist/components/fx-3d.d.cts +1 -3
  56. package/dist/components/fx-3d.d.ts +1 -3
  57. package/dist/components/fx-3d.js +3 -8
  58. package/dist/components/fx-3d.js.map +1 -1
  59. package/dist/components/fx-focus.js +2 -2
  60. package/dist/components/fx-gpu.cjs +2 -3
  61. package/dist/components/fx-gpu.cjs.map +1 -1
  62. package/dist/components/fx-gpu.d.cts +1 -3
  63. package/dist/components/fx-gpu.d.ts +1 -3
  64. package/dist/components/fx-gpu.js +3 -3
  65. package/dist/components/fx-light.cjs +1 -7
  66. package/dist/components/fx-light.cjs.map +1 -1
  67. package/dist/components/fx-light.d.cts +1 -3
  68. package/dist/components/fx-light.d.ts +1 -3
  69. package/dist/components/fx-light.js +3 -8
  70. package/dist/components/fx-light.js.map +1 -1
  71. package/dist/components/fx-morph.cjs +1 -7
  72. package/dist/components/fx-morph.cjs.map +1 -1
  73. package/dist/components/fx-morph.d.cts +1 -3
  74. package/dist/components/fx-morph.d.ts +1 -3
  75. package/dist/components/fx-morph.js +3 -8
  76. package/dist/components/fx-morph.js.map +1 -1
  77. package/dist/components/fx-music.cjs +179 -0
  78. package/dist/components/fx-music.cjs.map +1 -0
  79. package/dist/components/fx-music.d.cts +102 -0
  80. package/dist/components/fx-music.d.ts +102 -0
  81. package/dist/components/fx-music.js +174 -0
  82. package/dist/components/fx-music.js.map +1 -0
  83. package/dist/components/fx-physics.cjs +1 -7
  84. package/dist/components/fx-physics.cjs.map +1 -1
  85. package/dist/components/fx-physics.d.cts +1 -3
  86. package/dist/components/fx-physics.d.ts +1 -3
  87. package/dist/components/fx-physics.js +3 -8
  88. package/dist/components/fx-physics.js.map +1 -1
  89. package/dist/components/fx-text.cjs +1 -7
  90. package/dist/components/fx-text.cjs.map +1 -1
  91. package/dist/components/fx-text.d.cts +1 -3
  92. package/dist/components/fx-text.d.ts +1 -3
  93. package/dist/components/fx-text.js +3 -8
  94. package/dist/components/fx-text.js.map +1 -1
  95. package/dist/components/fx-transitions.cjs +1 -7
  96. package/dist/components/fx-transitions.cjs.map +1 -1
  97. package/dist/components/fx-transitions.d.cts +1 -3
  98. package/dist/components/fx-transitions.d.ts +1 -3
  99. package/dist/components/fx-transitions.js +4 -9
  100. package/dist/components/fx-transitions.js.map +1 -1
  101. package/dist/components/fx-weather.cjs +1 -7
  102. package/dist/components/fx-weather.cjs.map +1 -1
  103. package/dist/components/fx-weather.d.cts +1 -3
  104. package/dist/components/fx-weather.d.ts +1 -3
  105. package/dist/components/fx-weather.js +3 -8
  106. package/dist/components/fx-weather.js.map +1 -1
  107. package/dist/components/fx.js +5 -5
  108. package/dist/components/fx2.cjs +15 -19
  109. package/dist/components/fx2.cjs.map +1 -1
  110. package/dist/components/fx2.d.cts +97 -22
  111. package/dist/components/fx2.d.ts +97 -22
  112. package/dist/components/fx2.js +16 -19
  113. package/dist/components/fx2.js.map +1 -1
  114. package/dist/components/gesture.js +4 -4
  115. package/dist/components/interaction.cjs +11 -95
  116. package/dist/components/interaction.cjs.map +1 -1
  117. package/dist/components/interaction.css +0 -1
  118. package/dist/components/interaction.d.cts +3 -21
  119. package/dist/components/interaction.d.ts +3 -21
  120. package/dist/components/interaction.js +13 -96
  121. package/dist/components/interaction.js.map +1 -1
  122. package/dist/components/jsx.d.cts +2 -2
  123. package/dist/components/jsx.d.ts +2 -2
  124. package/dist/components/layout.js +1 -1
  125. package/dist/components/lazy.cjs +1 -1
  126. package/dist/components/lazy.d.cts +2 -2
  127. package/dist/components/lazy.d.ts +2 -2
  128. package/dist/components/lazy.js +1 -1
  129. package/dist/components/lite.cjs +115 -258
  130. package/dist/components/lite.cjs.map +1 -1
  131. package/dist/components/lite.js +116 -257
  132. package/dist/components/lite.js.map +1 -1
  133. package/dist/components/marketplace.js +2 -2
  134. package/dist/components/packs.js +1 -1
  135. package/dist/components/page.js +3 -3
  136. package/dist/components/perf.cjs +1 -1
  137. package/dist/components/perf.d.cts +2 -2
  138. package/dist/components/perf.d.ts +2 -2
  139. package/dist/components/perf.js +3 -3
  140. package/dist/components/physics.js +3 -3
  141. package/dist/components/react.cjs +2 -2
  142. package/dist/components/react.cjs.map +1 -1
  143. package/dist/components/react.js +2 -2
  144. package/dist/components/react.js.map +1 -1
  145. package/dist/components/reveal.js +1 -1
  146. package/dist/components/solid.cjs +2 -2
  147. package/dist/components/solid.cjs.map +1 -1
  148. package/dist/components/solid.d.cts +4 -35
  149. package/dist/components/solid.d.ts +4 -35
  150. package/dist/components/solid.js +9 -9
  151. package/dist/components/solid.js.map +1 -1
  152. package/dist/components/svelte.cjs +2 -2
  153. package/dist/components/svelte.cjs.map +1 -1
  154. package/dist/components/svelte.d.cts +5 -36
  155. package/dist/components/svelte.d.ts +5 -36
  156. package/dist/components/svelte.js +9 -9
  157. package/dist/components/svelte.js.map +1 -1
  158. package/dist/components/svg.js +1 -1
  159. package/dist/components/text.js +2 -2
  160. package/dist/components/timeline.js +3 -3
  161. package/dist/components/transitions.js +1 -1
  162. package/dist/components/ui.cjs +16 -75
  163. package/dist/components/ui.cjs.map +1 -1
  164. package/dist/components/ui.css +0 -1
  165. package/dist/components/ui.d.cts +3 -18
  166. package/dist/components/ui.d.ts +3 -18
  167. package/dist/components/ui.js +21 -79
  168. package/dist/components/ui.js.map +1 -1
  169. package/dist/components/vue.cjs +2 -2
  170. package/dist/components/vue.cjs.map +1 -1
  171. package/dist/components/vue.d.cts +5 -36
  172. package/dist/components/vue.d.ts +5 -36
  173. package/dist/components/vue.js +9 -9
  174. package/dist/components/vue.js.map +1 -1
  175. package/dist/components/webgl.js +1 -1
  176. package/dist/components/widgets.cjs +542 -61
  177. package/dist/components/widgets.cjs.map +1 -1
  178. package/dist/components/widgets.d.cts +79 -2
  179. package/dist/components/widgets.d.ts +79 -2
  180. package/dist/components/widgets.js +542 -67
  181. package/dist/components/widgets.js.map +1 -1
  182. package/dist/components.cjs +1 -3
  183. package/dist/components.cjs.map +1 -1
  184. package/dist/components.css +0 -2
  185. package/dist/components.d.cts +6 -39
  186. package/dist/components.d.ts +6 -39
  187. package/dist/components.js +12 -12
  188. package/dist/components.umd.js +2 -2
  189. package/dist/components.umd.js.map +1 -1
  190. package/dist/index.js +2 -2
  191. package/dist/widgets.umd.js +1 -1
  192. package/dist/widgets.umd.js.map +1 -1
  193. package/docs/ROADMAP.md +12 -12
  194. package/docs/accessibility.md +2 -2
  195. package/docs/components.md +38 -2
  196. package/docs/frameworks-ssr.md +4 -4
  197. package/docs/hybrid-apps.md +2 -2
  198. package/docs/upgrading-7.md +11 -1
  199. package/docs/windows-apps.md +1 -1
  200. package/package.json +131 -1
  201. package/dist/chunks/gpu-C2D4T9Q-.cjs.map +0 -1
  202. package/dist/chunks/gpu-DPhMkJq6.js.map +0 -1
  203. package/dist/chunks/index-tags-DucKMQr_.js.map +0 -1
  204. package/dist/chunks/index-tags-wv0R_vkO.cjs.map +0 -1
@@ -4,6 +4,7 @@ var components_fx = require('./fx.cjs');
4
4
  var shared = require('../chunks/shared-jkgRH-Hx.cjs');
5
5
  var player = require('../chunks/player-PS6_FzNw.cjs');
6
6
  var generative = require('../chunks/generative-BHIj-NU0.cjs');
7
+ var audio = require('../chunks/audio-EXUoijsG.cjs');
7
8
  var registry = require('../chunks/registry-DehBVRDV.cjs');
8
9
  var base = require('../chunks/base-BaQV-2ha.cjs');
9
10
  var components_tokens = require('./tokens.cjs');
@@ -575,332 +576,6 @@ const PAGE_FX = [
575
576
  },
576
577
  ];
577
578
 
578
- let actx = null;
579
- let current = null;
580
- const mediaSources = new WeakMap();
581
- /** The running analyser, if `enableAudio()` was called. */
582
- const getAudio = () => current;
583
- function audioContext() {
584
- const AC = globalThis.AudioContext || globalThis.webkitAudioContext;
585
- if (!AC)
586
- throw new Error('[motionary] Web Audio is not available');
587
- if (!actx || actx.state === 'closed')
588
- actx = new AC();
589
- return actx;
590
- }
591
- /**
592
- * Start analysing `input` and make it the source of every sound-reactive
593
- * effect. Call from a user gesture. Replaces a previous source.
594
- */
595
- async function enableAudio(input = 'mic', opts = {}) {
596
- current?.stop();
597
- const ac = audioContext();
598
- if (ac.state === 'suspended')
599
- await ac.resume().catch(() => undefined);
600
- const analyser = ac.createAnalyser();
601
- analyser.fftSize = opts.fftSize || 512;
602
- analyser.smoothingTimeConstant = opts.smoothing ?? 0.8;
603
- let src;
604
- let release = () => { };
605
- const media = typeof input === 'string' && input !== 'mic' ? document.querySelector(input) : input;
606
- if (media === 'mic') {
607
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
608
- src = ac.createMediaStreamSource(stream);
609
- src.connect(analyser); // never to the speakers: no feedback
610
- release = () => stream.getTracks().forEach((t) => t.stop());
611
- }
612
- else if (media && typeof media.play === 'function') {
613
- const m = media;
614
- let node = mediaSources.get(m);
615
- if (!node)
616
- mediaSources.set(m, (node = ac.createMediaElementSource(m)));
617
- try {
618
- node.disconnect();
619
- }
620
- catch {
621
- /* not connected */
622
- }
623
- src = node;
624
- src.connect(analyser);
625
- analyser.connect(ac.destination);
626
- release = () => {
627
- try {
628
- node.disconnect();
629
- }
630
- catch {
631
- /* already */
632
- }
633
- node.connect(ac.destination); // keep the media audible
634
- };
635
- if (m.paused)
636
- await m.play()?.catch?.(() => undefined);
637
- }
638
- else if (media && typeof media.getTracks === 'function') {
639
- src = ac.createMediaStreamSource(media);
640
- src.connect(analyser);
641
- }
642
- else
643
- throw new Error(`[motionary] enableAudio: no audio source for ${String(input)}`);
644
- const freq = new Uint8Array(analyser.frequencyBinCount);
645
- const wave = new Uint8Array(analyser.fftSize);
646
- const self = {
647
- context: ac,
648
- analyser,
649
- sample: () => {
650
- analyser.getByteFrequencyData(freq);
651
- analyser.getByteTimeDomainData(wave);
652
- let sq = 0;
653
- for (let i = 0; i < wave.length; i++)
654
- sq += ((wave[i] - 128) / 128) ** 2;
655
- const n = Math.max(1, Math.round(freq.length * 0.08));
656
- let b = 0;
657
- for (let i = 0; i < n; i++)
658
- b += freq[i];
659
- return { level: Math.min(1, Math.sqrt(sq / wave.length) * 2), bass: b / n / 255, freq, wave };
660
- },
661
- stop: () => {
662
- if (current === self) {
663
- current = null;
664
- if (raf && typeof cancelAnimationFrame === 'function')
665
- cancelAnimationFrame(raf);
666
- raf = 0;
667
- }
668
- try {
669
- src.disconnect();
670
- analyser.disconnect();
671
- }
672
- catch {
673
- /* already */
674
- }
675
- release();
676
- setVars(0, 0);
677
- },
678
- };
679
- current = self;
680
- kick();
681
- return self;
682
- }
683
- /** Stop the current audio source (if any). */
684
- function disableAudio() {
685
- current?.stop();
686
- }
687
- /** A pure beat detector: feed it energy (0–1) and a timestamp per frame; it answers "beat?". */
688
- function createBeatDetector(o = {}) {
689
- const { threshold = 1.35, cooldown = 250, history = 43, floor = 0.08 } = o;
690
- const hist = [];
691
- let last = -Infinity;
692
- return (energy, now) => {
693
- const avg = hist.length ? hist.reduce((a, b) => a + b, 0) / hist.length : energy;
694
- const ready = hist.length >= 8;
695
- hist.push(energy);
696
- if (hist.length > history)
697
- hist.shift();
698
- if (ready && energy > floor && energy > avg * threshold && now - last >= cooldown) {
699
- last = now;
700
- return true;
701
- }
702
- return false;
703
- };
704
- }
705
- const listeners = new Set();
706
- let raf = 0;
707
- function setVars(level, bass) {
708
- if (typeof document === 'undefined')
709
- return;
710
- const s = document.documentElement.style;
711
- s.setProperty('--usa-audio-level', level.toFixed(3));
712
- s.setProperty('--usa-audio-bass', bass.toFixed(3));
713
- }
714
- function loop(now) {
715
- raf = 0;
716
- if (!current)
717
- return;
718
- const { level, bass } = current.sample();
719
- const reduced = base.prefersReducedMotion();
720
- setVars(reduced ? 0 : level, reduced ? 0 : bass);
721
- for (const l of Array.from(listeners))
722
- if (l.detect(bass, now))
723
- l.cb({ energy: bass, time: now });
724
- kick();
725
- }
726
- function kick() {
727
- if (!raf && current && typeof requestAnimationFrame === 'function')
728
- raf = requestAnimationFrame(loop);
729
- }
730
- /** Call `cb` on every detected beat of the current audio source. Returns an unsubscribe. */
731
- function onBeat(cb, o = {}) {
732
- const l = { detect: createBeatDetector(o), cb };
733
- listeners.add(l);
734
- kick();
735
- return () => void listeners.delete(l);
736
- }
737
- /** Play the registered effect `name` on `el` at every beat (not under reduced motion). Returns an unbind. */
738
- function bindBeat(el, name, options = {}) {
739
- const { threshold, cooldown, history, floor, ...fx } = options;
740
- return onBeat(() => {
741
- if (!base.prefersReducedMotion())
742
- registry.playEffect(el, name, fx).catch(() => undefined);
743
- }, { threshold, cooldown, history, floor });
744
- }
745
- // --- visual effects ----------------------------------------------------------
746
- /** The current sample, or a gentle synthetic one while no audio is enabled. */
747
- function read(t, bins) {
748
- if (current)
749
- return { ...current.sample(), idle: false };
750
- const freq = new Uint8Array(bins);
751
- const wave = new Uint8Array(bins * 2);
752
- for (let i = 0; i < bins; i++)
753
- freq[i] = 70 + 50 * Math.sin(t * 2 + i * 0.35) * Math.cos(t * 0.7 + i * 0.11) * (1 - i / bins);
754
- for (let i = 0; i < wave.length; i++)
755
- wave[i] = 128 + 22 * Math.sin(t * 3 + i * 0.12);
756
- return { level: 0.25 + 0.1 * Math.sin(t * 2), bass: 0.35 + 0.2 * Math.sin(t * 2.4), freq, wave, idle: true };
757
- }
758
- const audioFx = (name, description, defaults, spec) => ({
759
- name,
760
- kind: 'background',
761
- description,
762
- reduced: 'skip',
763
- defaults: { colors: shared.PALETTE, background: '#0b0d12', speed: 1, quality: 1, ...defaults },
764
- run: (el, o, ctx) => generative.canvasBackground(el, ctx, spec, o),
765
- });
766
- const AUDIO_FX = [
767
- audioFx('spectrum-bars', 'Frequency bars dance to the audio (mirror them with `mirror: true`).', { bars: 48, gap: 2, mirror: false }, {
768
- draw: ({ ctx, w, h, t, o }) => {
769
- ctx.fillStyle = o.background;
770
- ctx.fillRect(0, 0, w, h);
771
- const s = read(t, o.bars);
772
- const per = Math.max(1, Math.floor((s.freq.length * 0.7) / o.bars));
773
- const bw = w / o.bars;
774
- for (let i = 0; i < o.bars; i++) {
775
- let v = 0;
776
- for (let k = 0; k < per; k++)
777
- v += s.freq[Math.min(s.freq.length - 1, i * per + k)];
778
- const bh = (v / per / 255) * h * (o.mirror ? 0.5 : 0.9);
779
- ctx.fillStyle = o.colors[i % o.colors.length];
780
- ctx.fillRect(i * bw + o.gap / 2, o.mirror ? h / 2 - bh : h - bh, Math.max(1, bw - o.gap), o.mirror ? bh * 2 : bh);
781
- }
782
- },
783
- }),
784
- audioFx('pulse-ring', 'Glowing rings pulse with the bass.', { rings: 3, color: '#7c5cff' }, {
785
- draw: ({ ctx, w, h, t, o }) => {
786
- ctx.fillStyle = o.background;
787
- ctx.fillRect(0, 0, w, h);
788
- const s = read(t, 32);
789
- const [r, g, b] = generative.hexRgb(o.color);
790
- const base = Math.min(w, h) * 0.18;
791
- for (let i = 0; i < o.rings; i++) {
792
- const rad = base * (1 + i * 0.55) * (1 + s.bass * 0.6);
793
- ctx.strokeStyle = `rgba(${r},${g},${b},${(0.9 - i * 0.25) * (0.4 + s.level)})`;
794
- ctx.lineWidth = 3 + s.bass * 10 - i;
795
- ctx.beginPath();
796
- ctx.arc(w / 2, h / 2, rad, 0, Math.PI * 2);
797
- ctx.stroke();
798
- }
799
- },
800
- }),
801
- audioFx('wave-ring', 'The live waveform wrapped into a circle.', { color: '#22d3ee', amplitude: 0.35 }, {
802
- draw: ({ ctx, w, h, t, o }) => {
803
- ctx.fillStyle = o.background;
804
- ctx.fillRect(0, 0, w, h);
805
- const s = read(t, 64);
806
- const n = s.wave.length;
807
- const base = Math.min(w, h) * 0.28;
808
- ctx.strokeStyle = o.color;
809
- ctx.lineWidth = 2;
810
- ctx.beginPath();
811
- for (let i = 0; i <= n; i++) {
812
- const a = (i / n) * Math.PI * 2;
813
- const rad = base * (1 + ((s.wave[i % n] - 128) / 128) * o.amplitude * 2);
814
- const x = w / 2 + Math.cos(a) * rad;
815
- const y = h / 2 + Math.sin(a) * rad;
816
- if (i)
817
- ctx.lineTo(x, y);
818
- else
819
- ctx.moveTo(x, y);
820
- }
821
- ctx.closePath();
822
- ctx.stroke();
823
- },
824
- }),
825
- ];
826
- /**
827
- * `<usa-audio source="#track | mic" label="…">` — a toggle button (yours, as
828
- * `[data-audio-toggle]`, or one it renders) that enables the audio source on
829
- * click; children with `data-usa-beat="effect"` play that effect on every
830
- * beat (`data-usa-beat-options` JSON; `threshold` / `cooldown` attributes).
831
- * Emits `usa-beat` and `usa-audio-error`.
832
- */
833
- function defineAudio(tag = 'usa-audio') {
834
- return base.defineElement(tag, (Base) => class UsaAudio extends Base {
835
- constructor() {
836
- super(...arguments);
837
- this.active = false;
838
- this.audio = null;
839
- this.off = null;
840
- }
841
- static get observedAttributes() {
842
- return ['source'];
843
- }
844
- button() {
845
- let b = this.querySelector('[data-audio-toggle]');
846
- if (!b) {
847
- b = document.createElement('button');
848
- b.type = 'button';
849
- b.setAttribute('data-audio-toggle', '');
850
- b.textContent = this.str('label', '🔊 Enable sound-reactive effects');
851
- this.prepend(b);
852
- this.onCleanup(() => b.remove());
853
- }
854
- return b;
855
- }
856
- async toggle() {
857
- const b = this.button();
858
- if (this.active)
859
- return this.stop();
860
- try {
861
- this.audio = await enableAudio(this.str('source', 'mic'));
862
- this.active = true;
863
- this.removeAttribute('data-audio-error');
864
- b.setAttribute('aria-pressed', 'true');
865
- this.off = onBeat((d) => {
866
- this.dispatchEvent(new CustomEvent('usa-beat', { detail: d, bubbles: true }));
867
- if (base.prefersReducedMotion())
868
- return;
869
- this.querySelectorAll('[data-usa-beat]').forEach((el) => {
870
- let opts = {};
871
- try {
872
- opts = JSON.parse(el.dataset.usaBeatOptions || '{}') || {};
873
- }
874
- catch {
875
- /* ignore bad JSON */
876
- }
877
- registry.playEffect(el, el.dataset.usaBeat || 'pulse', opts).catch(() => undefined);
878
- });
879
- }, { threshold: this.num('threshold', 1.35), cooldown: this.num('cooldown', 250) });
880
- }
881
- catch (err) {
882
- this.setAttribute('data-audio-error', '');
883
- this.dispatchEvent(new CustomEvent('usa-audio-error', { detail: { error: err }, bubbles: true }));
884
- }
885
- }
886
- stop() {
887
- this.off?.();
888
- this.off = null;
889
- if (this.audio && current === this.audio)
890
- this.audio.stop();
891
- this.audio = null;
892
- this.active = false;
893
- this.querySelector('[data-audio-toggle]')?.setAttribute('aria-pressed', 'false');
894
- }
895
- mount() {
896
- const b = this.button();
897
- b.setAttribute('aria-pressed', 'false');
898
- this.listen(b, 'click', () => void this.toggle());
899
- this.onCleanup(() => this.stop());
900
- }
901
- }, { id: 'usa-audio', text: 'usa-audio{display:block}usa-audio[data-audio-error] [data-audio-toggle]{outline:2px solid #ff5c8a}' });
902
- }
903
-
904
579
  const touchOk = (e, o) => o.touch || e.pointerType !== 'touch';
905
580
  /** A fixed, viewport-sized canvas in the fx layer, redrawn while `draw` returns true. */
906
581
  function overlayCanvas(draw) {
@@ -1640,7 +1315,7 @@ const EFFECT_PACKS = {
1640
1315
  physics: PHYSICS_FX,
1641
1316
  page: PAGE_FX,
1642
1317
  generative: generative.GENERATIVE_FX,
1643
- audio: AUDIO_FX,
1318
+ audio: audio.AUDIO_FX,
1644
1319
  cursor: CURSOR_FX,
1645
1320
  micro: MICRO_FX,
1646
1321
  themes: THEME_FX,
@@ -1677,7 +1352,7 @@ function registerMicroEffects() {
1677
1352
  /** Define the 5.x elements of this entry (`<usa-story>`, …) under their default tags. */
1678
1353
  function defineEffectElements() {
1679
1354
  player.defineStory();
1680
- defineAudio();
1355
+ audio.defineAudio();
1681
1356
  defineGestureFx();
1682
1357
  defineTheme();
1683
1358
  player.definePlayer();
@@ -1702,7 +1377,14 @@ exports.GENERATIVE_FX = generative.GENERATIVE_FX;
1702
1377
  exports.canvasBackground = generative.canvasBackground;
1703
1378
  exports.hexRgb = generative.hexRgb;
1704
1379
  exports.noise2 = generative.noise2;
1705
- exports.AUDIO_FX = AUDIO_FX;
1380
+ exports.AUDIO_FX = audio.AUDIO_FX;
1381
+ exports.bindBeat = audio.bindBeat;
1382
+ exports.createBeatDetector = audio.createBeatDetector;
1383
+ exports.defineAudio = audio.defineAudio;
1384
+ exports.disableAudio = audio.disableAudio;
1385
+ exports.enableAudio = audio.enableAudio;
1386
+ exports.getAudio = audio.getAudio;
1387
+ exports.onBeat = audio.onBeat;
1706
1388
  exports.CARD_FX = CARD_FX;
1707
1389
  exports.CLICK_FX = CLICK_FX;
1708
1390
  exports.CURSOR_FX = CURSOR_FX;
@@ -1717,20 +1399,13 @@ exports.THEME_NAMES = THEME_NAMES;
1717
1399
  exports.THEME_ROLES = THEME_ROLES;
1718
1400
  exports.angleDelta = angleDelta;
1719
1401
  exports.applyTheme = applyTheme;
1720
- exports.bindBeat = bindBeat;
1721
1402
  exports.bindGesture = bindGesture;
1722
1403
  exports.bounceKeyframes = bounceKeyframes;
1723
1404
  exports.bumpCount = bumpCount;
1724
- exports.createBeatDetector = createBeatDetector;
1725
- exports.defineAudio = defineAudio;
1726
1405
  exports.defineEffectElements = defineEffectElements;
1727
1406
  exports.defineGestureFx = defineGestureFx;
1728
1407
  exports.defineTheme = defineTheme;
1729
- exports.disableAudio = disableAudio;
1730
- exports.enableAudio = enableAudio;
1731
1408
  exports.flingVelocity = flingVelocity;
1732
- exports.getAudio = getAudio;
1733
- exports.onBeat = onBeat;
1734
1409
  exports.playThemeEffect = playThemeEffect;
1735
1410
  exports.registerAllEffects = registerAllEffects;
1736
1411
  exports.registerAudioEffects = registerAudioEffects;