---
name: theatrical-html-reader
description: Design system and code patterns for turning a long literary/theatrical text (play, poem, libretto, script) into a polished, standalone, single-file HTML reading edition — with light/dark/system theming, selectable accent colors, a collapsible table-of-contents drawer, draggable floating controls, and localStorage-based preference persistence. Use this whenever the user wants to convert a manuscript, play script, or long-form text into a styled HTML page, especially if they mention a reading theme, dark mode, a table of contents menu, or want the result to feel like a designed reading app rather than a plain document. Also use when asked to add theme pickers, hamburger/TOC menus, draggable UI controls, or "remember my settings" behavior to an existing HTML artifact — the patterns and known pitfalls here (see gotchas.md) apply broadly, not just to plays.
---
# Theatrical HTML reader
A reusable design system for converting long structured texts (plays, poems,
libretti) into single-file, distraction-light HTML reading editions. Built
and refined over several iterations — reuse it rather than re-deriving these
choices from scratch.
## When to use this
- "Convert this play/script/poem into HTML"
- "Make this a nice reading page with dark mode"
- "Add a table of contents menu" / "hamburger menu"
- "Let users pick a color theme"
- "Make the floating buttons draggable" / "remember user preferences"
Even for a request that only touches one piece (e.g. "just add dark mode"),
check `references/gotchas.md` first — several of these patterns have subtle
failure modes that are easy to reintroduce.
## Design decisions (apply by default unless the user says otherwise)
**Typography**: pair a serif for reading (`Newsreader`) with a sans for UI
chrome — buttons, labels, TOC entries (`Inter`). Base size ~18–19px,
line-height 1.7–1.75. Don't shrink body font on mobile; only display
headlines shrink via `clamp()`.
**Color**: a small variable set, not a full design-token system —
`--ink`, `--ink-soft`, `--bg`, `--bg-panel`, `--accent`, `--rule`. Default to
a light, warm-neutral background (not stark white, not the generic cream
`#F4F1EA`) with near-black ink, one restrained accent color used sparingly
(speaker names, act/scene numbers) rather than decorating everything.
**Theming**: three states — Light / Dark / System (`Auto`) — via
`data-theme` attribute on ``, plus a small set of selectable accent
colors via `data-accent`. Dark-mode accents need their own brighter values
(don't reuse the light-mode hex on a dark background — contrast breaks).
Full CSS variable structure: `assets/theme-system.css`.
**Floating controls**: keep navigation (TOC) and preferences (theme/accent)
as two separate, discreet corner icon buttons — don't combine them into one
menu. Each opens on tap/click; a real drag (past a ~6px threshold) instead
repositions the button. Both are draggable so a user can move a control off
of content it happens to overlap. See `assets/drag-reposition.html` and
`references/gotchas.md` (#1, #2, #7) before touching this — there's a
click-eating bug that's easy to reintroduce.
**Navigation pattern**: a full-height off-canvas drawer sliding from the
left edge for TOC/contents, with a dimming backdrop; closes on backdrop
click, ✕ button, Escape, or selecting a link. See `assets/toc-drawer.html`.
**Preferences panel pattern**: a small dropdown card anchored to its trigger
button, position recalculated on every open via `getBoundingClientRect()` so
it never overflows the viewport even after the trigger has been dragged. See
`assets/settings-dock.html`.
**Persistence**: `localStorage`, wrapped in `try/catch` with an in-memory
fallback, namespaced under one JSON blob (not many separate keys). Restore
theme/accent in a blocking `