From 237248321a1a40b9b98e7e0a6df156d0aa247ef0 Mon Sep 17 00:00:00 2001 From: cashmere Date: Sun, 2 Aug 2026 19:59:32 +0200 Subject: feat: pan & zoom motion presets Ken Burns-style motion effects (zoom in/out, pan left/right/up/down) that drag onto clips like regular effects. Instead of shader passes they evaluate a per-frame transform offset in resolveVisualState, so they stack with keyframed transforms and work in preview and export. - intensity param (0-100%, keyframable) scales the whole effect - easing select maps progress through the graph editor's bezier presets - supportsStandalone: false hides them from effect-track creation - empty shader pass groups are filtered out so pass-less effects and zero-intensity blur no longer crash the compositor --- apps/web/src/services/renderer/resolve.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'apps/web/src/services') diff --git a/apps/web/src/services/renderer/resolve.ts b/apps/web/src/services/renderer/resolve.ts index 5335de2d..a4c8d303 100644 --- a/apps/web/src/services/renderer/resolve.ts +++ b/apps/web/src/services/renderer/resolve.ts @@ -6,6 +6,7 @@ import { intensityToSigma, } from "@/effects/definitions/blur"; import { effectsRegistry, resolveEffectPasses } from "@/effects"; +import { applyMotionEffects } from "@/effects/motion"; import type { Effect, EffectPass } from "@/effects/types"; import { getSourceTimeAtClipTime } from "@/retime"; import { @@ -125,7 +126,8 @@ function resolveEffectPassGroups({ width, height, }); - }); + }) + .filter((passes) => passes.length > 0); } function resolveVisualState({ @@ -149,10 +151,18 @@ function resolveVisualState({ elementStartTime: params.timeOffset, elementDuration: params.duration, }); - const transform = resolveTransformAtTime({ - baseTransform: params.transform, + const transform = applyMotionEffects({ + baseTransform: resolveTransformAtTime({ + baseTransform: params.transform, + animations: params.animations, + localTime, + }), + effects: params.effects, animations: params.animations, localTime, + duration: params.duration, + canvasWidth: context.renderer.width, + canvasHeight: context.renderer.height, }); const opacity = resolveOpacityAtTime({ baseOpacity: params.opacity, -- cgit v1.3.1