summaryrefslogtreecommitdiff
path: root/apps/web/src/services/renderer/nodes/blur-background-node.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-13 04:41:17 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-13 05:08:29 +0200
commitcad88ee4d1c9e06e7529b88ef5e5d3fdf3f89149 (patch)
tree0bfc1fcb18b3da4969afa2836bb65e6a5e25d123 /apps/web/src/services/renderer/nodes/blur-background-node.ts
parent36efdf66e707c818b81009acf8a00630a0309ca1 (diff)
downloadopencut-cad88ee4d1c9e06e7529b88ef5e5d3fdf3f89149.tar.gz
refactor: rendering pipeline
Made-with: Cursor
Diffstat (limited to 'apps/web/src/services/renderer/nodes/blur-background-node.ts')
-rw-r--r--apps/web/src/services/renderer/nodes/blur-background-node.ts136
1 files changed, 10 insertions, 126 deletions
diff --git a/apps/web/src/services/renderer/nodes/blur-background-node.ts b/apps/web/src/services/renderer/nodes/blur-background-node.ts
index 4cb45b33..d20e2533 100644
--- a/apps/web/src/services/renderer/nodes/blur-background-node.ts
+++ b/apps/web/src/services/renderer/nodes/blur-background-node.ts
@@ -1,13 +1,6 @@
-import { buildGaussianBlurPasses, intensityToSigma } from "@/lib/effects/definitions/blur";
-import { mediaTimeToSeconds } from "opencut-wasm";
-import { getSourceTimeAtClipTime } from "@/lib/retime";
-import { videoCache } from "@/services/video-cache/service";
+import type { EffectPass } from "@/lib/effects/types";
import type { RetimeConfig } from "@/lib/timeline";
-import type { CanvasRenderer } from "../canvas-renderer";
-import { createOffscreenCanvas } from "../canvas-utils";
-import { gpuRenderer } from "../gpu-renderer";
import { BaseNode } from "./base-node";
-import { loadImageSource, type CachedImageSource } from "./image-node";
export type BlurBackgroundNodeParams = {
mediaId: string;
@@ -22,127 +15,18 @@ export type BlurBackgroundNodeParams = {
blurIntensity: number;
};
-type BackdropSource = {
+export type BackdropSource = {
source: CanvasImageSource;
width: number;
height: number;
};
-export class BlurBackgroundNode extends BaseNode<BlurBackgroundNodeParams> {
- private cachedImageSource: Promise<CachedImageSource> | null;
-
- constructor(params: BlurBackgroundNodeParams) {
- super(params);
- this.cachedImageSource =
- params.mediaType === "image" ? loadImageSource(params.url) : null;
- }
-
- private isInRange({ time }: { time: number }): boolean {
- const localTime = time - this.params.timeOffset;
- return localTime >= 0 && localTime < this.params.duration;
- }
-
- private getSourceLocalTime({ time }: { time: number }): number {
- const clipTime = time - this.params.timeOffset;
- return (
- this.params.trimStart +
- getSourceTimeAtClipTime({
- clipTime,
- retime: this.params.retime,
- })
- );
- }
-
- private async getBackdropSource({
- time,
- }: {
- time: number;
- }): Promise<BackdropSource | null> {
- if (this.params.mediaType === "video") {
- const sourceTimeTicks = this.getSourceLocalTime({ time });
- const frame = await videoCache.getFrameAt({
- mediaId: this.params.mediaId,
- file: this.params.file,
- time: mediaTimeToSeconds({ time: sourceTimeTicks }),
- });
-
- if (!frame) {
- return null;
- }
-
- return {
- source: frame.canvas,
- width: frame.canvas.width,
- height: frame.canvas.height,
- };
- }
-
- if (!this.cachedImageSource) {
- return null;
- }
-
- const { source, width, height } = await this.cachedImageSource;
- return { source, width, height };
- }
-
- async render({ renderer, time }: { renderer: CanvasRenderer; time: number }) {
- await super.render({ renderer, time });
-
- if (!this.isInRange({ time })) {
- return;
- }
-
- const backdropSource = await this.getBackdropSource({ time });
- if (!backdropSource) {
- return;
- }
-
- const offscreen = createOffscreenCanvas({
- width: renderer.width,
- height: renderer.height,
- });
- const offscreenCtx = offscreen.getContext("2d") as
- | CanvasRenderingContext2D
- | OffscreenCanvasRenderingContext2D
- | null;
- if (!offscreenCtx) {
- return;
- }
-
- const coverScale = Math.max(
- renderer.width / backdropSource.width,
- renderer.height / backdropSource.height,
- );
- const scaledWidth = backdropSource.width * coverScale;
- const scaledHeight = backdropSource.height * coverScale;
- const offsetX = (renderer.width - scaledWidth) / 2;
- const offsetY = (renderer.height - scaledHeight) / 2;
-
- offscreenCtx.drawImage(
- backdropSource.source,
- offsetX,
- offsetY,
- scaledWidth,
- scaledHeight,
- );
-
- const passes = buildGaussianBlurPasses({
- sigmaX: intensityToSigma({ intensity: this.params.blurIntensity, resolution: renderer.width, reference: 1920 }),
- sigmaY: intensityToSigma({ intensity: this.params.blurIntensity, resolution: renderer.height, reference: 1080 }),
- });
- const effectResult = gpuRenderer.applyEffect({
- source: offscreen as CanvasImageSource,
- width: renderer.width,
- height: renderer.height,
- passes,
- });
-
- renderer.context.drawImage(
- effectResult,
- 0,
- 0,
- renderer.width,
- renderer.height,
- );
- }
+export interface ResolvedBlurBackgroundNodeState {
+ backdropSource: BackdropSource;
+ passes: EffectPass[];
}
+
+export class BlurBackgroundNode extends BaseNode<
+ BlurBackgroundNodeParams,
+ ResolvedBlurBackgroundNodeState
+> {}