Root-cause fix for edits being wiped after refresh: the studio's
inspector edits were patched client-side via regex matching in
sourcePatcher.ts, which silently failed for many compositions ("Unable
to patch" toast). Replaced with a server-side patch-element API endpoint
using linkedom for proper DOM parsing via querySelector.
Also fixes the WYSIWYG render bug where sub-composition CSS was not
applied. The CSS scoping generated descendant selectors when both
attributes coexist on the same host element. Fixed to use compound
selectors for the authored root.
Edit persistence:
- New POST /file-mutations/patch-element endpoint using linkedom
- persistDomEditOperations calls server instead of client regex
- 15 tests covering all patch operation types
Render CSS scoping:
- Compound selector for authored root on host element
- Regression test: wysiwyg-subcomp-css (baseline pending Docker)
- 3 unit tests + 1 integration test
GSAP CDN fallback:
- Preview: error-handler catches gsap 404 and loads from CDN
- Producer: rewrites missing local gsap paths to CDN before compile
Studio resilience:
- Error boundary with recoverable UI
- Lazy mediabunny import prevents crash cascade
- Hash routing listens for hashchange events
- Sub-composition duration reads data-hf-authored-duration fallback
- Save debounce 600ms to requestAnimationFrame
Observability:
- PostHog telemetry for crashes, save failures, tab switches, playback,
toolbar actions, navigation, and render starts
* fix(studio): auto-reconnect when preview server is not running
When the preview server is not reachable (tab reload after server died,
or opening the URL before running npm run dev), the Studio was silently
swallowing the fetch error and rendering an infinite pulsing dot with no
recovery path. Users had no idea what happened.
Instead of showing an error and asking the user to act, the Studio now
polls /api/projects every 2 seconds and automatically transitions into
the full editor the moment the server becomes available — no manual
reload required.
Also fixes how agents are instructed about the dev server: CLAUDE.md and
AGENTS.md listed `npm run dev` as a one-liner comment identical to other
commands, giving no indication it blocks until stopped. Agents (including
Claude Code) were running it in foreground, timing out after ~2 minutes,
and silently killing the server. Added an explicit note that it must be
started as a background process.
* fix(studio): auto-reconnect when preview server is not running
Two issues combined to produce the "reloading the tab kills the whole"
experience for users running with an AI agent:
1. Agents silently killed the server — CLAUDE.md/AGENTS.md listed
npm run dev with no indication it blocks. Agents ran it in foreground,
the Bash tool timed out, and the process died. Added an explicit
run_in_background instruction.
2. Studio had no recovery path — fetch errors were swallowed, leaving
a permanent pulsing dot with no way out. Now the Studio polls every
2s and auto-transitions the moment the server responds.
Also fixes the bookmark-reload case: the hash path previously bailed out
before pinging the server, so a dead server + saved URL produced a blank
editor instead of the waiting state. The server is now always contacted
first, regardless of whether a hash project ID is present.
Timer cleanup (cancelled flag + clearTimeout) prevents setState on
unmounted components under StrictMode dev re-mounts.
Extracted into useServerConnection hook to keep App.tsx under the 500
LOC limit.