From 725fa4d0247e7ed04069bd35e85aed9616df582f Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Mon, 24 Nov 2025 11:41:04 +0100 Subject: [PATCH 1/4] Update playground to reproduce many clips performance issue - Change imports from core-v4 to core in all playground files - Replace single animated video clip with multiple clips using sequential layer - Split 20-second video into 50 clips with 4-second minimum duration each - Use sliding window approach where clips overlap to maintain minimum duration - Skip clips that would exceed video duration - This setup helps reproduce browser hanging issue when adding many clips --- playground/composition.ts | 64 ++++++++++++++------------------------- playground/controls.ts | 2 +- playground/main.ts | 2 +- playground/render.ts | 2 +- playground/timeline.ts | 4 +-- 5 files changed, 27 insertions(+), 47 deletions(-) diff --git a/playground/composition.ts b/playground/composition.ts index 5bd1e2d..4d9d8cb 100644 --- a/playground/composition.ts +++ b/playground/composition.ts @@ -1,4 +1,4 @@ -import * as core from '@diffusionstudio/core-v4'; +import * as core from '@diffusionstudio/core'; export const settings: core.CompositionSettings = { background: '#76b7f5', @@ -22,49 +22,29 @@ export async function main(composition: core.Composition) { core.Source.from('/parrot.jpg') ]); - const mask = new core.RectangleMask({ - x: 1920 / 2, - y: 1080 / 2, - width: 1080, - height: 1080, - radius: 100, - }); - - const videoClip = new core.VideoClip(sources[0], { - position: 'center', - mask, - height: '100%', - animations: [ - { - key: 'scale', - frames: [ - { time: 0, value: 0.5 }, - { time: 2, value: 1 }, - ], - }, - { - key: 'rotation', - frames: [ - { time: 0, value: 0 }, - { time: 2, value: 720 }, - ], - }, - { - key: 'opacity', - frames: [ - { time: 0, value: 100 }, - { time: 1, value: 80 }, - { time: 2, value: 100 }, - ], - } - ], - range: [0.8, 18], - delay: 1, - }) + const CLIPS = 50; + const videoDuration = 20; + const minClipDuration = 4; + const slideStep = videoDuration / CLIPS; - const videoLayer = new core.Layer(); + const videoLayer = new core.Layer({ mode: 'SEQUENTIAL' }); await composition.add(videoLayer); - await videoLayer.add(videoClip); + + for (let i = 0; i < CLIPS; i++) { + const startTime = i * slideStep; + const endTime = startTime + minClipDuration; + + if (endTime > videoDuration) continue; + + const videoClip = new core.VideoClip(sources[0], { + position: 'center', + height: '100%', + range: [startTime, endTime], + duration: minClipDuration, + }); + + await videoLayer.add(videoClip); + } const imageClip = new core.ImageClip(sources[1], { position: 'center', diff --git a/playground/controls.ts b/playground/controls.ts index 337938d..d45a68e 100644 --- a/playground/controls.ts +++ b/playground/controls.ts @@ -1,4 +1,4 @@ -import * as core from '@diffusionstudio/core-v4'; +import * as core from '@diffusionstudio/core'; import { render } from './render'; export function setupControls(composition: core.Composition) { diff --git a/playground/main.ts b/playground/main.ts index 5f5212a..e5b74f2 100644 --- a/playground/main.ts +++ b/playground/main.ts @@ -1,4 +1,4 @@ -import * as core from '@diffusionstudio/core-v4'; +import * as core from '@diffusionstudio/core'; import { setupControls } from './controls'; import { setupTimeline } from './timeline'; import { main, settings } from './composition'; diff --git a/playground/render.ts b/playground/render.ts index b9ba740..ebd2c2d 100644 --- a/playground/render.ts +++ b/playground/render.ts @@ -1,4 +1,4 @@ -import * as core from '@diffusionstudio/core-v4'; +import * as core from '@diffusionstudio/core'; let fps = 30; diff --git a/playground/timeline.ts b/playground/timeline.ts index d103d12..7f682cc 100644 --- a/playground/timeline.ts +++ b/playground/timeline.ts @@ -1,4 +1,4 @@ -import * as core from '@diffusionstudio/core-v4'; +import * as core from '@diffusionstudio/core'; export function setupTimeline(composition: core.Composition) { composition.on('playback:time', () => { @@ -26,4 +26,4 @@ export function setupTimeline(composition: core.Composition) { } const timeline = document.querySelector('[id="timeline"]') as HTMLDivElement; -const cursor = document.querySelector('[id="timeline"] > div') as HTMLDivElement; \ No newline at end of file +const cursor = document.querySelector('[id="timeline"] > div') as HTMLDivElement; From f2e194d92d2d1a71827369f75dc0d43e130b33f2 Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Mon, 24 Nov 2025 11:44:20 +0100 Subject: [PATCH 2/4] Simplify playground to only include video clips for performance testing - Remove all layers except video clips layer - Remove unused sources (images, audio, captions) - Remove font loading - Keep only the essential code for reproducing many clips issue - Composition now only contains 50 video clips of 4 seconds each --- package-lock.json | 10 +- playground/composition.ts | 233 +------------------------------------- 2 files changed, 7 insertions(+), 236 deletions(-) diff --git a/package-lock.json b/package-lock.json index 84bd882..ff8d377 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "MPL-2.0", "dependencies": { - "@diffusionstudio/core-v4": "^4.0.2" + "@diffusionstudio/core": "^4.0.0" }, "devDependencies": { "@types/wicg-file-system-access": "^2023.10.7", @@ -17,10 +17,10 @@ "vite": "^7.2.2" } }, - "node_modules/@diffusionstudio/core-v4": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@diffusionstudio/core-v4/-/core-v4-4.0.2.tgz", - "integrity": "sha512-v7Zyc4KLPkzlIFqyCiSJgyDRhv7b1BwsWWkdQj5Uh2PrX9o66BgLbs6HV9VompDi15WJcnwLtAVJ8Q/Ppm5Ykg==", + "node_modules/@diffusionstudio/core": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@diffusionstudio/core/-/core-4.0.1.tgz", + "integrity": "sha512-Q0YaMc7nebVN5GnBcI8dKgyesGIkjopWrRHgoJJFNOyM8cwEZ8jK6p/24FjC3SPeKXZMYLea3laPE1kCZGK5aw==", "license": "MPL-2.0", "dependencies": { "mediabunny": "^1.25.0" diff --git a/playground/composition.ts b/playground/composition.ts index 4d9d8cb..1b528c8 100644 --- a/playground/composition.ts +++ b/playground/composition.ts @@ -5,22 +5,10 @@ export const settings: core.CompositionSettings = { }; export async function main(composition: core.Composition) { - const font = await core.loadFont({ - family: 'Geologica', - weight: '800', - }); - core.env.experimental_timeBase = 30; core.env.experimental_canonicalTimeBase = 48_000; - const sources = await Promise.all([ - core.Source.from('/bbb_1080p_30fps.mp4'), - core.Source.from('/lenna.png'), - core.Source.from('/harvard.MP3'), - core.Source.from('/captions.json'), - core.Source.from('/file_example_MP3_1MG.mp3'), - core.Source.from('/parrot.jpg') - ]); + const videoSource = await core.Source.from('/bbb_1080p_30fps.mp4'); const CLIPS = 50; const videoDuration = 20; @@ -36,7 +24,7 @@ export async function main(composition: core.Composition) { if (endTime > videoDuration) continue; - const videoClip = new core.VideoClip(sources[0], { + const videoClip = new core.VideoClip(videoSource, { position: 'center', height: '100%', range: [startTime, endTime], @@ -45,221 +33,4 @@ export async function main(composition: core.Composition) { await videoLayer.add(videoClip); } - - const imageClip = new core.ImageClip(sources[1], { - position: 'center', - height: 600, - duration: 6, - effects: [ - { - type: 'contrast', - value: 60, - }, - { - type: 'sepia', - value: 100, - }, - { - type: 'drop-shadow', - value: { - offsetX: -9, - offsetY: 9, - blur: 3, - color: '#e81', - }, - }, - ], - animations: [ - { - key: 'translateX', - frames: [ - { time: 0, value: -1000 }, - { time: 2, value: 1000 }, - { time: 4, value: 0 } - ], - }, - ] - }); - - const imageLayer = new core.Layer(); - await composition.add(imageLayer); - await imageLayer.add(imageClip); - - const audioClip = new core.AudioClip(sources[2]); - - const audioLayer = new core.Layer(); - await composition.add(audioLayer); - await audioLayer.sequential(); - await audioLayer.add(audioClip); - await audioClip.removeSilences(); - - const captionLayer = new core.Layer(); - await composition.add(captionLayer); - const captionClip = new core.CaptionClip(sources[3]); - await captionLayer.add(captionClip); - - const textLayer0 = new core.Layer(); - await composition.add(textLayer0); - await textLayer0.add(new core.TextClip({ - text: "Basic text in \nDiffusion Studio", - align: 'center', - baseline: 'middle', - fontSize: 14, - strokes: [{ - width: 3, - color: '#000000', - }], - x: '50%', - y: '15%', - rotation: 45, - })); - - const textLayer1 = new core.Layer(); - await composition.add(textLayer1); - await textLayer1.add( - new core.TextClip({ - align: 'center', - baseline: 'middle', - fontSize: 14, - x: '75%', - y: '40%', - casing: 'upper', - duration: 20, - animations: [{ - key: 'text', - easing: 'ease-out', - frames: [ - { time: 0, value: '' }, - { time: 20 / 30, value: 'Animated Text' }, - ], - }] - }) - ); - - const rectangleLayer = new core.Layer(); - await composition.add(rectangleLayer); - await rectangleLayer.add( - new core.RectangleClip({ - position: 'center', - delay: 6, - duration: 4, - fill: '#FF0000', - radius: 10, - strokes: [{ - width: 2, - color: '#000000', - }], - animations: [ - { - key: 'x', - easing: 'ease-in-out', - frames: [ - { time: 2.6, value: 960 }, - { time: 4, value: 50 }, - ], - }, - { - key: 'width', - easing: 'ease-in-out', - frames: [ - { time: 0, value: 0 }, - { time: 2, value: 1000 }, - { time: 4, value: 60 }, - ], - }, - { - key: 'height', - easing: 'ease-in-out', - frames: [ - { time: 0, value: 0 }, - { time: 2, value: 700 }, - { time: 4, value: 40 }, - ], - }, - { - key: 'fill', - frames: [ - { time: 0, value: '#FF0000' }, - { time: 4, value: '#00FF00' }, - ], - } - ] - }) - ) - - const circleLayer = new core.Layer(); - await composition.add(circleLayer); - await circleLayer.add( - new core.EllipseClip({ - position: 'center', - x: '70%', - fill: '#FFFF00', - radius: 90, - blendMode: 'screen', - }) - ); - - const textLayer2 = new core.Layer(); - await composition.add(textLayer2); - await textLayer2.add( - new core.TextClip({ - text: `This is a Complex Text`, - duration: 12, - align: 'center', - baseline: 'middle', - font, - casing: 'upper', - fontSize: 12, - background: { - borderRadius: 20, - opacity: 40, - }, - strokes: [{ - width: 2, - color: '#000000', - }], - y: '85%', - x: '50%', - shadows: [{ - opacity: 70, - blur: 7, - offsetX: 2, - offsetY: 4, - }], - styles: [{ - start: 8, - style: { - color: '#19fa2c' - } - }], - }) - ) - - - const audioClip1 = new core.AudioClip(sources[4], { volume: 0.2, duration: 20 }); - const audioLayer1 = new core.Layer(); - await composition.add(audioLayer1); - await audioLayer1.add(audioClip1); - - const imageLayer2 = new core.Layer(); - await composition.add(imageLayer2); - await imageLayer2.add( - new core.ImageClip(sources[1], { - height: 300, - delay: 2, - duration: 3, - transition: { - duration: 3, - type: 'dissolve', - } - }) - ) - - await imageLayer2.add( - new core.ImageClip(sources[5], { - height: 300, - delay: 5, - duration: 3, - }) - ) } From 6c0fc64789e1ad535f03acd45cecfb6dda75634f Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Mon, 24 Nov 2025 11:46:52 +0100 Subject: [PATCH 3/4] Adjust clips configuration for reproduction - Set CLIPS to 40 and minClipDuration to 3 - This configuration reliably reproduces the freeze after ~4 seconds of playback --- playground/composition.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playground/composition.ts b/playground/composition.ts index 1b528c8..60cae20 100644 --- a/playground/composition.ts +++ b/playground/composition.ts @@ -10,9 +10,9 @@ export async function main(composition: core.Composition) { const videoSource = await core.Source.from('/bbb_1080p_30fps.mp4'); - const CLIPS = 50; + const CLIPS = 40; const videoDuration = 20; - const minClipDuration = 4; + const minClipDuration = 3; const slideStep = videoDuration / CLIPS; const videoLayer = new core.Layer({ mode: 'SEQUENTIAL' }); From 4d6fd1262295c7eb24cecfc773cfa1b46fa734fe Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Wed, 26 Nov 2025 09:59:05 +0100 Subject: [PATCH 4/4] update package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2589231..82e58c1 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,6 @@ "vite": "^7.2.2" }, "dependencies": { - "@diffusionstudio/core": "^4.0.0" + "@diffusionstudio/core": "^4.0.2" } }