From e8f89df88bf9ca5a3b2df12b42ec9f2eb3c8f5f9 Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Fri, 19 Jun 2026 15:35:58 -0700 Subject: [PATCH 1/3] fix(slideshow): harden media controls in present decks --- packages/cli/src/commands/present.ts | 18 +- packages/cli/src/commands/validate.test.ts | 14 ++ packages/cli/src/commands/validate.ts | 9 +- packages/core/src/runtime/bridge.test.ts | 8 + packages/core/src/runtime/bridge.ts | 5 + packages/core/src/runtime/init.ts | 7 + packages/core/src/runtime/types.ts | 1 + .../player/src/hyperframes-player.test.ts | 150 +++++++++++++++- packages/player/src/hyperframes-player.ts | 40 ++++- packages/player/src/media-element-guards.ts | 14 ++ packages/player/src/parent-media.ts | 55 +++--- .../src/slideshow/SlideshowController.test.ts | 167 +++++++++++------- .../src/slideshow/SlideshowController.ts | 109 +++++------- .../slideshow/hyperframes-slideshow.test.ts | 84 +++++++++ .../src/slideshow/hyperframes-slideshow.ts | 100 ++++++++++- .../src/slideshow/slideshowPresenter.ts | 7 +- packages/player/src/styles.ts | 7 + packages/player/src/timeline-adapters.ts | 4 +- .../src/components/panels/SlideshowPanel.tsx | 11 -- .../components/panels/SlideshowSubPanels.tsx | 51 ++---- skills/slideshow/SKILL.md | 71 +++++++- .../references/standalone-harness.md | 82 ++++++++- 22 files changed, 784 insertions(+), 230 deletions(-) create mode 100644 packages/player/src/media-element-guards.ts diff --git a/packages/cli/src/commands/present.ts b/packages/cli/src/commands/present.ts index 7fae6f49cb..c96675adcf 100644 --- a/packages/cli/src/commands/present.ts +++ b/packages/cli/src/commands/present.ts @@ -174,7 +174,7 @@ function buildPresentPage(projectName: string, islandJson: string): string { - ${projectName} — Presenter + ${escHtml(projectName)} — Presenter @@ -188,6 +244,7 @@ The key insight: scene backgrounds must be `transparent` (not opaque) if you wan if (!el) continue; var active = t >= s.start && t < s.end; el.style.opacity = active ? "1" : "0"; + el.style.visibility = active ? "visible" : "hidden"; el.style.pointerEvents = active ? "auto" : "none"; if (active && lastActiveId !== s.id) { @@ -334,7 +391,11 @@ Omitting any scene (including branch scenes) from this manifest means the slides ## 6. Audio/SFX — built-in mute control via `` -Audio **must** live in the parent page, not the composition iframe. Browsers enforce user-activation for AudioContext and HTMLAudioElement.play() — an iframe without its own activation (i.e., the user never clicked inside it) is permanently autoplay-blocked. The user's keypress lands on the parent, so the parent is the only frame that can get the activation token. +Wrapper-owned SFX should live in the parent page. Browsers enforce user-activation for AudioContext and HTMLAudioElement.play() — an iframe without its own activation (i.e., the user never clicked inside it) is often autoplay-blocked. The user's keypress lands on the parent, so the parent is the reliable frame for click/transition sound effects. + +Normal slide media should stay in the composition. The slideshow player now stops slide media automatically on slide/sequence changes by calling `hyperframes-player.stopMedia()`, which pauses iframe `