Skip to content

Fix export hanging at "preparing" and black preview after long minimize - #974

Open
finartcom wants to merge 1 commit into
webadderallorg:mainfrom
finartcom:fix/export-hang-and-preview-black-screen
Open

finartcom wants to merge 1 commit into
webadderallorg:mainfrom
finartcom:fix/export-hang-and-preview-black-screen

Conversation

@finartcom

@finartcom finartcom commented Sep 16, 2026

Copy link
Copy Markdown

Summary

  • Export hangs forever at "preparing": ModernVideoExporter.export() calls collectRuntimeDiagnostics() as its very first step, before any progress is ever reported. That awaits window.electronAPI.getExportHardwareInfo(), whose main-process handler awaits app.getGPUInfo("complete") with no timeout — a documented Electron footgun that can hang indefinitely (never resolve or reject) when the GPU process is crashed, disabled, or blocklisted. With no timeout anywhere in that chain, the whole export pipeline silently stalls at "preparing" forever, with no error ever surfaced to the user. Fixed by racing app.getGPUInfo("complete") against a 3s timeout in electron/ipc/export/native-video.ts, plus a defense-in-depth timeout around both diagnostics IPC calls on the renderer side in modernVideoExporter.ts.
  • Black preview after minimizing the editor for a long time: the live preview renders through a PixiJS WebGL/WebGPU canvas (VideoPlayback.tsx). Windows can reclaim GPU resources from a window that's been minimized/occluded for a long time, silently killing the WebGL context — nothing in the app listened for webglcontextlost/contextrestored or visibilitychange, so the canvas stayed permanently black until the user fully quit and relaunched the app. Added a webglcontextlost listener that forces a full teardown/recreate of the Pixi renderer (via a rendererGeneration counter, reusing the existing solid cleanup logic), plus a visibilitychange safety net that does the same after the window was hidden for over a minute, to also cover the WebGPU backend (which doesn't fire that event) and a stalled hidden <video> decoder session.

Test plan

  • npx tsc --noEmit
  • npx vitest run (1182 passing, 1 skipped, unrelated to this change)
  • Manual verification on Windows: leave the editor minimized for 1+ minute, confirm the preview recovers instead of staying black; trigger an export and confirm it no longer hangs indefinitely at "preparing" (could not fully reproduce/verify the GPU-hang path locally without a machine in the exact failure state, so please confirm in review/testing)

Summary by CodeRabbit

  • Bug Fixes
    • Video exports no longer remain blocked indefinitely when hardware or application diagnostics fail to respond.
    • Export processing can continue when diagnostic information is unavailable or times out.
    • Video playback now recovers after WebGL context loss.
    • Playback renderer state is refreshed when returning to the app after being hidden for an extended period.

…g minimize

Export hang: ModernVideoExporter.export() awaits collectRuntimeDiagnostics()
as its very first step, before any progress is reported. That function calls
window.electronAPI.getExportHardwareInfo(), whose main-process handler awaits
app.getGPUInfo("complete") with no timeout. That Electron API can hang
indefinitely (never resolve or reject) when the GPU process is crashed,
disabled, or blocklisted, which silently stalls the entire export pipeline at
the "preparing" phase forever with no error ever surfaced. Race it against a
3s timeout in the main process, and add a defense-in-depth timeout around both
diagnostics IPC calls on the renderer side.

Black preview after minimizing: the editor's live preview renders through a
PixiJS WebGL/WebGPU canvas (VideoPlayback.tsx). Windows can reclaim GPU
resources from a window minimized/occluded for a long time, silently killing
the WebGL context with no recovery — nothing listened for
`webglcontextlost`/`contextrestored` or `visibilitychange` anywhere in the
app, so the canvas stayed permanently black until a full app relaunch. Add a
`webglcontextlost` listener that forces a full teardown/recreate of the Pixi
renderer (via a `rendererGeneration` counter), plus a `visibilitychange`
safety net that does the same after the window was hidden for over a minute,
to also cover the WebGPU backend (which doesn't fire that event) and stalled
hidden-<video> decoder sessions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 82773a21-4d0d-46ed-99e3-300a16f2dc52

📥 Commits

Reviewing files that changed from the base of the PR and between b3ea775 and 7aaeffe.

📒 Files selected for processing (3)
  • electron/ipc/export/native-video.ts
  • src/components/video-editor/VideoPlayback.tsx
  • src/lib/exporter/modernVideoExporter.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Changes

The PR adds Pixi renderer recovery for WebGL context loss and extended document hiding. It also bounds Electron export diagnostic requests with timeouts so stalled GPU or application information calls do not block export.

Runtime resilience

Layer / File(s) Summary
Pixi renderer recovery
src/components/video-editor/VideoPlayback.tsx
VideoPlayback recreates the Pixi renderer after WebGL context loss or at least 60 seconds of document hiding. Cleanup removes the context-loss listener before renderer destruction.
Export diagnostic timeouts
src/lib/exporter/modernVideoExporter.ts, electron/ipc/export/native-video.ts
Application-version and hardware-information requests use timeouts. A timed-out GPU request leaves hardware diagnostics empty and does not block export.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: webadderall

Sequence Diagram(s)

sequenceDiagram
  participant Document
  participant VideoPlayback
  participant PixiRenderer
  Document->>VideoPlayback: emit webglcontextlost or resume after extended hiding
  VideoPlayback->>PixiRenderer: destroy existing renderer
  VideoPlayback->>PixiRenderer: initialize renderer for new generation
Loading

Merge Risk: ⚪ Minimal · up to 7aaef

No actionable regression remains; the bounded diagnostics and renderer recovery changes are ready to merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes both primary changes: preventing export stalls at "preparing" and recovering the preview after prolonged minimization.
Description check ✅ Passed The description clearly explains both problems, the implemented fixes, and the test results. It includes a testing guide and identifies pending manual Windows verification. It does not use all templat…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant