diff options
| author | cashmere <cashmere@autistici.org> | 2026-07-28 19:41:14 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-07-28 19:41:14 +0200 |
| commit | e837e7504379e100ff3b56282577ec67bb88bec9 (patch) | |
| tree | eec7e6f964725a783a9e907e931862591bb46b55 /apps/web/src/services/renderer/scene-exporter.ts | |
| parent | da99dec8a2de1f3849aebbf5695c1e812b2dbdf9 (diff) | |
| download | opencut-e837e7504379e100ff3b56282577ec67bb88bec9.tar.gz | |
feat: ripple-extend resize, timeline filmstrip, export hardening
Yesterday's verified web session (gates green: 316 tests, tsc, build):
- ripple-extend pushes right-hand chain on static-element resize
- per-position video filmstrip thumbnails with zoom-adaptive density
- fps-aware export bitrate, 2s keyframes, even-dim export canvas
- freeze frame uses fixed 3s duration, prompt removed
Diffstat (limited to 'apps/web/src/services/renderer/scene-exporter.ts')
| -rw-r--r-- | apps/web/src/services/renderer/scene-exporter.ts | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/apps/web/src/services/renderer/scene-exporter.ts b/apps/web/src/services/renderer/scene-exporter.ts index 66df9485..04c14277 100644 --- a/apps/web/src/services/renderer/scene-exporter.ts +++ b/apps/web/src/services/renderer/scene-exporter.ts @@ -19,6 +19,7 @@ import { frameRateToFloat } from "@/fps/utils"; import type { RootNode } from "./nodes/root-node"; import type { ExportFormat, ExportQuality } from "@/export"; import { CanvasRenderer } from "./canvas-renderer"; +import { computeVideoBitrate } from "./export-encoding"; type ExportParams = { width: number; @@ -30,13 +31,15 @@ type ExportParams = { audioBuffer?: AudioBuffer; }; -const qualityMap = { +const audioQualityMap = { low: QUALITY_LOW, medium: QUALITY_MEDIUM, high: QUALITY_HIGH, very_high: QUALITY_VERY_HIGH, }; +const KEY_FRAME_INTERVAL_SECONDS = 2; + export type SceneExporterEvents = { progress: [progress: number]; complete: [buffer: ArrayBuffer]; @@ -99,9 +102,17 @@ export class SceneExporter extends EventEmitter<SceneExporterEvents> { target: new BufferTarget(), }); + const videoBitrate = computeVideoBitrate({ + width: this.renderer.width, + height: this.renderer.height, + fps: fpsFloat, + quality: this.quality, + }); + const videoSource = new CanvasSource(this.renderer.getOutputCanvas(), { codec: this.format === "webm" ? "vp9" : "avc", - bitrate: qualityMap[this.quality], + bitrate: videoBitrate, + keyFrameInterval: KEY_FRAME_INTERVAL_SECONDS, }); output.addVideoTrack(videoSource, { frameRate: fpsFloat }); @@ -122,7 +133,7 @@ export class SceneExporter extends EventEmitter<SceneExporterEvents> { audioSource = new AudioBufferSource({ codec: audioCodec, - bitrate: qualityMap[this.quality], + bitrate: audioQualityMap[this.quality], }); output.addAudioTrack(audioSource); } |
