Skip to content

feat: add reusable html-read-aloud skill for narrated dossiers #2

Description

@itse4elhaam

Summary

Create a reusable html-read-aloud skill that adds in-browser narration and synchronized scrolling to standalone HTML documents. Integrate it with readable-html-dossier so generated dossiers can optionally include a self-contained reading controller without requiring a server, browser extension, framework, or build step.

The narration feature should remain a separate composable skill rather than expanding readable-html-dossier into a large mixed-purpose skill.

Motivation

readable-html-dossier already produces semantic, standalone HTML files and opens them directly through a file:// URL. This makes it a good host for an inline reader powered by the browser's native Web Speech API.

The desired experience is:

  1. Open a generated dossier in the browser.
  2. Press Read aloud.
  3. Hear the document narrated block by block.
  4. See the active block highlighted and automatically scrolled into view.
  5. Pause, resume, stop, or move between blocks.

Architectural decision

Add a new skill:

.agents/skills/html-read-aloud/
├── SKILL.md
└── REFERENCES.md

html-read-aloud owns:

  • narration controls
  • semantic content extraction
  • speech queue management
  • active-block highlighting
  • synchronized scrolling
  • persistence of reader preferences/progress
  • accessibility requirements

readable-html-dossier continues to own:

  • document structure
  • typography and readability
  • themes
  • print styles
  • report-generation workflow

The dossier skill should invoke or reference html-read-aloud when narration is requested. Once stable, narration may become the default for interactive dossiers, with an explicit opt-out.

Proposed integration contract

Update readable-html-dossier/SKILL.md with guidance similar to:

When a dossier should support narrated reading, load /html-read-aloud and embed its standalone controller. Narration must work from a file:// URL and must not require a server or build step.

Generated HTML should expose a predictable reading root:

<article data-readable-root>
  ...
</article>

Optionally allow explicit inclusion/exclusion:

<section data-readable>...</section>
<pre data-reader-ignore>...</pre>
<nav data-reader-ignore>...</nav>

V1 scope

Content extraction

Build a deterministic list of readable blocks from the document root.

Default readable selectors:

h1, h2, h3, h4, p, li, blockquote, figcaption, td, th

Default ignored content:

script, style, nav, button, input, select, textarea,
[hidden], [aria-hidden="true"], [data-reader-ignore], pre, code

Rules:

  • Ignore empty or whitespace-only blocks.
  • Avoid reading nested elements twice.
  • Preserve semantic order from the DOM.
  • Collapse excessive whitespace.
  • Do not narrate raw URLs unless they are the meaningful visible text.
  • Code blocks are excluded by default but may be explicitly enabled later.

Speech model

Use window.speechSynthesis and SpeechSynthesisUtterance.

Use one utterance per semantic block rather than one utterance for the entire document.

Reasons:

  • more reliable synchronization
  • simple previous/next navigation
  • clean pause boundaries
  • easier progress persistence
  • no dependency on inconsistent word-boundary events

For each block:

  1. Create an utterance from normalized textContent.
  2. On start, mark the corresponding element active and scroll it into view.
  3. On end, advance to the next block.
  4. On error, surface a non-blocking status and stop safely.

Reader controls

Add a compact floating controller containing:

  • Play / resume
  • Pause
  • Stop
  • Previous block
  • Next block
  • Playback-rate selector
  • Voice selector
  • Auto-follow toggle
  • Progress indicator, for example 12 / 84

Recommended keyboard shortcuts:

Shortcut Action
Space Play/pause when focus is in the reader controller
Escape Stop narration
Alt+ArrowLeft Previous block
Alt+ArrowRight Next block

Do not hijack keyboard input while the user is typing in a form control.

Highlighting and scrolling

Apply an active class or attribute:

<p data-reader-active="true">...</p>

Expected behavior:

  • Highlight the active block with a subtle background/border treatment.
  • Use scrollIntoView({ behavior: "smooth", block: "center" }) when auto-follow is enabled.
  • Respect prefers-reduced-motion; use instant scrolling when reduced motion is requested.
  • Avoid continuous forced scrolling if the user manually scrolls away.
  • Provide an explicit auto-follow toggle to re-enable centering.

State management

Model the reader as a small state machine:

idle -> playing -> paused -> playing
playing -> stopped
playing -> completed
any state -> error

Suggested state:

{
  blocks: HTMLElement[],
  currentIndex: number,
  status: "idle" | "playing" | "paused" | "stopped" | "completed" | "error",
  rate: number,
  voiceURI: string | null,
  autoFollow: boolean
}

Always call speechSynthesis.cancel() before starting a new queue to prevent overlapping narration.

Persistence

Use localStorage with a document-specific key derived from the pathname/title.

Persist:

  • selected voice URI
  • playback rate
  • auto-follow preference
  • last completed block index

Do not auto-start narration on page load. Browser autoplay/user-gesture restrictions should be respected.

Accessibility

  • Controls must be keyboard operable.
  • Every icon-only control must have an accessible label.
  • Status updates should use a restrained aria-live="polite" region.
  • Active highlighting must not rely on color alone.
  • Focus indicators must remain visible.
  • The controller must remain usable at 200% zoom and narrow laptop/mobile widths.
  • Print styles must hide the controller and active-reading decoration.

Privacy and dependencies

V1 must:

  • run entirely in the browser
  • use the browser's installed/native voices
  • make no network requests for narration
  • require no external JavaScript dependencies
  • work from a local file:// URL

Cloud TTS, generated audio, and server-side timestamp alignment are explicitly out of scope for V1.

Suggested skill contents

html-read-aloud/SKILL.md

Document:

  • when to use the skill
  • required HTML semantics
  • extraction rules
  • required controls
  • speech queue behavior
  • synchronization behavior
  • accessibility requirements
  • file:// constraints
  • verification checklist

html-read-aloud/REFERENCES.md

Include a reusable implementation scaffold with:

  • CSS for the controller and active block
  • semantic controller markup
  • dependency-free JavaScript implementation
  • content extraction helper
  • voice-loading behavior, including voiceschanged
  • queue/state management
  • localStorage persistence
  • reduced-motion handling
  • cleanup on beforeunload

The reference implementation should be designed for agents to embed directly into generated standalone HTML.

Implementation phases

Phase 1: functional prototype

  • Create the new skill files.
  • Implement block extraction.
  • Implement play, pause, stop, previous, and next.
  • Highlight and scroll to the active block.
  • Verify operation from a local file:// URL in Edge/Chromium.

Phase 2: reusable integration

  • Update readable-html-dossier to reference the new skill.
  • Add the data-readable-root convention to the dossier scaffold.
  • Add opt-in/opt-out instructions.
  • Ensure PR, Linear, and code-review dossier skills inherit the behavior through readable-html-dossier rather than duplicating it.

Phase 3: polish

  • Voice and rate selectors.
  • Preference/progress persistence.
  • Manual-scroll/auto-follow behavior.
  • Keyboard shortcuts.
  • Responsive and accessibility refinements.

Acceptance criteria

  • A new html-read-aloud skill exists and is independently reusable.
  • A generated standalone HTML file can narrate itself from a file:// URL.
  • Narration progresses block by block in DOM order.
  • The active block is visibly highlighted.
  • The active block scrolls into view when auto-follow is enabled.
  • Play, pause, resume, stop, previous, and next work without overlapping speech.
  • Voice and playback rate can be changed.
  • Reader preferences and progress survive a page refresh.
  • Controls are keyboard accessible and usable at 200% zoom.
  • Reduced-motion preferences are respected.
  • Code, navigation, controls, and explicitly ignored regions are not narrated by default.
  • The controller is hidden when printing.
  • No server, build step, framework, browser automation, or external JS dependency is required.
  • readable-html-dossier documents how and when to compose the new skill.
  • Existing dossier-producing skills can gain narration without copying implementation instructions.

Test plan

Test with a generated dossier containing:

  • multiple heading levels
  • long and short paragraphs
  • ordered and unordered lists
  • cards and callouts
  • tables
  • links
  • code blocks
  • hidden and ignored regions
  • dark and light themes

Verify at minimum in the user's primary browser, Microsoft Edge on Linux, and one additional Chromium browser if available.

Manually verify:

  • pause/resume in the middle of a block
  • stop and restart
  • previous/next at document boundaries
  • switching voices after voices load asynchronously
  • refreshing and restoring progress
  • manual scrolling while narration continues
  • print preview
  • 200% zoom
  • reduced-motion mode

Non-goals for V1

  • word-by-word karaoke highlighting
  • cloud-generated or premium AI voices
  • audio-file export
  • sentence-level timestamps from a server
  • cross-device progress synchronization
  • automatic narration on page load
  • browser extension support

Future enhancements

  • opt-in code-block narration with language-aware preprocessing
  • sentence-level highlighting where browser support is reliable
  • cloud TTS adapters with cached audio and timestamps
  • chapter navigation from document headings
  • estimated time remaining
  • pronunciation overrides for technical terms and acronyms

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions