You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Windows] #3379's windowsHide fix landed in engine only — studio-server, lint and cli still spawn console binaries unhidden (fires during preview/Studio, not just render) #3500
Follow-up to #3379 (ffmpeg console windows, fixed) — the fix landed in packages/engine only. Console-subsystem binaries are still spawned without windowsHide: true from studio-server, lint and several cli paths, so on Windows console windows still pop up. Distinct from #3476 (detached: true spawns of Node itself) and #3430 (chrome-headless-shell).
The practical difference from #3379: those were render-time. These fire during ordinary Studio use.previewLifecycle starts the preview server with detached: true, so that server has no console of its own. Every console-subsystem child it spawns therefore gets a brand-new visible console window from Windows for the duration of the call — an ffprobe flash of ~100–400 ms, a waveform or proxy encode for seconds. Scrubbing a timeline or opening the colour-grading panel is enough to trigger it.
packages/engine/src/utils/runFfmpeg.ts already carries the explanatory comment after #3379:
windowsHide: ffmpeg/ffprobe are console-subsystem binaries, so without this Node opens a visible console window per spawn on Windows.
That reasoning applies verbatim to the sites below.
Root cause
Verified by reading the shipped bundle of 0.8.15 (node_modules/hyperframes/dist/cli.js) — none of these pass windowsHide:
The two powershell.exe calls and the taskkill call sit behind explicit process.platform === "win32" guards, i.e. they exist only to run on Windows, and still omit the one option that matters there. getProcessIdentity/getParentPid run one PowerShell per ancestry hop, so a single hyperframes preview --status / --list / --stop spawns several.
Corresponding sources (paths from a main checkout):
packages/studio-server/src/helpers/mediaMetadata.ts — execFile(ffprobe, …); called on preview-HTML build and by GET /api/projects/:id/media/metadata, which is uncached (one ffprobe per request) and is hit by the colour-grading panel
packages/studio-server/src/helpers/waveform.ts — spawn(ffmpeg, …) for audio peaks
packages/studio-server/src/helpers/proxyTranscoder.ts — the -filters HDR probe and the proxy transcode
packages/studio-server/src/helpers/mediaValidation.ts — spawnSync("ffprobe", …) on upload, no options at all
packages/lint/src/hevcPreviewLint.ts — one ffprobe per video asset, per lint run
On Windows, in any project with a video asset: npx hyperframes preview --background
Open the Studio, scrub the timeline, open the colour-grading panel
Watch the desktop — console windows flash open and closed
Also visible with just npx hyperframes preview --status (PowerShell spawns from orphanCleanup)
Expected behavior
No visible console windows during preview/Studio use, matching the post-#3379 behaviour of render.
Actual behavior
Console windows flash open and closed repeatedly while the Studio is open, and on every preview --status/--list/--stop.
Suggested fix
Add windowsHide: true at each site (a no-op on macOS/Linux, so it can be applied unconditionally). For the calls that pass no options object at all, add one.
It may be worth adding a lint rule or a shared spawnHidden() helper so this class of regression stops recurring — this is now the third issue in the same family (#3379, #3476, this one).
Two smaller things noticed while tracing, mentioned only because they are in the same code paths and not filed separately:
routes/preview.ts calls probeAssetCodec(file) per ?hf-proxy= asset request, deliberately before the 304 shortcut, and routes/media.tsGET …/media/metadata has no cache — both are uncapped ffprobe-per-request paths.
packages/cli/src/utils/autoUpdate.ts passes detached: trueandwindowsHide: true, which is the combination Windows resolves in favour of DETACHED_PROCESS (documented: CREATE_NO_WINDOW is ignored when DETACHED_PROCESS is set). Same conflict as [Windows] chrome-headless-shell.exe opens a visible console window on every render #3430's root cause, so the windowsHide there is not doing what it looks like it does.
Environment
Version 0.8.15 (latest)
Node.js v22.23.2 and v24.19.0 (win32 x64) — reproduced on both
OS Windows 11 Home 10.0.26200
CPU AMD Ryzen 7 5700U
FFmpeg 9.0 (Gyan build, winget)
Describe the bug
Follow-up to #3379 (ffmpeg console windows, fixed) — the fix landed in
packages/engineonly. Console-subsystem binaries are still spawned withoutwindowsHide: truefromstudio-server,lintand severalclipaths, so on Windows console windows still pop up. Distinct from #3476 (detached: truespawns of Node itself) and #3430 (chrome-headless-shell).The practical difference from #3379: those were render-time. These fire during ordinary Studio use.
previewLifecyclestarts the preview server withdetached: true, so that server has no console of its own. Every console-subsystem child it spawns therefore gets a brand-new visible console window from Windows for the duration of the call — an ffprobe flash of ~100–400 ms, a waveform or proxy encode for seconds. Scrubbing a timeline or opening the colour-grading panel is enough to trigger it.packages/engine/src/utils/runFfmpeg.tsalready carries the explanatory comment after #3379:That reasoning applies verbatim to the sites below.
Root cause
Verified by reading the shipped bundle of 0.8.15 (
node_modules/hyperframes/dist/cli.js) — none of these passwindowsHide::68030execFileP(getFfmpegBinary(), ["-hide_banner","-filters"]){ maxBuffer, timeout }:102626spawn(ffmpegPath, ["-hide_banner","-filters"]){ stdio }:100507execFileSync("taskkill", …)— inside aprocess.platform === "win32"branch{ stdio, timeout }:100542execFileSync("powershell.exe", ["-NoProfile","-NonInteractive","-Command", …])— win32-only branch{ encoding, timeout }:100571execFileSync("powershell.exe", …)— win32-only branch{ encoding, timeout }The two
powershell.execalls and thetaskkillcall sit behind explicitprocess.platform === "win32"guards, i.e. they exist only to run on Windows, and still omit the one option that matters there.getProcessIdentity/getParentPidrun one PowerShell per ancestry hop, so a singlehyperframes preview --status/--list/--stopspawns several.Corresponding sources (paths from a
maincheckout):packages/studio-server/src/helpers/mediaMetadata.ts—execFile(ffprobe, …); called on preview-HTML build and byGET /api/projects/:id/media/metadata, which is uncached (one ffprobe per request) and is hit by the colour-grading panelpackages/studio-server/src/helpers/waveform.ts—spawn(ffmpeg, …)for audio peakspackages/studio-server/src/helpers/proxyTranscoder.ts— the-filtersHDR probe and the proxy transcodepackages/studio-server/src/helpers/mediaValidation.ts—spawnSync("ffprobe", …)on upload, no options at allpackages/lint/src/hevcPreviewLint.ts— one ffprobe per video asset, per lint runpackages/cli/src/utils/orphanCleanup.ts—taskkill,powershell.exe×2packages/cli/src/browser/manager.ts—execSync("where chrome")→cmd.exepackages/cli/src/capture/captureCompositionFrame.ts—spawn(ffmpegPath, args)with no options objectpackages/cli/src/background-removal/pipeline.ts,packages/cli/src/browser/ffmpeg.ts,packages/cli/src/utils/webmAlphaCheck.ts,packages/cli/src/browser/preflight.tsSteps to reproduce
npx hyperframes preview --backgroundnpx hyperframes preview --status(PowerShell spawns fromorphanCleanup)Expected behavior
No visible console windows during preview/Studio use, matching the post-#3379 behaviour of
render.Actual behavior
Console windows flash open and closed repeatedly while the Studio is open, and on every
preview --status/--list/--stop.Suggested fix
Add
windowsHide: trueat each site (a no-op on macOS/Linux, so it can be applied unconditionally). For the calls that pass no options object at all, add one.It may be worth adding a lint rule or a shared
spawnHidden()helper so this class of regression stops recurring — this is now the third issue in the same family (#3379, #3476, this one).Two smaller things noticed while tracing, mentioned only because they are in the same code paths and not filed separately:
routes/preview.tscallsprobeAssetCodec(file)per?hf-proxy=asset request, deliberately before the 304 shortcut, androutes/media.tsGET …/media/metadatahas no cache — both are uncapped ffprobe-per-request paths.packages/cli/src/utils/autoUpdate.tspassesdetached: trueandwindowsHide: true, which is the combination Windows resolves in favour ofDETACHED_PROCESS(documented:CREATE_NO_WINDOWis ignored whenDETACHED_PROCESSis set). Same conflict as [Windows] chrome-headless-shell.exe opens a visible console window on every render #3430's root cause, so thewindowsHidethere is not doing what it looks like it does.Environment