summaryrefslogtreecommitdiff
path: root/apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts')
-rw-r--r--apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts99
1 files changed, 99 insertions, 0 deletions
diff --git a/apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts b/apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts
new file mode 100644
index 00000000..dd644f2a
--- /dev/null
+++ b/apps/web/src/services/renderer/__tests__/scene-builder-transition.test.ts
@@ -0,0 +1,99 @@
+import { describe, expect, test } from "bun:test";
+import { buildScene } from "@/services/renderer/scene-builder";
+import { ImageNode } from "@/services/renderer/nodes/image-node";
+import type { ImageElement, SceneTracks } from "@/timeline";
+import type { MediaAsset } from "@/media/types";
+import {
+ mediaTime,
+ type MediaTime,
+ TICKS_PER_SECOND,
+ ZERO_MEDIA_TIME,
+} from "@/wasm";
+
+function imageElement({
+ id,
+ mediaId,
+ startTime,
+ transitionDuration = 0,
+}: {
+ id: string;
+ mediaId: string;
+ startTime: MediaTime;
+ transitionDuration?: number;
+}): ImageElement {
+ return {
+ id,
+ name: id,
+ type: "image",
+ mediaId,
+ startTime,
+ duration: mediaTime({ ticks: 2 * TICKS_PER_SECOND }),
+ trimStart: ZERO_MEDIA_TIME,
+ trimEnd: ZERO_MEDIA_TIME,
+ params: {
+ "transform.positionX": 0,
+ "transform.positionY": 0,
+ "transform.scaleX": 1,
+ "transform.scaleY": 1,
+ "transform.rotate": 0,
+ opacity: 1,
+ blendMode: "normal",
+ "transition.kind": "fade",
+ "transition.inDuration": transitionDuration,
+ "transition.outDuration": 0,
+ },
+ };
+}
+
+function imageAsset(id: string): MediaAsset {
+ return {
+ id,
+ name: id,
+ type: "image",
+ file: new File([], `${id}.png`, { type: "image/png" }),
+ url: `blob:${id}`,
+ };
+}
+
+describe("scene transition boundaries", () => {
+ test("holds the outgoing slide through the incoming transition", () => {
+ const first = imageElement({
+ id: "first",
+ mediaId: "media-first",
+ startTime: ZERO_MEDIA_TIME,
+ });
+ const second = imageElement({
+ id: "second",
+ mediaId: "media-second",
+ startTime: mediaTime({ ticks: 3 * TICKS_PER_SECOND }),
+ transitionDuration: 1,
+ });
+ const tracks: SceneTracks = {
+ overlay: [],
+ main: {
+ id: "main",
+ name: "Main Track",
+ type: "video",
+ elements: [first, second],
+ muted: false,
+ hidden: false,
+ },
+ audio: [],
+ };
+ const scene = buildScene({
+ canvasSize: { width: 1920, height: 1080 },
+ tracks,
+ mediaAssets: [imageAsset("media-first"), imageAsset("media-second")],
+ duration: 5 * TICKS_PER_SECOND,
+ background: { type: "color", color: "transparent" },
+ });
+ const imageNodes = scene.children.filter(
+ (node): node is ImageNode => node instanceof ImageNode,
+ );
+
+ expect(imageNodes).toHaveLength(2);
+ expect(imageNodes[0].params.contentDuration).toBe(2 * TICKS_PER_SECOND);
+ expect(imageNodes[0].params.duration).toBe(4 * TICKS_PER_SECOND);
+ expect(imageNodes[1].params.transition?.inDuration).toBe(TICKS_PER_SECOND);
+ });
+});