@thewhateverapp/tile-sdk 0.12.11 → 0.12.13

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.
@@ -59,8 +59,9 @@ export declare class TileBridge {
59
59
  private tokenExpiresAt;
60
60
  private keyboardState;
61
61
  private visibilityState;
62
- private autoMuteEnabled;
63
62
  private mediaOriginalMutedState;
63
+ private trackedAudioContexts;
64
+ private audioContextPatched;
64
65
  private baselineViewportHeight;
65
66
  private keyboardDetectionEnabled;
66
67
  private lastReportedKeyboardState;
@@ -112,12 +113,25 @@ export declare class TileBridge {
112
113
  */
113
114
  private handleVisibility;
114
115
  /**
115
- * Automatically mute all video and audio elements in the document
116
- * Stores original muted state so we can restore it when unmuting
116
+ * ROBUST: Monkey-patch AudioContext to auto-intercept ALL new AudioContext() calls
117
+ * This catches WASM/Emscripten audio without tiles needing to call registerAudioContext()
118
+ */
119
+ private patchAudioContext;
120
+ /**
121
+ * ROBUST: MutationObserver to watch for dynamically added media elements
122
+ * Auto-mutes any <video> or <audio> elements added while tile is offscreen
123
+ */
124
+ private setupMediaObserver;
125
+ /**
126
+ * MANDATORY: Mute all audio sources when tile is offscreen
127
+ * - Mutes all <video> and <audio> elements
128
+ * - Suspends all registered AudioContexts (for WASM/Emscripten audio)
117
129
  */
118
130
  private muteAllMedia;
119
131
  /**
120
- * Unmute all video and audio elements, restoring their original muted state
132
+ * Unmute all audio sources when tile becomes visible
133
+ * - Unmutes <video> and <audio> elements (restoring original state)
134
+ * - Resumes all registered AudioContexts
121
135
  */
122
136
  private unmuteAllMedia;
123
137
  private sendToParent;
@@ -333,30 +347,26 @@ export declare class TileBridge {
333
347
  */
334
348
  onVisibilityChange(handler: (state: VisibilityState) => void): () => void;
335
349
  /**
336
- * Enable or disable automatic audio muting when visibility changes
337
- * By default, auto-mute is ENABLED - all <video> and <audio> elements are
338
- * automatically muted when the tile becomes hidden/offscreen.
350
+ * Register an AudioContext for mandatory muting when tile goes offscreen.
339
351
  *
340
- * Tiles with custom audio handling (e.g., using AudioContext, Emscripten/WASM)
341
- * should disable this and handle audio manually via onVisibilityChange.
352
+ * PROTOCOL FOR TILES WITH CUSTOM AUDIO:
353
+ * Tiles using AudioContext (e.g., Emscripten/WASM games like DOOM) MUST call
354
+ * this method to register their AudioContext. The TileBridge will automatically
355
+ * suspend/resume the context when the tile goes offscreen/onscreen.
342
356
  *
343
- * @param enabled - true to enable auto-mute (default), false to disable
344
- */
345
- setAutoMute(enabled: boolean): void;
346
- /**
347
- * Check if automatic audio muting is enabled
348
- */
349
- isAutoMuteEnabled(): boolean;
350
- /**
351
- * Manually mute all audio/video elements
352
- * Useful for tiles that need to mute on demand
357
+ * Example usage in DoomManager:
358
+ * ```
359
+ * const bridge = getTileBridge();
360
+ * bridge.registerAudioContext(myAudioContext);
361
+ * ```
362
+ *
363
+ * @param ctx - The AudioContext to track for automatic suspension
353
364
  */
354
- muteAll(): void;
365
+ registerAudioContext(ctx: AudioContext): void;
355
366
  /**
356
- * Manually unmute all audio/video elements
357
- * Restores original muted state (elements that were muted before stay muted)
367
+ * Unregister an AudioContext (e.g., when closing it)
358
368
  */
359
- unmuteAll(): void;
369
+ unregisterAudioContext(ctx: AudioContext): void;
360
370
  /**
361
371
  * Wait for ready state
362
372
  *
@@ -1 +1 @@
1
- {"version":3,"file":"TileBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/TileBridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TileBridge.d.ts","sourceRoot":"","sources":["../../src/bridge/TileBridge.ts"],"names":[],"mappings":"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"}
@@ -18,10 +18,11 @@ export class TileBridge {
18
18
  // Visibility state from parent (for TikTok-style feeds)
19
19
  // Includes muted state for atomic updates to prevent race conditions
20
20
  this.visibilityState = { visible: true, muted: false };
21
- // Automatic audio enforcement - enabled by default
22
- this.autoMuteEnabled = true;
23
21
  // Store original muted state of media elements to restore when unmuting
24
22
  this.mediaOriginalMutedState = new WeakMap();
23
+ // Track all AudioContext instances for suspension (catches Emscripten/WASM audio)
24
+ this.trackedAudioContexts = new Set();
25
+ this.audioContextPatched = false;
25
26
  // VisualViewport tracking for keyboard detection (Plan A)
26
27
  this.baselineViewportHeight = 0;
27
28
  this.keyboardDetectionEnabled = false;
@@ -85,6 +86,9 @@ export class TileBridge {
85
86
  this.sendToParent({ type: 'tile:ready' });
86
87
  // Initialize keyboard detection (Plan A: VisualViewport + Plan B: Input Focus)
87
88
  this.initializeKeyboardDetection();
89
+ // ROBUST AUDIO MUTING: Auto-intercept all audio sources
90
+ this.patchAudioContext();
91
+ this.setupMediaObserver();
88
92
  }
89
93
  /**
90
94
  * Initialize keyboard detection using VisualViewport API and input focus tracking
@@ -411,14 +415,12 @@ export class TileBridge {
411
415
  if (this.isDevelopment() || this.isPreview()) {
412
416
  console.log('[TileBridge] 👁️ Received visibility state', this.visibilityState);
413
417
  }
414
- // Auto-enforce audio muting if enabled
415
- if (this.autoMuteEnabled) {
416
- if (this.visibilityState.muted) {
417
- this.muteAllMedia();
418
- }
419
- else if (wasMuted && !this.visibilityState.muted) {
420
- this.unmuteAllMedia();
421
- }
418
+ // MANDATORY: Enforce audio muting when offscreen - no exceptions
419
+ if (this.visibilityState.muted) {
420
+ this.muteAllMedia();
421
+ }
422
+ else if (wasMuted && !this.visibilityState.muted) {
423
+ this.unmuteAllMedia();
422
424
  }
423
425
  // Emit if visibility OR muted state changed
424
426
  if (wasVisible !== this.visibilityState.visible || wasMuted !== this.visibilityState.muted) {
@@ -426,12 +428,98 @@ export class TileBridge {
426
428
  }
427
429
  }
428
430
  /**
429
- * Automatically mute all video and audio elements in the document
430
- * Stores original muted state so we can restore it when unmuting
431
+ * ROBUST: Monkey-patch AudioContext to auto-intercept ALL new AudioContext() calls
432
+ * This catches WASM/Emscripten audio without tiles needing to call registerAudioContext()
433
+ */
434
+ patchAudioContext() {
435
+ if (typeof window === 'undefined' || this.audioContextPatched)
436
+ return;
437
+ this.audioContextPatched = true;
438
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
439
+ const bridge = this;
440
+ const OriginalAudioContext = window.AudioContext || window.webkitAudioContext;
441
+ if (!OriginalAudioContext) {
442
+ console.log('[TileBridge] AudioContext not available in this environment');
443
+ return;
444
+ }
445
+ // Create a patched constructor that auto-registers all instances
446
+ function PatchedAudioContext(options) {
447
+ // Call original constructor
448
+ const ctx = new OriginalAudioContext(options);
449
+ // Auto-register this context
450
+ bridge.trackedAudioContexts.add(ctx);
451
+ console.log(`[TileBridge] 🎵 AudioContext auto-intercepted (${bridge.trackedAudioContexts.size} total)`);
452
+ // If tile is currently muted, suspend immediately
453
+ if (bridge.visibilityState.muted && ctx.state === 'running') {
454
+ console.log('[TileBridge] 🔇 New AudioContext auto-suspended (tile is muted)');
455
+ ctx.suspend().catch(() => { });
456
+ }
457
+ return ctx;
458
+ }
459
+ // Copy prototype and static properties
460
+ PatchedAudioContext.prototype = OriginalAudioContext.prototype;
461
+ Object.setPrototypeOf(PatchedAudioContext, OriginalAudioContext);
462
+ // Replace global AudioContext
463
+ window.AudioContext = PatchedAudioContext;
464
+ if (window.webkitAudioContext) {
465
+ window.webkitAudioContext = PatchedAudioContext;
466
+ }
467
+ console.log('[TileBridge] 🔧 AudioContext patched for auto-interception');
468
+ }
469
+ /**
470
+ * ROBUST: MutationObserver to watch for dynamically added media elements
471
+ * Auto-mutes any <video> or <audio> elements added while tile is offscreen
472
+ */
473
+ setupMediaObserver() {
474
+ if (typeof document === 'undefined' || typeof MutationObserver === 'undefined')
475
+ return;
476
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
477
+ const bridge = this;
478
+ const observer = new MutationObserver((mutations) => {
479
+ // Only process if we're currently muted
480
+ if (!bridge.visibilityState.muted)
481
+ return;
482
+ mutations.forEach((mutation) => {
483
+ mutation.addedNodes.forEach((node) => {
484
+ // Check if the added node is a media element
485
+ if (node instanceof HTMLMediaElement) {
486
+ if (!node.muted) {
487
+ bridge.mediaOriginalMutedState.set(node, node.muted);
488
+ node.muted = true;
489
+ console.log('[TileBridge] 🔇 Auto-muted dynamically added media element');
490
+ }
491
+ }
492
+ // Also check children of added nodes
493
+ if (node instanceof Element) {
494
+ const mediaElements = node.querySelectorAll('video, audio');
495
+ mediaElements.forEach((element) => {
496
+ const media = element;
497
+ if (!media.muted) {
498
+ bridge.mediaOriginalMutedState.set(media, media.muted);
499
+ media.muted = true;
500
+ console.log('[TileBridge] 🔇 Auto-muted dynamically added media element (child)');
501
+ }
502
+ });
503
+ }
504
+ });
505
+ });
506
+ });
507
+ // Start observing the entire document for added nodes
508
+ observer.observe(document.documentElement, {
509
+ childList: true,
510
+ subtree: true,
511
+ });
512
+ console.log('[TileBridge] 👁️ MutationObserver active for dynamic media elements');
513
+ }
514
+ /**
515
+ * MANDATORY: Mute all audio sources when tile is offscreen
516
+ * - Mutes all <video> and <audio> elements
517
+ * - Suspends all registered AudioContexts (for WASM/Emscripten audio)
431
518
  */
432
519
  muteAllMedia() {
433
520
  if (typeof document === 'undefined')
434
521
  return;
522
+ // 1. Mute all HTML media elements
435
523
  const mediaElements = document.querySelectorAll('video, audio');
436
524
  let mutedCount = 0;
437
525
  mediaElements.forEach((element) => {
@@ -445,16 +533,29 @@ export class TileBridge {
445
533
  mutedCount++;
446
534
  }
447
535
  });
448
- if (mutedCount > 0) {
449
- console.log(`[TileBridge] 🔇 Auto-muted ${mutedCount} media element(s)`);
536
+ // 2. Suspend all registered AudioContexts (for tiles like DOOM with WASM audio)
537
+ let suspendedCount = 0;
538
+ this.trackedAudioContexts.forEach((ctx) => {
539
+ if (ctx.state === 'running') {
540
+ ctx.suspend().catch((err) => {
541
+ console.warn('[TileBridge] Failed to suspend AudioContext:', err);
542
+ });
543
+ suspendedCount++;
544
+ }
545
+ });
546
+ if (mutedCount > 0 || suspendedCount > 0) {
547
+ console.log(`[TileBridge] 🔇 MUTED: ${mutedCount} media element(s), ${suspendedCount} AudioContext(s)`);
450
548
  }
451
549
  }
452
550
  /**
453
- * Unmute all video and audio elements, restoring their original muted state
551
+ * Unmute all audio sources when tile becomes visible
552
+ * - Unmutes <video> and <audio> elements (restoring original state)
553
+ * - Resumes all registered AudioContexts
454
554
  */
455
555
  unmuteAllMedia() {
456
556
  if (typeof document === 'undefined')
457
557
  return;
558
+ // 1. Unmute HTML media elements
458
559
  const mediaElements = document.querySelectorAll('video, audio');
459
560
  let unmutedCount = 0;
460
561
  mediaElements.forEach((element) => {
@@ -471,8 +572,18 @@ export class TileBridge {
471
572
  // Clear stored state
472
573
  this.mediaOriginalMutedState.delete(media);
473
574
  });
474
- if (unmutedCount > 0) {
475
- console.log(`[TileBridge] 🔊 Auto-unmuted ${unmutedCount} media element(s)`);
575
+ // 2. Resume all registered AudioContexts
576
+ let resumedCount = 0;
577
+ this.trackedAudioContexts.forEach((ctx) => {
578
+ if (ctx.state === 'suspended') {
579
+ ctx.resume().catch((err) => {
580
+ console.warn('[TileBridge] Failed to resume AudioContext:', err);
581
+ });
582
+ resumedCount++;
583
+ }
584
+ });
585
+ if (unmutedCount > 0 || resumedCount > 0) {
586
+ console.log(`[TileBridge] 🔊 UNMUTED: ${unmutedCount} media element(s), ${resumedCount} AudioContext(s)`);
476
587
  }
477
588
  }
478
589
  sendToParent(message) {
@@ -1184,40 +1295,40 @@ export class TileBridge {
1184
1295
  onVisibilityChange(handler) {
1185
1296
  return this.on('visibility:update', handler);
1186
1297
  }
1187
- // ============= AUTO-MUTE API =============
1298
+ // ============= AUDIOCONTEXT REGISTRATION API =============
1299
+ // Tiles with custom audio (WASM/Emscripten) MUST register their AudioContexts
1300
+ // to be automatically suspended/resumed when the tile goes offscreen.
1188
1301
  /**
1189
- * Enable or disable automatic audio muting when visibility changes
1190
- * By default, auto-mute is ENABLED - all <video> and <audio> elements are
1191
- * automatically muted when the tile becomes hidden/offscreen.
1302
+ * Register an AudioContext for mandatory muting when tile goes offscreen.
1192
1303
  *
1193
- * Tiles with custom audio handling (e.g., using AudioContext, Emscripten/WASM)
1194
- * should disable this and handle audio manually via onVisibilityChange.
1304
+ * PROTOCOL FOR TILES WITH CUSTOM AUDIO:
1305
+ * Tiles using AudioContext (e.g., Emscripten/WASM games like DOOM) MUST call
1306
+ * this method to register their AudioContext. The TileBridge will automatically
1307
+ * suspend/resume the context when the tile goes offscreen/onscreen.
1195
1308
  *
1196
- * @param enabled - true to enable auto-mute (default), false to disable
1197
- */
1198
- setAutoMute(enabled) {
1199
- this.autoMuteEnabled = enabled;
1200
- console.log(`[TileBridge] 🔈 Auto-mute ${enabled ? 'enabled' : 'disabled'}`);
1201
- }
1202
- /**
1203
- * Check if automatic audio muting is enabled
1204
- */
1205
- isAutoMuteEnabled() {
1206
- return this.autoMuteEnabled;
1207
- }
1208
- /**
1209
- * Manually mute all audio/video elements
1210
- * Useful for tiles that need to mute on demand
1309
+ * Example usage in DoomManager:
1310
+ * ```
1311
+ * const bridge = getTileBridge();
1312
+ * bridge.registerAudioContext(myAudioContext);
1313
+ * ```
1314
+ *
1315
+ * @param ctx - The AudioContext to track for automatic suspension
1211
1316
  */
1212
- muteAll() {
1213
- this.muteAllMedia();
1317
+ registerAudioContext(ctx) {
1318
+ this.trackedAudioContexts.add(ctx);
1319
+ console.log(`[TileBridge] 🎵 AudioContext registered (${this.trackedAudioContexts.size} total)`);
1320
+ // If tile is currently muted, suspend immediately
1321
+ if (this.visibilityState.muted && ctx.state === 'running') {
1322
+ console.log('[TileBridge] 🔇 New AudioContext auto-suspended (tile is muted)');
1323
+ ctx.suspend().catch(() => { });
1324
+ }
1214
1325
  }
1215
1326
  /**
1216
- * Manually unmute all audio/video elements
1217
- * Restores original muted state (elements that were muted before stay muted)
1327
+ * Unregister an AudioContext (e.g., when closing it)
1218
1328
  */
1219
- unmuteAll() {
1220
- this.unmuteAllMedia();
1329
+ unregisterAudioContext(ctx) {
1330
+ this.trackedAudioContexts.delete(ctx);
1331
+ console.log(`[TileBridge] 🎵 AudioContext unregistered (${this.trackedAudioContexts.size} remaining)`);
1221
1332
  }
1222
1333
  /**
1223
1334
  * Wait for ready state
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thewhateverapp/tile-sdk",
3
- "version": "0.12.11",
3
+ "version": "0.12.13",
4
4
  "description": "SDK for building interactive tiles on The Whatever App platform",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",