---
name: wiki-readme-slideshow
description: Build a narrated, fullscreen-capable slideshow INSIDE a wiki page's readme.html - per-slide TTS audio, arrow-key navigation, auto-advance on audio end - without losing the markdown README (fold it in below the show). Born on the adom-theme page (2026-08-02, John's ask while driving). Trigger words - readme slideshow, narrated readme, slideshow in readme, audio tour, page tour, narrated tour, embeddable slideshow, readme with audio, slide deck on a wiki page.
---

# A narrated slideshow inside readme.html

The live reference implementation is `adom/adom-theme` (readme.html + docs/slides/*.mp3).
Read `wiki-readme-html` FIRST - every sandbox rule there applies. This skill adds the
slideshow recipe on top.

## The shape

1. **Slides are the page's existing images** - reference them by absolute
   `/blob/<type>/<slug>/...` URLs (same-origin media loads fine in the sandbox; fetch does
   not). Do NOT re-encode images as base64; keep readme.html small.
2. **One TTS clip per slide** - `adom-tts say "<15-25s script>" --out slideN.mp3` (no
   --play; you are synthesizing files, not narrating). Push the mp3s to the page repo
   (e.g. `docs/slides/`) and reference them by `/blob/...` URLs in `<audio>`.
3. **The player** - one `<img>` stage + caption + a control bar:
   - Play button toggles the narrated tour: sets `audio.src` per slide, `audio.play()`.
   - `audio.onended` advances to the next slide while playing (auto-advance).
   - Back/Forward buttons + ArrowLeft/ArrowRight keydown, and dot navigation.
   - A Fullscreen button calling `requestFullscreen()` WITH a `.catch(()=>{})` - see
     the sandbox caveat below.
4. **Keep the markdown**: readme.html SHADOWS README.md on the page, so convert README.md
   to HTML (`python3 -c "import markdown..."` with `tables,fenced_code`) and append it
   below the show. Keep README.md in the repo for the Files tab and clone readers; every
   page-visible edit now goes through the readme.html rebuild.
5. **Height contract**: fixed-pixel stage (NEVER vh - the resize feedback loop), plus the
   standard readme-height postMessage reporter from wiki-readme-html.

## Sandbox truths that shape the design

- In the page's iframe (`sandbox="allow-scripts allow-downloads"`) there is **no
  allow-fullscreen**: `requestFullscreen()` rejects. The show still works embedded; catch
  the rejection silently. TRUE fullscreen happens on the raw endpoint:
  `https://wiki.adom.inc/readme/<owner>/<type>/<slug>?variant=public` is your file served
  top-level - no sandbox, fullscreen and audio both work. That URL is what you open in pup
  to present the show on the user's screen (window-maximize via `desktop_set_window_state`;
  valid states are maximize|minimize - there is no "fullscreen" state).
- **Audio needs a user gesture.** Embedded: the visitor clicks Play. Presenting via pup:
  `browser_click {selector:'#play'}` is CDP input = a real gesture that unlocks audio
  (a pup `browser_eval` .click() is NOT trusted and audio stays blocked). Note the pup
  click can report "timed out" yet have landed - verify by screenshot (button state), not
  by the error.
- No fetch, no popups, no wiki API - the show is display-only. All state in-page.

## Publish checklist

- `readme.html` at the publish-tree root AND listed in package.json `files[]`, then
  `pkg publish` (the page renders the PUBLISHED layer) AND `repo push` readme.html + the
  mp3s (the /blob URLs serve the repo layer). Do both or you get a stale/half page.
- Verify: curl the readme endpoint and md5-compare your bytes; open the page in pup
  (iframe mode renders, styles applied, height grows past the 600px fallback); trusted-
  click Play and confirm audio + auto-advance.
- Narration etiquette: clips are page content, not adom-tts player traffic - do NOT also
  narrate the same content through the shared player at the same time; the two audio
  paths overlap on the user's speakers.
