Skip to content

feat(core): frame-range capture, pinned encoder params, and an upload sink for capture-video templates - #43

Merged
hblee12294 merged 1 commit into
mainfrom
feat/capture-range-encoder-upload
Jul 17, 2026
Merged

feat(core): frame-range capture, pinned encoder params, and an upload sink for capture-video templates#43
hblee12294 merged 1 commit into
mainfrom
feat/capture-range-encoder-upload

Conversation

@hblee12294

@hblee12294 hblee12294 commented Jul 17, 2026

Copy link
Copy Markdown
Member

What

Four additive capabilities for generateRenderTemplate's capture-video mode, plus a determinism fix in the capture loop:

  • capture.range?: { startFrame, endFrame } — render only a sub-range of the composition as an independent segment: frames are evaluated at their global timeline time, but captured with segment-local timestamps (the file starts at t=0 and begins on a keyframe by construction). Because vos evaluation is a pure function of time, disjoint ranges render correctly in isolation — hosts can distribute a long render across workers, or resume a partial one, and concatenate the segments externally. Validated against ceil(duration × fps).
  • capture.encoder?: { codec?, bitrate? } — pin encoder settings explicitly instead of relying on format defaults, so every segment of one render is guaranteed to share a single encoder configuration (the precondition for lossless stream-copy concatenation). Defaults are unchanged: avc for mp4, vp9 for webm, QUALITY_HIGH.
  • capture.uploadUrl?PUT the finished bytes to a URL instead of embedding them as base64 in __renderComplete.data. Large outputs no longer have to marshal through a giant string. Fail-open: if the upload fails, the bytes are embedded as before with an uploadError field, so a completed render is never lost.
  • window.__renderProgress = { framesDone, totalFrames } — structured progress during the capture loop for host polling.
  • Determinism fix: the capture loop now sets __vos__.isPaused = true and uses the same two-phase waitForVideosReady settle as the client-side exporter (seek → wait decodes → rAF → re-check decodes → gl.finish()), so compositions with video sources capture frame-accurately server-side.

Compatibility

Fully backward compatible: with no new options the emitted loop is behaviorally identical (startFrame = 0, endFrame = ceil(duration × fps), local timestamps equal global ones, same default codecs/bitrate, base64 embedding unchanged apart from the added video settle + progress writes).

Tests

13 new template assertions (range emission + local-timestamp expression, range validation matrix, default vs pinned encoder settings, upload vs embed paths, progress/settle/isPaused) — 29 pass in renderTemplate.test.ts, 123 pass across the core suite; typecheck, lint, and build clean. Changeset: minor.

🤖 Generated with Claude Code

…ess for capture-video templates

- capture.range { startFrame, endFrame }: render a sub-range of the
  composition as an independent segment — frames are evaluated at their
  global timeline time but captured with segment-local timestamps, so a
  host can render disjoint ranges (distributed or resumable rendering) and
  concatenate the files externally. Validated against ceil(duration*fps).
- capture.encoder { codec, bitrate }: pin encoder settings explicitly so
  every segment of one render shares a single configuration; defaults
  unchanged (avc/vp9 by format, QUALITY_HIGH).
- capture.uploadUrl: PUT the finished bytes instead of embedding base64 in
  __renderComplete; fail-open to embedding with an uploadError field so a
  render is never lost. Avoids marshalling large outputs through strings.
- window.__renderProgress = { framesDone, totalFrames } during the loop.
- deterministic video handling in the capture loop: __vos__.isPaused = true
  and the two-phase waitForVideosReady settle (matching the client
  exporter), so compositions with video sources capture frame-accurately.
@hblee12294
hblee12294 merged commit c6c5075 into main Jul 17, 2026
3 checks passed
@hblee12294
hblee12294 deleted the feat/capture-range-encoder-upload branch July 17, 2026 07:23
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