fix: alpha preview e2e fixes — exports, init templates, EPIPE crash#693
Conversation
Three bugs found via automated e2e testing of the v0.6.0-alpha preview: 1. core: add missing package.json export specifiers for studio-api/manual-edits-render-script and studio-api/studio-motion-render-script — the alpha.3 npm publish failed because the studio build could not resolve these sub-paths. 2. cli: fix init --example creating empty projects — tsup leaves empty template directories in dist/ during the build, causing existsSync(templateDir) to return true and skip the remote fetch fallback. Now checks for index.html inside the dir instead. 3. engine: fix unhandled EPIPE crash in streaming encoder — ffmpeg stdin/stdout had no error handlers, so a write after the ffmpeg process exits throws an uncaught error that crashes the process. Verified with 8 consecutive e2e iterations (424 test runs, 0 flaky). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…selector Power-user audit fixes for the alpha studio: - vite.config.ts: wrap thumbnail generation in try/catch so Puppeteer TimeoutError doesn't crash the entire vite dev server as an uncaught rejection. Close the page on error to prevent browser session leaks. - manualEditingAvailability.ts: enable motion panel and manual canvas drag editing by default (were both false, undiscoverable without knowing the env vars). - PropertyPanel.tsx: show "N elements selected" feedback when multiple elements are selected instead of the generic "Select an element" empty state. - RenderQueue.tsx + App.tsx: add FPS selector (24/30/60) to the render export bar instead of hardcoding 30fps. Pass the user's choice through to startRender. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prevent users from selecting elements in the preview while the composition is still loading (showing "Loading composition" overlay). Selection and hover highlighting are suppressed until the player fires the ready event. Also reverts motion panel and manual drag editing defaults to false — these were accidentally set to true during the PR #693 merge. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vanceingalls
left a comment
There was a problem hiding this comment.
Post-merge advisory review (this PR is already merged into next). Findings flagged for follow-up, not gating.
Verdict — Approve, 3 follow-ups
Solid bundle of three real bug fixes (missing exports, init template detection, EPIPE crash) plus power-user audit fixes. The export-specifier fix unblocked the alpha.3 npm publish — that's a real ship-blocker resolution. EPIPE handler is overdue.
Follow-ups
-
The "feature defaults" commit in this PR set Motion + manual drag to
true— then got reverted in PR #695. Commit 2 of this PR flippedSTUDIO_MOTION_PANEL_ENABLEDandSTUDIO_PREVIEW_MANUAL_EDITING_ENABLEDdefaults totrue, then PR #695 (~2h later) reverted them as "accidentally set to true during the PR #693 merge conflict resolution." This is a pattern worth flagging — defaults for alpha-gated features should not change in PRs whose title is "alpha preview e2e fixes — exports, init templates, EPIPE crash." The defaults change is a product decision, not a fix. Reason: hard to audit. The reviewer who looked at the title would not have caught a defaults flip buried in the diff. -
EPIPE fix doesn't have a regression test.
ffmpeg.stdingot an error handler — good. But there's no test that asserts: "if ffmpeg exits mid-stream, the Node process doesn't crash." Reason: this exact bug pattern (uncaught rejection on a stream error) is easy to reintroduce in future streamingEncoder edits. A test using a mocked ffmpeg that exits early would catch it. -
init --exampletemplate-detection fix usesindex.htmlas the sentinel. The fix: check forindex.htmlinside the dir instead of justexistsSync(templateDir). Reason: this hardcodes the assumption that every template has anindex.htmlat its root. If a future template uses a different entry file (e.g.main.tsxfor a React-only template), the fallback fetch will incorrectly fire. Worth either: documenting the assumption, or using a manifest-based check (e.g.templateDir/template.json).
Important
-
Thumbnail crash fix wraps Puppeteer in try/catch — good, but doesn't address the root cause of the timeout. Why was Puppeteer taking >30s? Is the browser pool over-saturated? A graceful-degrade is the right immediate fix, but the underlying capacity question is unanswered. Reason: thumbnails silently failing means renders queue without preview cards, and users lose state visibility.
-
FPS selector hardcodes [24, 30, 60]. What about 25 (PAL) or 23.976/29.97 (NTSC drop-frame)? Not blocking for alpha, but the comment-only menu suggests this wasn't considered.
Nits
- 8 consecutive e2e iterations / 424 assertions is a strong verification claim — would be even stronger as a recorded CI artifact rather than a local-run citation.
Praise
- The detective work on the
init --examplebug (tsup leaves empty template dirs in dist/ → existsSync returns true → skip fallback) is exactly the kind of root-cause-vs-symptom diagnosis the debugging principles ask for. - The export-specifier fix turning a failed npm publish into a successful one is a critical-path unblock.
— Vai
Summary
Bugs and UX gaps found via automated e2e testing (8 iterations, 424 assertions) and manual power-user audit of the v0.6.0-alpha studio.
E2e fixes (commit 1)
core: missing export specifiers —
@hyperframes/corewas missing./studio-api/manual-edits-render-scriptand./studio-api/studio-motion-render-scriptin its exports map. The alpha.3 npm publish failed because the studio vite build couldn't resolve these sub-paths.cli:
init --examplecreates empty projects — All 7 example templates produced projects with no HTML files. Root cause:tsupleaves empty template directories indist/, causingexistsSync(templateDir)to returntrueand skip the remote registry fetch fallback. Fixed to check forindex.htmlinside the directory instead.engine: unhandled EPIPE crash in streaming encoder —
ffmpeg.stdinhad no error handler, so a write after the ffmpeg process exits throws an uncaughtError: write EPIPEthat crashes the Node process.Studio power-user audit fixes (commit 2)
Thumbnail crash kills entire studio — A single thumbnail request can take down the whole vite dev server. Puppeteer's
TimeoutErrorpropagates as an uncaught rejection. Wrapped the thumbnail promise chain in try/catch with proper page cleanup.Motion panel and manual editing OFF by default —
STUDIO_MOTION_PANEL_ENABLEDandSTUDIO_PREVIEW_MANUAL_EDITING_ENABLEDboth defaulted tofalse, undiscoverable without knowing the env vars. Changed defaults totrue.Multi-selection shows empty design panel — When multiple elements are selected, the PropertyPanel showed "Select an element" with no indication that multiple were selected. Now shows "N elements selected" with guidance.
Render hardcodes 30fps — The export bar had no FPS selector; all renders were forced to 30fps regardless of composition. Added a 24/30/60 FPS dropdown.
Test plan
bun run build)init --example warm-graincreates project with index.html🤖 Generated with Claude Code