CHANGELOG.md

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.5] - 2026-05-10

### Fixed

- The overlay component would silently render empty in some host apps
  even though the router macro had been called and the route was
  reachable. Root cause: the macro's `Application.put_env(:demo_director,
  :mount_path, ...)` ran inline at compile time, which writes to
  whichever BEAM is doing the compile. During Mix-driven workflows
  (initial `mix phx.server`, fresh-clone `mix setup` flows, some hot
  reloads) that's often a short-lived compiler subprocess whose env
  dies before the dev server's runtime BEAM ever sees it — so the
  overlay component looked up `mount_path` at runtime, found nil, and
  rendered empty markup. Macro now computes the full scoped path at
  compile time (where `Phoenix.Router.scoped_path/2` works), bakes it
  into a module attribute, and registers it via an `@on_load` callback
  that fires every time the router module is loaded into a BEAM. Cold
  boot, hot reload, code purge + reload — all paths converge on a
  registered runtime env. README troubleshooting section adds the
  `config :demo_director, mount_path: "/path"` escape hatch for
  unusual release-build / umbrella-app setups where `@on_load` doesn't
  fire as expected.

## [0.1.4] - 2026-05-10

### Changed

- Install task's agent-instructions template (the content that gets
  dropped into AGENTS.md / CLAUDE.md) was still telling agents "Never
  invent a CSS selector" and describing `data-demo-id` as mandatory.
  The runtime has accepted raw CSS selectors as a fallback since
  0.1.2, so the contract was a version behind reality. Template now
  recommends picking the most stable handle that already exists in
  the host's markup — semantic ids, form-field ids that `<label
  for="">` points at, distinctive attributes — and to reach for
  `data-demo-id` only when no such handle exists. `:nth-child`
  chains and deep descendant paths are still called out as fragile.
  Existing installations keep their old AGENTS.md / CLAUDE.md
  content; rerun `mix igniter.install demo_director` to refresh.

### Documentation

- README's selector-contract section rewritten to match the template
  change above, plus a pacing note for LiveView-driven inputs with
  `phx-debounce` (callers should allow the debounce window plus a
  server roundtrip — ~600–1200ms total — before reading the
  resulting DOM state). Production-stripping section now describes
  the deferred sandboxed demo-session primitive inline rather than
  pointing at an internal MEMORY.md.

## [0.1.3] - 2026-05-10

### Documentation

- README's "Replay a saved demo" section pointed at the wrong URL —
  `/dev/director/demos` — which neither the install task nor the
  router macro's default produce. Updated to `/dev/demo-director`,
  matching the macro's `@default_path`. Same fix applied to the
  `mix demo_director.play` example URL.
- README now mentions that the listing page is reachable at the bare
  mount path (`<mount>`) in addition to `<mount>/demos` (added in
  0.1.2 but not surfaced in the docs).
- README's manual wire-up section for the router macro previously
  used `demo_director "/director"`, which conflicted with what the
  install task generates and produced confusing URLs. Aligned to
  `demo_director "/demo-director"` so the docs match the installer.

## [0.1.2] - 2026-05-10

### Added

- The install task now also adds the playback socket to your
  endpoint (after the existing `Phoenix.LiveView.Socket`
  declaration) and writes `config :demo_director, pubsub: <OtpApp>.PubSub`
  into `config/dev.exs`. The post-install notice shrinks from three
  manual steps to one (the overlay-component HEEx edit), which stays
  manual on purpose because root layouts aren't AST-editable.
  Both new edits are idempotent — the task searches for an existing
  `DemoDirector.PlaybackSocket` socket declaration / `:demo_director`
  config block before adding.
- Selector resolver in the runtime now falls back to
  `document.querySelector` when a string isn't found via
  `data-demo-id`. Lets demos target existing semantic ids
  (`#vitals`), classes (`.btn-primary`), or any other CSS selector
  the host app already has, without forcing ad-hoc `data-demo-id`
  annotations. `data-demo-id` lookup is still tried first, so the
  recommended idiom is unchanged.
- `fillTyped` now dispatches a synthetic `keyup` event per character
  alongside the existing `input` event. Hosts that listen via
  `phx-keyup` (rather than `phx-change`) now react to typed input
  during demo playback.
- Demos listing page is now reachable at the bare mount path (e.g.
  `/dev/demo-director`) in addition to the original `<mount>/demos`.
  Both URLs render the same listing.
- Listing-page styling switched to a purple palette (Elixir-ish
  lavender on deep purple). The Play button stays red for contrast.
  The demo overlay (subtitle bar, highlight ring) is intentionally
  unchanged — it stays neutral so it works visually on any host
  app's color scheme.

### Fixed

- `mix igniter.install demo_director` crashed with
  `FunctionClauseError in Rewrite.update!/2` while seeding `AGENTS.md`
  / `CLAUDE.md`. The install task's updater callback returned a raw
  string instead of the `Rewrite.Source` that
  `Igniter.create_or_update_file/4` expects from its 4th argument.
  Updates the source's `:content` via `Rewrite.Source.update/3`.
- The router edit was not idempotent: re-running the install task
  appended a duplicate `if Application.compile_env(:my_app, :dev_routes)`
  block on every run. The task now searches for an existing
  `import DemoDirector.Router` call before adding, mirroring the
  pattern used by the Tidewave installer.
- Subtitle bar's text was bidi-flipped on hosts with
  `<html dir="rtl">` — English content's punctuation could land on
  the wrong side. Subtitle node now carries `dir="auto"` so its
  visual direction is determined by the first strong character of
  the subtitle text itself, regardless of the host page's direction.

### Documentation

- README's "Add to your Phoenix app" section notes that
  `demo_director` assumes the host app has a working Phoenix
  LiveView setup; the installer does not bootstrap LiveView from
  scratch.
- The README's manual wire-up step for the overlay component now
  explains why that step stays manual (HEEx isn't AST-editable like
  Elixir, so editing root layouts programmatically would be
  string-level surgery on a frequently-customized file) and notes
  that the component is prod-safe to leave unconditionally inside
  `<body>` (it returns empty markup when no mount path is
  registered). The install task's post-install notice carries the
  same explanation in shorter form.

## [0.1.1] - 2026-05-10

### Changed

- Reworded package description / README tagline to lead with what the
  package does ("Narrated, highlighted, animated demos for Phoenix
  LiveView") before the workflow tagline.
- Added Hex.pm and HexDocs badges to the README.

## [0.1.0] - 2026-05-10

### Added

- Helper API: `subtitle/1`, `highlight/1`, `fill/2`, `fill_typed/3`,
  `click/1`, `wait/1`. Each emits a JS string the agent passes to
  `browser_eval` (or that gets saved into a `.exs` script).
- HEEx integration via `demo_id/1` for stable selectors through LiveView
  patches.
- Overlay component (`demo_director_overlay`) rendering a
  word-by-word-revealed subtitle bar and a target-tracking highlight ring.
- Router macro (`demo_director "/director"`) mounting:
  - static assets (CSS + JS) at `<mount>/demo_director.{css,js}`
  - a web demos browser at `<mount>/demos` listing every saved demo
  - a per-demo JSON endpoint at `<mount>/demos/<name>.js`
  - a playback POST endpoint at `<mount>/play` (localhost-only)
- Phoenix channel + socket (`DemoDirector.PlaybackSocket`) that
  relays demo JS broadcasts to every connected overlay.
- `mix demo_director.play <name>` task that POSTs a saved demo's JS
  to the running dev server. Reads `# @start_at "/path"` metadata from
  the demo file and navigates the browser there before running.
- Igniter-based install task (`mix igniter.install demo_director`)
  that wires the router macro and seeds AGENTS.md / CLAUDE.md with the
  agent contract.