aurasu 0.1.6 → 0.1.8

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.
Binary file
Binary file
Binary file
Binary file
@@ -150,6 +150,36 @@
150
150
  "sha256": "7f0f8344db9fda1d6b3d0c6a45e36ae51d5198b7613deee326a85e67cd2f413b",
151
151
  "size": 2142
152
152
  },
153
+ {
154
+ "path": "assets/splash/aurajs-gg-wordmark.webp",
155
+ "sha256": "80a4ebd7d23f624aa1ead31c4702b3c21ce8c99075e80e4f3a371870585c73af",
156
+ "size": 21970
157
+ },
158
+ {
159
+ "path": "assets/splash/bg.webp",
160
+ "sha256": "3a8892862610ce453314dae576f6707470a7761eb2be5987b55501d9ccd41f54",
161
+ "size": 46216
162
+ },
163
+ {
164
+ "path": "assets/splash/boot-loop.wav",
165
+ "sha256": "569b8c457d478b003011d62f165ffd73ad11a598d28337b2c98ee8bb4357c0f7",
166
+ "size": 70604
167
+ },
168
+ {
169
+ "path": "assets/splash/boot-sting.wav",
170
+ "sha256": "386abbb357537ec0a284c9ff64de26821782de10002b2b5c9675b26bb755c44d",
171
+ "size": 48554
172
+ },
173
+ {
174
+ "path": "assets/splash/logo-mascot-sheet.webp",
175
+ "sha256": "aaa75bea690285b2c6df08182c248cdae6ca374057978cdba25d57d8fb70c225",
176
+ "size": 22036
177
+ },
178
+ {
179
+ "path": "assets/splash/logoholo.webp",
180
+ "sha256": "65bec52e3ecb6417aa74832a3153c837b9aaee6b3dd5d7e8536235b7d11442cd",
181
+ "size": 12782
182
+ },
153
183
  {
154
184
  "path": "assets/ui-back.wav",
155
185
  "sha256": "a4e071c73866aa94a7e34a636c18aff4a9c83a4bd3d5333f63f07704e982b793",
@@ -177,53 +207,8 @@
177
207
  },
178
208
  {
179
209
  "path": "bin/play.js",
180
- "sha256": "9b444ba23f1ea908c16a2266b223f987386966a0248bad0e56f4d2d1beafee46",
181
- "size": 40778
182
- },
183
- {
184
- "path": "build/mac/assets-manifest.json",
185
- "sha256": "5174022540cddd4cc11b2e791267376d00bb1ef90dab695edb6d2fe6b29ec7e4",
186
- "size": 7035
187
- },
188
- {
189
- "path": "build/mac/assets/asset-pack.pak",
190
- "sha256": "e9493c11c042f84b0c211ebbadc3b5e6dfe5beb49e025679c0c80b2bef274797",
191
- "size": 37326050
192
- },
193
- {
194
- "path": "build/mac/aurasu",
195
- "sha256": "6c667fed6977f6833b4c695d5966da5616f1dd994201fe828d93dba1885aed8c",
196
- "size": 66392000
197
- },
198
- {
199
- "path": "build/mac/aurasu.app/Contents/Info.plist",
200
- "sha256": "12a5cb044ab4b9a3a0e43c0827896a11662eca29a18b29ffa23ba0dec07e4bfd",
201
- "size": 832
202
- },
203
- {
204
- "path": "build/mac/aurasu.app/Contents/MacOS/aurasu",
205
- "sha256": "6c667fed6977f6833b4c695d5966da5616f1dd994201fe828d93dba1885aed8c",
206
- "size": 66392000
207
- },
208
- {
209
- "path": "build/mac/aurasu.app/Contents/Resources/AppIcon.icns",
210
- "sha256": "02171500adb3fc2fc965b2c4d25e167ce3b4125edd19fab7023d02430ba5338a",
211
- "size": 3222641
212
- },
213
- {
214
- "path": "build/mac/build-manifest.json",
215
- "sha256": "46abba00ed8b885f03dea8354fa02d813219bfaa09095a8d04d7f633b93fd02b",
216
- "size": 633
217
- },
218
- {
219
- "path": "build/mac/js/game.bundle.js",
220
- "sha256": "32278be0508a48e869c035646031f4b2047477be62d09b26125f5afb76f8f7c9",
221
- "size": 210434
222
- },
223
- {
224
- "path": "build/mac/meta/icon.png",
225
- "sha256": "f63784b866f19e3e2373304fd30c9ea119418d8b074b4a12a5ece00b766f4c87",
226
- "size": 574673
210
+ "sha256": "c29cc4a29d0470e46ce5555cbc4001f96d7458ab7a5975ad55b3248fb5859520",
211
+ "size": 42416
227
212
  },
228
213
  {
229
214
  "path": "config/gameplay/game.config.js",
@@ -237,7 +222,7 @@
237
222
  },
238
223
  {
239
224
  "path": "package.json",
240
- "sha256": "9fa90df85b3c7ec4d0930b5b45467ae94487c26c1aba29b47a7691987cf286ef",
225
+ "sha256": "4c081cac3332359fef0c3c4e224ccf1d3f48441c38e70dd54394225110dca757",
241
226
  "size": 568
242
227
  },
243
228
  {
@@ -257,8 +242,8 @@
257
242
  },
258
243
  {
259
244
  "path": "src/main.js",
260
- "sha256": "441adcb9f5cd61413b82146b7c9b9b44782f7543a273cb8f6b66b5151a1ff8b7",
261
- "size": 365
245
+ "sha256": "0b2f36b0a56d38529289077b7a43795edc4c064d9747c47f3c200426bbfb67d9",
246
+ "size": 577
262
247
  },
263
248
  {
264
249
  "path": "src/runtime/app-state.js",
@@ -300,6 +285,11 @@
300
285
  "sha256": "56321b896b4368973feb6f5581a9e27d2553b1be91d66206e88cf9ffb25723f8",
301
286
  "size": 6384
302
287
  },
288
+ {
289
+ "path": "src/runtime/splash.js",
290
+ "sha256": "00cd80250f0abffd14b27241d65dc0b3402c3814a5bb4395d0cd538b20ae59fc",
291
+ "size": 9799
292
+ },
303
293
  {
304
294
  "path": "src/runtime/ui-settings.js",
305
295
  "sha256": "c09e6ae51fa3dc507da5c8b1975598629081bad0af98faa32471ca5fb1b32c6e",
@@ -317,14 +307,14 @@
317
307
  }
318
308
  ],
319
309
  "package": {
320
- "aurajsVersion": "0.1.1",
310
+ "aurajsVersion": "0.1.3",
321
311
  "bin": {
322
312
  "aurasu": "bin/play.js"
323
313
  },
324
314
  "description": "A hit-circle rhythm game built with AuraJS.",
325
315
  "name": "aurasu",
326
316
  "type": "module",
327
- "version": "0.1.6"
317
+ "version": "0.1.8"
328
318
  },
329
319
  "publishedMetadata": {
330
320
  "authored": {
@@ -1 +1 @@
1
- UT6PKQtY6QwXaCBdKnd8TTK/hjLDWroFfFb6mFupkl18Y3MkOooXiBNMaQVuPO13H8CY5/5WFrnQ/erevzZ1Dg==
1
+ dVntP3f6ovlY/3IR88FwdOm1RuqOGaSJlY4d4r0gcWHGG5C2uyapbrNxm2ufha+zqpUXCCma3tTrnEl0Y7oQBg==
package/bin/play.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from 'node:child_process';
3
+ import { spawn, spawnSync } from 'node:child_process';
4
4
  import { cpSync, createWriteStream, existsSync, mkdirSync, readFileSync } from 'node:fs';
5
5
  import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
6
6
  import { fileURLToPath, pathToFileURL } from 'node:url';
@@ -58,6 +58,39 @@ const ALL_COMMANDS = ['dev', 'join', 'play', 'fork', 'publish', 'session', 'stat
58
58
  const ROOM_CODE_PATTERN = /^[A-Z0-9]{4,8}$/;
59
59
  const FORK_EXCLUDED_TOP_LEVEL = new Set(['.aura', '.git', '.logs', 'build', 'dist', 'node_modules']);
60
60
 
61
+ function resolveAuraMaxxBinary() {
62
+ return process.platform === 'win32' ? 'auramaxx.cmd' : 'auramaxx';
63
+ }
64
+
65
+ function resolveNpmBinary() {
66
+ return process.platform === 'win32' ? 'npm.cmd' : 'npm';
67
+ }
68
+
69
+ function isAuraMaxxInstalled() {
70
+ const probe = spawnSync(resolveAuraMaxxBinary(), ['--version'], {
71
+ stdio: 'ignore',
72
+ env: process.env,
73
+ });
74
+ return !probe.error && probe.status === 0;
75
+ }
76
+
77
+ async function installAuraMaxxGlobally() {
78
+ return new Promise((resolveInstall) => {
79
+ const child = spawn(
80
+ resolveNpmBinary(),
81
+ ['install', '-g', 'auramaxx', '--foreground-scripts'],
82
+ {
83
+ cwd: process.cwd(),
84
+ stdio: 'inherit',
85
+ env: process.env,
86
+ },
87
+ );
88
+
89
+ child.on('error', () => resolveInstall(false));
90
+ child.on('close', (code) => resolveInstall((code ?? 1) === 0));
91
+ });
92
+ }
93
+
61
94
  function resolveLocalAuraCli(startRoot) {
62
95
  let current = resolve(startRoot);
63
96
  while (true) {
@@ -1063,6 +1096,38 @@ async function chooseDefaultCommand() {
1063
1096
  return choice;
1064
1097
  }
1065
1098
 
1099
+ async function maybeOfferAuraMaxxInstall() {
1100
+ if (isAuraMaxxInstalled()) {
1101
+ return;
1102
+ }
1103
+
1104
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
1105
+ return;
1106
+ }
1107
+
1108
+ printSection('AuraMaxx', 'AuraMaxx is not installed globally.');
1109
+ const choice = await promptSelect(
1110
+ ' Install AuraMaxx now?',
1111
+ [
1112
+ { value: 'yes', label: 'Yes, install AuraMaxx' },
1113
+ { value: 'no', label: 'No, continue playing' },
1114
+ ],
1115
+ 'yes',
1116
+ );
1117
+
1118
+ if (choice !== 'yes') {
1119
+ return;
1120
+ }
1121
+
1122
+ printSection('AuraMaxx', 'Installing global CLI...');
1123
+ const installed = await installAuraMaxxGlobally();
1124
+ if (installed) {
1125
+ printSection('AuraMaxx', 'Installed. Continuing play...');
1126
+ return;
1127
+ }
1128
+ printSection('AuraMaxx', 'Install failed. Continuing play...');
1129
+ }
1130
+
1066
1131
  async function main() {
1067
1132
  const parsed = parseArgs(process.argv.slice(2));
1068
1133
 
@@ -1092,6 +1157,7 @@ async function main() {
1092
1157
  if (command === 'play') {
1093
1158
  printBanner('PLAY');
1094
1159
  printSection(toDisplayTitle(packageName), 'Starting packaged local game session...');
1160
+ await maybeOfferAuraMaxxInstall();
1095
1161
  const externalAssets = await maybePrepareExternalAssets('play');
1096
1162
  const multiplayerEnv = await resolveLocalMultiplayerCommandEnv();
1097
1163
  await runCommand(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aurasu",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "A hit-circle rhythm game built with AuraJS.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "aura.package-integrity.sig"
22
22
  ],
23
23
  "dependencies": {
24
- "@auraindustry/aurajs": "0.1.1"
24
+ "@auraindustry/aurajs": "0.1.3"
25
25
  },
26
26
  "keywords": [
27
27
  "aurajs",
package/src/main.js CHANGED
@@ -1,16 +1,20 @@
1
1
  import { createApp } from './runtime/app.js';
2
+ import { initSplash, updateSplash, drawSplash, isSplashActive } from './runtime/splash.js';
2
3
 
3
4
  const app = createApp();
4
5
 
5
6
  aura.setup = function setup() {
7
+ initSplash();
6
8
  return app.setup();
7
9
  };
8
10
 
9
11
  aura.update = function update(dt) {
12
+ if (isSplashActive()) { updateSplash(dt); return; }
10
13
  app.update(dt);
11
14
  };
12
15
 
13
16
  aura.draw = function draw() {
17
+ if (isSplashActive()) { drawSplash(); return; }
14
18
  app.draw();
15
19
  };
16
20
 
@@ -0,0 +1,305 @@
1
+ // AuraJS Splash — unified retro paper-card boot screen.
2
+ // Auto-wired by createApp(). Shows once on launch, then hands off to the game.
3
+
4
+ const FADE_IN = 0.7;
5
+ const HOLD = 1.8;
6
+ const FADE_OUT = 0.7;
7
+ const TOTAL = FADE_IN + HOLD + FADE_OUT;
8
+
9
+ const PAPER = [0.89, 0.89, 0.89];
10
+ const PAPER_SHADOW = [0.80, 0.80, 0.80];
11
+ const PAPER_EDGE = [0.41, 0.41, 0.41];
12
+ const INK = [0.1, 0.1, 0.1];
13
+ const INK_MUTED = [0.42, 0.42, 0.42];
14
+ const MASCOT_FRAME_W = 64;
15
+ const MASCOT_FRAME_H = 84;
16
+ const MASCOT_SEQUENCE = Object.freeze([0, 1, 2, 1]);
17
+ const SPLASH_STING_PATH = 'splash/boot-sting.wav';
18
+ const SPLASH_LOOP_PATH = 'splash/boot-loop.wav';
19
+ const SPLASH_BUS = 'splash';
20
+ const QUIET_BUSES = Object.freeze(['default', 'music', 'sfx']);
21
+
22
+ let state = null;
23
+
24
+ function has(obj, method) {
25
+ return Boolean(obj) && typeof obj[method] === 'function';
26
+ }
27
+
28
+ function color(rgb, alpha = 1) {
29
+ return aura.rgba(rgb[0], rgb[1], rgb[2], alpha);
30
+ }
31
+
32
+ function drawShadowText(text, x, y, options = {}) {
33
+ const {
34
+ shadowOffset = 2,
35
+ shadowColor = color(INK_MUTED, 0.3),
36
+ ...rest
37
+ } = options;
38
+ aura.draw2d.text(text, x + shadowOffset, y + shadowOffset, {
39
+ ...rest,
40
+ color: shadowColor,
41
+ });
42
+ aura.draw2d.text(text, x, y, rest);
43
+ }
44
+
45
+ export function initSplash() {
46
+ state = {
47
+ t: 0,
48
+ logo: null,
49
+ mascot: null,
50
+ wordmark: null,
51
+ font: null,
52
+ stingHandle: null,
53
+ loopHandle: null,
54
+ busVolumes: null,
55
+ pausedHandles: [],
56
+ };
57
+ try { if (has(aura.assets, 'load')) state.logo = aura.assets.load('splash/logoholo.webp'); } catch (_) {}
58
+ try { if (has(aura.assets, 'load')) state.mascot = aura.assets.load('splash/logo-mascot-sheet.webp'); } catch (_) {}
59
+ try { if (has(aura.assets, 'load')) state.wordmark = aura.assets.load('splash/aurajs-gg-wordmark.webp'); } catch (_) {}
60
+ try {
61
+ if (has(aura.assets, 'loadBitmapFont')) {
62
+ const result = aura.assets.loadBitmapFont();
63
+ if (result && result.ok && result.font) state.font = result.font;
64
+ }
65
+ } catch (_) {}
66
+ captureBusVolumes();
67
+ applySplashBusIsolation();
68
+ try {
69
+ if (aura.audio && aura.audio.supported !== false && typeof aura.audio.play === 'function') {
70
+ state.loopHandle = aura.audio.play(SPLASH_LOOP_PATH, {
71
+ loop: true,
72
+ volume: 0.22,
73
+ bus: SPLASH_BUS,
74
+ });
75
+ state.stingHandle = aura.audio.play(SPLASH_STING_PATH, {
76
+ loop: false,
77
+ volume: 0.54,
78
+ bus: SPLASH_BUS,
79
+ });
80
+ }
81
+ } catch (_) {}
82
+ }
83
+
84
+ export function isSplashActive() {
85
+ return state !== null;
86
+ }
87
+
88
+ export function updateSplash(dt) {
89
+ if (!state) return;
90
+ syncPausedTracks();
91
+ try {
92
+ if (aura.audio && typeof aura.audio.update === 'function') {
93
+ aura.audio.update(Number(dt) > 0 ? Number(dt) : (1 / 60));
94
+ }
95
+ } catch (_) {}
96
+ state.t += dt;
97
+ if (state.t >= TOTAL) {
98
+ stopSplashAudio();
99
+ state = null;
100
+ }
101
+ }
102
+
103
+ export function drawSplash() {
104
+ if (!state) return;
105
+ const { width: w, height: h } = has(aura.window, 'getSize')
106
+ ? aura.window.getSize()
107
+ : { width: 640, height: 480 };
108
+ const t = state.t;
109
+ const cx = w / 2;
110
+ const cy = h / 2;
111
+
112
+ let a = 1;
113
+ if (t < FADE_IN) a = easeOut(t / FADE_IN);
114
+ else if (t > FADE_IN + HOLD) a = 1 - easeIn((t - FADE_IN - HOLD) / FADE_OUT);
115
+
116
+ aura.draw2d.clear(color(PAPER));
117
+
118
+ const panelW = Math.min(Math.floor(w * 0.48), 580);
119
+ const panelH = Math.min(Math.floor(h * 0.72), 620);
120
+ const panelX = Math.floor(cx - (panelW * 0.5));
121
+ const panelY = Math.floor(cy - (panelH * 0.5));
122
+
123
+ aura.draw2d.rectFill(panelX + 6, panelY + 6, panelW, panelH, color(INK, 0.08 * a));
124
+ aura.draw2d.rectFill(panelX, panelY, panelW, panelH, color(PAPER_EDGE, a));
125
+ aura.draw2d.rectFill(panelX + 6, panelY + 6, panelW - 12, panelH - 12, color(PAPER, a));
126
+ aura.draw2d.rectFill(panelX + 12, panelY + 12, panelW - 24, panelH - 24, color(PAPER, a * 0.96));
127
+
128
+ const floatY = Math.sin(t * 1.4 * Math.PI * 2) * 2;
129
+ const breathe = 0.985 + 0.015 * (0.5 + 0.5 * Math.sin(t * Math.PI * 2));
130
+ const mascotScale = Math.max(1, Math.min(Math.floor(Math.min(w, h) / 260), 2));
131
+ const mascotW = Math.floor(MASCOT_FRAME_W * mascotScale * breathe);
132
+ const mascotH = Math.floor(MASCOT_FRAME_H * mascotScale * breathe);
133
+ const mascotX = Math.floor(cx - (mascotW * 0.5));
134
+ const mascotY = Math.floor(panelY + panelH * 0.40 + floatY);
135
+ const mascotFrame = MASCOT_SEQUENCE[Math.floor(t * 7.5) % MASCOT_SEQUENCE.length] || 0;
136
+
137
+ aura.draw2d.rectFill(
138
+ mascotX + Math.floor(mascotW * 0.18),
139
+ mascotY + mascotH - 8,
140
+ Math.floor(mascotW * 0.64),
141
+ 6,
142
+ color(INK, a * 0.08),
143
+ );
144
+
145
+ if (state.mascot) {
146
+ aura.draw2d.sprite(state.mascot, mascotX, mascotY, {
147
+ width: mascotW,
148
+ height: mascotH,
149
+ frameX: mascotFrame * MASCOT_FRAME_W,
150
+ frameY: 0,
151
+ frameW: MASCOT_FRAME_W,
152
+ frameH: MASCOT_FRAME_H,
153
+ alpha: a,
154
+ });
155
+ } else if (state.logo) {
156
+ const sz = Math.min(Math.floor(panelW * 0.24), Math.floor(h * 0.14)) * breathe;
157
+ aura.draw2d.sprite(state.logo, Math.floor(cx - sz / 2), Math.floor(mascotY + 6), {
158
+ width: sz,
159
+ height: sz,
160
+ alpha: a,
161
+ });
162
+ }
163
+
164
+ const ta = clamp(a * easeOut(clamp((t - 0.2) / (FADE_IN * 0.6))));
165
+ const sa = clamp(a * easeOut(clamp((t - 0.4) / (FADE_IN * 0.6))));
166
+ const scale = Math.min(w, h) / 480;
167
+ const tsz = Math.max(24, Math.round(scale * 28));
168
+ const ssz = Math.max(11, Math.round(scale * 12));
169
+ const wordmarkW = Math.min(Math.floor(panelW * 0.52), 290);
170
+ const wordmarkH = Math.floor(wordmarkW * (768 / 1408));
171
+ const wordmarkX = Math.floor(cx - (wordmarkW * 0.5));
172
+ const wordmarkY = Math.floor(panelY + 36);
173
+ const sY = Math.floor(panelY + panelH - 108);
174
+ const fo = state.font ? { font: state.font } : {};
175
+
176
+ if (state.wordmark) {
177
+ aura.draw2d.sprite(state.wordmark, wordmarkX, wordmarkY, {
178
+ width: wordmarkW,
179
+ height: wordmarkH,
180
+ alpha: ta,
181
+ tint: color(INK, ta),
182
+ });
183
+ } else {
184
+ drawShadowText('AuraJS.gg', cx, wordmarkY + Math.floor(wordmarkH * 0.55), {
185
+ ...fo,
186
+ size: tsz,
187
+ color: color(INK, ta),
188
+ shadowColor: color(INK_MUTED, ta * 0.28),
189
+ align: 'center',
190
+ });
191
+ }
192
+
193
+ drawShadowText('Open-Source. MIT.', cx, sY, {
194
+ ...fo,
195
+ size: ssz,
196
+ color: color(INK_MUTED, sa),
197
+ shadowColor: color(PAPER_EDGE, sa * 0.18),
198
+ shadowOffset: 1,
199
+ align: 'center',
200
+ });
201
+ drawShadowText('Who needs publishers?', cx, sY + Math.max(16, Math.round(ssz * 1.45)), {
202
+ ...fo,
203
+ size: ssz,
204
+ color: color(INK_MUTED, sa),
205
+ shadowColor: color(PAPER_EDGE, sa * 0.18),
206
+ shadowOffset: 1,
207
+ align: 'center',
208
+ });
209
+
210
+ const rw = Math.min(panelW - 140, 240);
211
+ aura.draw2d.rectFill(Math.floor(cx - rw / 2), Math.floor(sY + Math.max(34, ssz * 3.2)), rw, 2, color(PAPER_EDGE, sa * 0.38));
212
+ }
213
+
214
+ function easeOut(t) {
215
+ const u = 1 - clamp(t);
216
+ return 1 - (u * u * u);
217
+ }
218
+
219
+ function easeIn(t) {
220
+ const c = clamp(t);
221
+ return c * c * c;
222
+ }
223
+
224
+ function clamp(v) {
225
+ return v < 0 ? 0 : v > 1 ? 1 : v;
226
+ }
227
+
228
+ function stopSplashAudio() {
229
+ if (!state || !aura.audio || typeof aura.audio.stop !== 'function') return;
230
+ try {
231
+ if (state.stingHandle != null) aura.audio.stop(state.stingHandle);
232
+ } catch (_) {}
233
+ try {
234
+ if (state.loopHandle != null) aura.audio.stop(state.loopHandle);
235
+ } catch (_) {}
236
+ restoreAudioState();
237
+ state.stingHandle = null;
238
+ state.loopHandle = null;
239
+ }
240
+
241
+ function captureBusVolumes() {
242
+ if (!state || !aura.audio || typeof aura.audio.getMixerState !== 'function') return;
243
+ try {
244
+ const mixer = aura.audio.getMixerState();
245
+ const buses = Array.isArray(mixer?.buses) ? mixer.buses : [];
246
+ state.busVolumes = buses.reduce((acc, entry) => {
247
+ const bus = String(entry?.bus || '').trim();
248
+ if (!bus) return acc;
249
+ acc[bus] = Number(entry?.volume);
250
+ return acc;
251
+ }, {});
252
+ } catch (_) {}
253
+ }
254
+
255
+ function applySplashBusIsolation() {
256
+ if (!state || !aura.audio || typeof aura.audio.setBusVolume !== 'function') return;
257
+ try { aura.audio.setBusVolume(SPLASH_BUS, 1); } catch (_) {}
258
+ for (const bus of QUIET_BUSES) {
259
+ try { aura.audio.setBusVolume(bus, 0); } catch (_) {}
260
+ }
261
+ }
262
+
263
+ function syncPausedTracks() {
264
+ if (!state || !aura.audio || typeof aura.audio.getMixerState !== 'function' || typeof aura.audio.pause !== 'function') return;
265
+ try {
266
+ const mixer = aura.audio.getMixerState();
267
+ const tracks = Array.isArray(mixer?.tracks) ? mixer.tracks : [];
268
+ const splashHandles = [state.stingHandle, state.loopHandle].filter((handle) => handle != null);
269
+ const pausedHandles = new Set(Array.isArray(state.pausedHandles) ? state.pausedHandles : []);
270
+ for (const track of tracks) {
271
+ const handle = Number(track?.handle);
272
+ if (!Number.isInteger(handle) || handle <= 0) continue;
273
+ if (splashHandles.includes(handle)) continue;
274
+ if (track?.paused === true || pausedHandles.has(handle)) continue;
275
+ try {
276
+ aura.audio.pause(handle);
277
+ pausedHandles.add(handle);
278
+ } catch (_) {}
279
+ }
280
+ state.pausedHandles = Array.from(pausedHandles);
281
+ } catch (_) {}
282
+ }
283
+
284
+ function restoreAudioState() {
285
+ if (!state || !aura.audio) return;
286
+ if (typeof aura.audio.setBusVolume === 'function') {
287
+ const snapshot = state.busVolumes && typeof state.busVolumes === 'object' ? state.busVolumes : null;
288
+ if (snapshot) {
289
+ for (const [bus, volume] of Object.entries(snapshot)) {
290
+ try { aura.audio.setBusVolume(bus, Number(volume)); } catch (_) {}
291
+ }
292
+ } else {
293
+ for (const bus of QUIET_BUSES) {
294
+ try { aura.audio.setBusVolume(bus, 1); } catch (_) {}
295
+ }
296
+ }
297
+ try { aura.audio.setBusVolume(SPLASH_BUS, 1); } catch (_) {}
298
+ }
299
+ if (typeof aura.audio.resume === 'function') {
300
+ for (const handle of Array.isArray(state.pausedHandles) ? state.pausedHandles : []) {
301
+ try { aura.audio.resume(handle); } catch (_) {}
302
+ }
303
+ }
304
+ state.pausedHandles = [];
305
+ }