Summary
When media.autoProxy is enabled and actually produces proxies, hyperframes preview enters a permanent reload loop. The Studio preview iframe re-navigates roughly every 700 ms, forever, with no file in the project ever changing.
The most visible symptom is that shader transitions never finish pre-capturing: the preview panel sits on "Preparing scene transitions — transition 1/5" indefinitely, and the preview is unusable. render and snapshot are unaffected, since they don't use the watcher / live-reload path.
Present in 0.7.61 through 0.7.88 (latest). Not platform-specific — reproduces on WSL2 and native Windows.
Root cause
A feedback loop between the media-proxy cache and the project file watcher.
- Serving a media proxy marks the cache entry as recently used, which rewrites the file's mtime (
../studio-server chunk):
function markCacheEntryUsed(cachePath) {
try {
const now = new Date();
utimesSync(cachePath, now, now);
} catch {}
}
-
The proxy cache lives inside the project directory — CACHE_DIR_NAME = ".transcode-cache".
-
src/server/fileWatcher.ts watches the project recursively, and its exclusion list does not contain .transcode-cache:
WATCHER_EXCLUDED_DIRS = new Set([
".cache", ".git", ".hyperframes", ".next", ".vite",
"build", "coverage", "dist", "node_modules", "outputs", "renders"
]);
DEBOUNCE_MS = 300;
So the mtime touch is indistinguishable from a real edit. The loop closes as:
serve proxy → utimesSync → watcher fires → SSE file-change on /api/events → Studio re-navigates the preview iframe (src + fresh _t) → composition re-requests its media → serve proxy → …
Observed period ≈ 700 ms (300 ms debounce + reload), and the server recompiles ~1.6×/sec indefinitely while otherwise idle.
Evidence
Listening directly on the SSE stream with the project completely idle — 14 events in 12 s, all for one file:
event: file-change
data: {"path":".transcode-cache/f0a349f28e3a0ff5b26294b2adbdf1305fc0c514c13dbcf27e3352ce61cd35f6.mp4"}
find . -newermt '-2 minutes' reports no changed project files during this. The cache files' mtimes are continuously reset to now.
Instrumenting shader-transition-state messages shows the shader pre-capture is not hung — it progresses normally (transition 5/5, frame 6/19 at t=33 s; a full pass needs ~33-40 s for 5 transitions at 1920×1080). Being restarted every ~700 ms, it never gets past the opening frames of transition 1, so the UI is pinned at "transition 1/5".
In DevTools this also shows up as the preview document request repeatedly reporting status (canceled) with 0.0 kB:
preview?__hf_shader_capture_scale=1&__hf_shader_loading=player
Each reload supersedes the in-flight navigation. Sub-resources (frame captures, media, fonts) in the same batch complete with 200/206, which makes it look like one specific request is failing when it's actually the iframe's own navigation being cancelled over and over.
Reproduction
- A project with
"media": { "autoProxy": true } and video assets that get proxied (e.g. VP9 .webm).
npx hyperframes preview
curl -sN http://localhost:<port>/api/events — observe a continuous stream of file-change events for .transcode-cache/*.mp4 with nothing being edited.
- With shader transitions configured via
HyperShader.init(...), the preview panel stays on "Preparing scene transitions — transition 1/5" forever.
Suggested fix
Add .transcode-cache to WATCHER_EXCLUDED_DIRS in src/server/fileWatcher.ts. .thumbnails looks like it has the same exposure — it's excluded in walkFiles/IGNORE_DIRS elsewhere but is likewise absent from the watcher list.
Alternatives worth considering: move the proxy cache out of the project tree, or skip the utimesSync keep-alive for entries whose mtime is already recent (it only needs LRU granularity, not per-request precision).
Workaround
Set "media": { "autoProxy": false } and delete .transcode-cache/. This is only viable when the sources are natively decodable by Chrome.
Worth noting for projects using transparent video: the proxy transcodes VP9/WebM to H.264 .mp4, which drops the alpha channel — so for transparent overlays the proxy is also lossy, independent of this bug.
Environment
- hyperframes 0.7.87 and 0.7.88
- Node v24.15.0
- WSL2 (Linux 6.18) — also reported on native Windows
- FFmpeg present, Docker not installed
Summary
When
media.autoProxyis enabled and actually produces proxies,hyperframes previewenters a permanent reload loop. The Studio preview iframe re-navigates roughly every 700 ms, forever, with no file in the project ever changing.The most visible symptom is that shader transitions never finish pre-capturing: the preview panel sits on "Preparing scene transitions — transition 1/5" indefinitely, and the preview is unusable.
renderandsnapshotare unaffected, since they don't use the watcher / live-reload path.Present in 0.7.61 through 0.7.88 (latest). Not platform-specific — reproduces on WSL2 and native Windows.
Root cause
A feedback loop between the media-proxy cache and the project file watcher.
../studio-serverchunk):The proxy cache lives inside the project directory —
CACHE_DIR_NAME = ".transcode-cache".src/server/fileWatcher.tswatches the project recursively, and its exclusion list does not contain.transcode-cache:So the mtime touch is indistinguishable from a real edit. The loop closes as:
serve proxy →
utimesSync→ watcher fires → SSEfile-changeon/api/events→ Studio re-navigates the preview iframe (src+ fresh_t) → composition re-requests its media → serve proxy → …Observed period ≈ 700 ms (300 ms debounce + reload), and the server recompiles ~1.6×/sec indefinitely while otherwise idle.
Evidence
Listening directly on the SSE stream with the project completely idle — 14 events in 12 s, all for one file:
find . -newermt '-2 minutes'reports no changed project files during this. The cache files' mtimes are continuously reset to now.Instrumenting
shader-transition-statemessages shows the shader pre-capture is not hung — it progresses normally (transition 5/5, frame 6/19 at t=33 s; a full pass needs ~33-40 s for 5 transitions at 1920×1080). Being restarted every ~700 ms, it never gets past the opening frames of transition 1, so the UI is pinned at "transition 1/5".In DevTools this also shows up as the preview document request repeatedly reporting status
(canceled)with 0.0 kB:Each reload supersedes the in-flight navigation. Sub-resources (frame captures, media, fonts) in the same batch complete with 200/206, which makes it look like one specific request is failing when it's actually the iframe's own navigation being cancelled over and over.
Reproduction
"media": { "autoProxy": true }and video assets that get proxied (e.g. VP9.webm).npx hyperframes previewcurl -sN http://localhost:<port>/api/events— observe a continuous stream offile-changeevents for.transcode-cache/*.mp4with nothing being edited.HyperShader.init(...), the preview panel stays on "Preparing scene transitions — transition 1/5" forever.Suggested fix
Add
.transcode-cachetoWATCHER_EXCLUDED_DIRSinsrc/server/fileWatcher.ts..thumbnailslooks like it has the same exposure — it's excluded inwalkFiles/IGNORE_DIRSelsewhere but is likewise absent from the watcher list.Alternatives worth considering: move the proxy cache out of the project tree, or skip the
utimesSynckeep-alive for entries whose mtime is already recent (it only needs LRU granularity, not per-request precision).Workaround
Set
"media": { "autoProxy": false }and delete.transcode-cache/. This is only viable when the sources are natively decodable by Chrome.Worth noting for projects using transparent video: the proxy transcodes VP9/WebM to H.264
.mp4, which drops the alpha channel — so for transparent overlays the proxy is also lossy, independent of this bug.Environment