diff options
Diffstat (limited to 'apps/web/src/services/renderer/scene-builder.ts')
| -rw-r--r-- | apps/web/src/services/renderer/scene-builder.ts | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/apps/web/src/services/renderer/scene-builder.ts b/apps/web/src/services/renderer/scene-builder.ts index 431b8269..9df154ef 100644 --- a/apps/web/src/services/renderer/scene-builder.ts +++ b/apps/web/src/services/renderer/scene-builder.ts @@ -1,4 +1,4 @@ -import type { SceneTracks, TimelineTrack } from "@/timeline"; +import type { SceneTracks, TimelineElement, TimelineTrack } from "@/timeline"; import type { MediaAsset } from "@/media/types"; import { RootNode } from "./nodes/root-node"; import { VideoNode } from "./nodes/video-node"; @@ -17,6 +17,7 @@ import { readBlendModeFromParams, readOpacityFromParams, } from "@/rendering"; +import { buildTransitionFromParams } from "@/rendering/transition"; const PREVIEW_MAX_IMAGE_SIZE = 2048; @@ -29,6 +30,32 @@ function getVisibleSortedElements({ track }: { track: TimelineTrack }) { return a.id.localeCompare(b.id); }); } +function getTailHoldDuration({ + elements, + elementIndex, +}: { + elements: TimelineElement[]; + elementIndex: number; +}): number { + const element = elements[elementIndex]; + const nextElement = elements[elementIndex + 1]; + if ( + !element || + !nextElement || + (element.type !== "video" && element.type !== "image") || + (nextElement.type !== "video" && nextElement.type !== "image") + ) { + return 0; + } + const gap = nextElement.startTime - (element.startTime + element.duration); + if (gap < 0) { + return 0; + } + const transitionDuration = buildTransitionFromParams({ + params: nextElement.params, + }).inDuration; + return transitionDuration > 0 ? gap + transitionDuration : 0; +} function buildTrackNodes({ tracks, @@ -46,7 +73,11 @@ function buildTrackNodes({ for (const track of tracks) { const elements = getVisibleSortedElements({ track }); - for (const element of elements) { + for (const [elementIndex, element] of elements.entries()) { + const tailHoldDuration = getTailHoldDuration({ + elements, + elementIndex, + }); if (element.type === "effect") { nodes.push( new EffectLayerNode({ @@ -71,7 +102,8 @@ function buildTrackNodes({ mediaId: mediaAsset.id, url: mediaAsset.url, file: mediaAsset.file, - duration: element.duration, + duration: element.duration + tailHoldDuration, + contentDuration: element.duration, timeOffset: element.startTime, trimStart: element.trimStart, trimEnd: element.trimEnd, @@ -80,6 +112,7 @@ function buildTrackNodes({ animations: element.animations, opacity: readOpacityFromParams({ params: element.params }), blendMode: readBlendModeFromParams({ params: element.params }), + transition: buildTransitionFromParams({ params: element.params }), effects: element.effects ?? [], masks: element.masks ?? [], }), @@ -89,7 +122,8 @@ function buildTrackNodes({ nodes.push( new ImageNode({ url: mediaAsset.url, - duration: element.duration, + duration: element.duration + tailHoldDuration, + contentDuration: element.duration, timeOffset: element.startTime, trimStart: element.trimStart, trimEnd: element.trimEnd, @@ -97,6 +131,7 @@ function buildTrackNodes({ animations: element.animations, opacity: readOpacityFromParams({ params: element.params }), blendMode: readBlendModeFromParams({ params: element.params }), + transition: buildTransitionFromParams({ params: element.params }), effects: element.effects ?? [], masks: element.masks ?? [], ...(isPreview && { @@ -114,6 +149,7 @@ function buildTrackNodes({ transform: buildTransformFromParams({ params: element.params }), opacity: readOpacityFromParams({ params: element.params }), blendMode: readBlendModeFromParams({ params: element.params }), + transition: buildTransitionFromParams({ params: element.params }), canvasCenter: { x: canvasSize.width / 2, y: canvasSize.height / 2 }, canvasHeight: canvasSize.height, textBaseline: "middle", @@ -136,6 +172,7 @@ function buildTrackNodes({ animations: element.animations, opacity: readOpacityFromParams({ params: element.params }), blendMode: readBlendModeFromParams({ params: element.params }), + transition: buildTransitionFromParams({ params: element.params }), effects: element.effects ?? [], }), ); @@ -154,6 +191,7 @@ function buildTrackNodes({ animations: element.animations, opacity: readOpacityFromParams({ params: element.params }), blendMode: readBlendModeFromParams({ params: element.params }), + transition: buildTransitionFromParams({ params: element.params }), effects: element.effects ?? [], masks: element.masks ?? [], }), |
