### Complete Checkpoint Workflow Example (v4) Source: https://docs.diffusion.studio/docs/v3-v4 This example demonstrates the full process of creating, saving, and restoring a composition checkpoint with assets in v4. ```javascript // v4 - Complete example // Step 1: Create sources const sources = await Promise.all([ core.Source.from('https://example.com/image.png'), core.Source.from('https://example.com/video.mp4'), ]); // Step 2: Create composition and add clips const composition = new core.Composition(); const layer = await composition.add(new core.Layer()); await layer.add(new core.ImageClip(sources[0], { height: '100%' })); // Step 3: Serialize sources and create checkpoint const assets = core.serializeSources(sources); const checkpoint = await composition.createCheckpoint(); // Step 4: Save to storage localStorage.setItem('project-checkpoint', JSON.stringify(checkpoint)); localStorage.setItem('project-assets', JSON.stringify(assets)); // Step 5: Restore from storage const savedCheckpoint = JSON.parse(localStorage.getItem('project-checkpoint')); const savedAssets = JSON.parse(localStorage.getItem('project-assets')); const restoredComposition = new core.Composition(); await restoredComposition.restoreCheckpoint(savedCheckpoint, savedAssets); ``` -------------------------------- ### Install Diffusion Studio Core Source: https://docs.diffusion.studio/docs Install the Diffusion Studio Core package using npm. ```bash npm install @diffusionstudio/core ``` -------------------------------- ### Automated Sequential Layer Setup Source: https://docs.diffusion.studio/docs/clips/audio Creates a sequential layer and adds an AudioClip, then splits it and adjusts ranges for automated timing. Delays are handled automatically. ```typescript const layer = await composition.add( new core.Layer({ mode: 'SEQUENTIAL' }) ); await layer.add(new core.AudioClip(source)); await layer.clips[0].split(8); // Split the first clip layer.clips[0].range = [0.5, 4]; layer.clips[1].range = [14, 16]; ``` -------------------------------- ### Using New Shape Components Source: https://docs.diffusion.studio/docs/v1-v2 Example of how to use the new ShapeTrack and RectangleClip components in v2.x. ```javascript import * as core from '@diffusionstudio/core' const shapeTrack = new core.ShapeTrack() const rectangle = new core.RectangleClip({ width: 100, height: 100, fill: '#ff0000', radius: 10, duration: 5 }) await shapeTrack.add(rectangle) ``` -------------------------------- ### Define and Render a Custom Alien Clip Source: https://docs.diffusion.studio/docs/clips/custom This example demonstrates how to create a custom Clip class, 'AlienClip', which extends the base 'Clip' class. It includes custom properties like 'speed' and an 'Image' object, and overrides lifecycle methods such as 'init', 'update', and 'render' to load an image and animate its rotation. Use this for custom visual elements with specific behaviors. ```typescript import * as core from '@diffusionstudio/core'; // Define custom Clip properties extending `ClipProps`, such as start, stop, etc. interface AlienClipProps extends core.ClipProps { speed?: number; // Optional speed property } // Create a new class extending `Clip` and apply your custom properties class AlienClip extends core.Clip { // Declare custom fields public speed = 10; public image = new Image(); private angle = 0; public constructor(props: AlienClipProps = {}) { // Ensure parent class `Clip` is properly initialized super(props); // Assign provided properties to the Clip instance Object.assign(this, props); } // Initialize the clip, typically used for loading assets asynchronously public override async init(): Promise { this.image.crossOrigin = 'anonymous'; this.image.src = 'https://pixijs.com/assets/flowerTop.png'; await new Promise(resolve => this.image.onload = resolve); } // Enter phase: invoked when the clip is about to be drawn to the canvas public override async enter(): Promise { // No specific actions in this example, but can be used for one-time setup } // Update the clip's state on each frame. Receives a `Timestamp` argument. public override async update(renderer: core.Renderer): Promise { // This can be useful for computationally expensive operations. // Adjust the sprite's angle based on elapsed time and configured speed this.angle = renderer.playbackTime * this.speed; } public override render(renderer: core.Renderer): void { const ctx = renderer.videoCtx; const x = renderer.width / 2; const y = renderer.height / 2; ctx.save(); ctx.translate(x, y); ctx.rotate(this.angle); ctx.drawImage(this.image, -this.image.width / 2, -this.image.height / 2); ctx.restore(); } // Exit phase: invoked when the clip is no longer needed public override async exit(): Promise { // Cleanup resources (e.g., removing filters) } } ``` -------------------------------- ### Create and Add Caption Clip to Composition Source: https://docs.diffusion.studio/docs/clips/caption Instantiate a CaptionClip using a source and add it to a composition's layer. This is the basic setup for displaying captions. ```typescript const clip = new core.CaptionClip(source); const layer = await composition.add(new core.Layer()); await layer.add(clip); ``` -------------------------------- ### Create Layer in Sequential Mode Source: https://docs.diffusion.studio/docs/layers Initializes a layer in 'SEQUENTIAL' mode, where each new clip starts after the previous one ends. To disable, set the mode to 'DEFAULT'. ```typescript const layer = new core.Layer({ mode: 'SEQUENTIAL', }); // undo sequential mode layer.mode = 'DEFAULT'; ``` -------------------------------- ### Clip Range Property (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 The 'subclip()' method for trimming clips has been replaced by the 'range' property in v4. Specify the start and end frames in seconds as an array: '[start, end]'. ```javascript // v3 clip.subclip(0, 180); // Trim from start to end frames clip.subclip(420); // Trim from frame 420 to end // v4 clip.range = [0, 180]; // Range in seconds: [start, end] clip.range = [14, 16]; // Range in seconds (assuming 30fps: 420/30 = 14s) ``` -------------------------------- ### Fallback for showSaveFilePicker Source: https://docs.diffusion.studio/docs/rendering Provides a fallback mechanism for the showSaveFilePicker API to ensure compatibility in browsers where it is not supported. This example assigns a default filename if the API is unavailable. ```typescript if (!('showSaveFilePicker' in window)) { Object.assign(window, { showSaveFilePicker: async () => 'myVideo.mp4' }); } ``` -------------------------------- ### Get Composition Playback Position Source: https://docs.diffusion.studio/docs/composition Calculates the current playback position as a fraction of the total duration. Both currentTime and duration are in seconds. ```typescript const position = composition.currentTime / composition.duration; ``` -------------------------------- ### Manipulate First AudioClip Source: https://docs.diffusion.studio/docs/clips/audio Trims the first audio clip to a specific range and applies a negative delay to offset its start time. ```typescript clip0.range = [0.5, 4]; clip0.delay = -0.5; ``` -------------------------------- ### Split an AudioClip Source: https://docs.diffusion.studio/docs/clips/audio Splits an existing AudioClip into two at a specified time in seconds. The original clip is shortened, and a new clip is created starting from the split point. ```typescript const clip1 = await clip0.split(8); ``` -------------------------------- ### Get and Restore Loaded Fonts Source: https://docs.diffusion.studio/docs/clips/text Retrieves a JSON serializable list of all currently loaded fonts and provides a method to restore them later. Use this for managing font states. ```typescript const loadedFonts = await core.getLoadedFonts(); // JSON serializable array ``` ```typescript await core.restoreFonts(loadedFonts); ``` -------------------------------- ### Complete Workflow: Save and Restore Project Source: https://docs.diffusion.studio/docs/checkpoints Demonstrates the full process of creating a composition, serializing its sources, creating a checkpoint, saving them to local storage, and later restoring the project. ```typescript import * as core from '@diffusionstudio/core'; // Step 1: Create and configure the composition const sources = await Promise.all([ core.Source.from('https://example.com/image.png'), core.Source.from('https://example.com/video.mp4'), ]); const composition = new core.Composition({ width: 1920, height: 1080 }); const layer0 = await composition.add(new core.Layer()); const layer1 = await composition.add(new core.Layer()); await layer0.add(new core.ImageClip(sources[0], { height: '100%' })); await layer1.add(new core.VideoClip(sources[1], { range: [0, 10] })); // Step 2: Serialize sources and create checkpoint const assets = core.serializeSources(sources); const checkpoint = await composition.createCheckpoint(); // Step 3: Save to storage (e.g., localStorage, database, etc.) localStorage.setItem('project-checkpoint', JSON.stringify(checkpoint)); localStorage.setItem('project-assets', JSON.stringify(assets)); // Step 4: Later, restore from storage const savedCheckpoint = JSON.parse(localStorage.getItem('project-checkpoint')); const savedAssets = JSON.parse(localStorage.getItem('project-assets')); const restoredComposition = new core.Composition(); await restoredComposition.restoreCheckpoint(savedCheckpoint, savedAssets); ``` -------------------------------- ### Set ImageClip Delay Source: https://docs.diffusion.studio/docs/clips/image Adjust the start time of an ImageClip by modifying its delay property. ```typescript image.delay = 0; ``` -------------------------------- ### Create a Composition Checkpoint Source: https://docs.diffusion.studio/docs/checkpoints Sets up a composition with image and video layers, then creates a checkpoint of its current state. Sources can be URLs, blobs, or file handles. ```typescript import * as core from '@diffusionstudio/core'; // Create and configure your composition const sources = await Promise.all([ core.Source.from('/image1.png'), core.Source.from('/video1.mp4'), ]); const composition = new core.Composition(); const layer0 = await composition.add(new core.Layer()); const layer1 = await composition.add(new core.Layer()); await layer0.add(new core.ImageClip(sources[0], { height: '100%' })); await layer1.add(new core.VideoClip(sources[1], { range: [0, 10] })); // Create a checkpoint of the current state const checkpoint = await composition.createCheckpoint(); ``` -------------------------------- ### Create Source with MIME Type Hint Source: https://docs.diffusion.studio/docs/source Provide a MIME type hint during source creation from a URL for faster initialization. ```javascript const source = await core.Source.from('https://example.com/video.mp4', { mimeType: 'video/mp4', }); ``` -------------------------------- ### Create Video Source from FileSystemFileHandle Source: https://docs.diffusion.studio/docs/source Generate a source using a FileSystemFileHandle obtained from the File System Access API. ```javascript const fileHandle = await window.showOpenFilePicker(); const source = await core.Source.from(fileHandle[0]); ``` -------------------------------- ### Manipulate Second AudioClip Source: https://docs.diffusion.studio/docs/clips/audio Trims the second audio clip, aligns its start with the end of the first clip using delay, and reduces its volume. ```typescript clip1.range = [14, 16] clip1.delay = clip0.end - 14; clip1.volume = 0.5; ``` -------------------------------- ### Create Video Source from URL Source: https://docs.diffusion.studio/docs/source Load a video asset from a given URL. Ensure the URL points to a valid video file. ```javascript const source = await core.Source.from('https://example.com/video.mp4'); ``` -------------------------------- ### Source Creation with Source.from Source: https://docs.diffusion.studio/docs/v2-v3 All types of sources are now created using Source.from. Previously, specific methods like VideoSource.from were used. ```typescript - await VideoSource.from(); + await Source.from(); ``` -------------------------------- ### Initialize Composition with License Key (v4) Source: https://docs.diffusion.studio/docs/v3-v4 In v4, the Composition constructor accepts a licenseKey option for initialization. This is a new requirement for v4. ```javascript // v4 const composition = new core.Composition({ licenseKey: "your-license-key", }); ``` -------------------------------- ### Create and Add Layers (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 The process for creating and adding layers has been updated in v4. Instantiate 'core.Layer' directly and use 'composition.add()' to append it. ```javascript // v3 const layer = composition.createLayer(); // or const layer = new core.Layer(); await composition.insertLayer(layer); // v4 const layer = new core.Layer(); await composition.add(layer); ``` -------------------------------- ### Create an ImageClip Source: https://docs.diffusion.studio/docs/clips/image Instantiate an ImageClip with a source URL, setting its delay and duration. Ensure the core library is imported. ```typescript import * as core from '@diffusionstudio/core'; const url = 'https://diffusion-studio-public.s3.eu-central-1.amazonaws.com/images/lenna.png'; const source = await core.Source.from(url); const image = new core.ImageClip(source, { delay: 20, duration: 100 }); ``` -------------------------------- ### Create and Add an AudioClip Source: https://docs.diffusion.studio/docs/clips/audio Fetches an audio source and adds it as an AudioClip to a layer in the composition. Requires importing the core library. ```typescript import * as core from '@diffusionstudio/core'; const source = await core.Source.from('https://diffusion-studio-public.s3.eu-central-1.amazonaws.com/audio/piano.mp3'); const layer = await composition.add(new core.Layer()); const clip0 = await layer.add(new core.AudioClip(source)); ``` -------------------------------- ### Create Video Source from File Input Source: https://docs.diffusion.studio/docs/source Create a source from a file selected by the user via an HTML file input element. ```javascript const fileInput = document.querySelector('input[type="file"]').files[0]; const source = await core.Source.from(fileInput); ``` -------------------------------- ### Create Video Source from Blob Source: https://docs.diffusion.studio/docs/source Initialize a source from a Blob object, which can contain binary data for a video. ```javascript const blob = new Blob([/ * your data * /], { type: 'video/mp4' }); const source = await core.Source.from(blob); ``` -------------------------------- ### Alternative Video Export Targets Source: https://docs.diffusion.studio/docs/rendering Demonstrates alternative methods for exporting video when showSaveFilePicker is not available or suitable. These include returning a Blob, downloading with a specified name, or streaming to a callback function. ```typescript const blob = await encoder.render(); // Returns the video as a Blob. core.assert(blob.type == 'success'); const blob = res.data; await encoder.render('myVideo.mp4'); // Downloads the result with a specified name. await encoder.render((data: Uint8Array, position: number) => { console.log(data, position) }); // Streams the video to a callback. ``` -------------------------------- ### Create Source from Asset Object Source: https://docs.diffusion.studio/docs/source Initialize a source directly from an Asset object, specifying input and MIME type. ```javascript const source = await core.Source.fromAsset({ input: new File([], 'my-audio.MP3', { type: 'audio/mpeg' }), mimeType: 'audio/mpeg', }); ``` -------------------------------- ### Configure Sequential Layer Mode (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 Sequential mode for layers is now configured via constructor options in v4. Use 'mode: "SEQUENTIAL"' during layer creation, or set 'layer.mode' directly. To disable, set 'mode' to 'DEFAULT'. ```javascript // v3 layer.sequential(); // Enable layer.sequential(false); // Disable // v4 const layer = new core.Layer({ mode: 'SEQUENTIAL', }); // To disable layer.mode = 'DEFAULT'; ``` -------------------------------- ### HTML Structure for Player Container Source: https://docs.diffusion.studio/docs/composition Basic HTML structure required to host the video player and its container for visualization. ```html
``` -------------------------------- ### Initialize Composition Source: https://docs.diffusion.studio/docs Import and initialize a new Composition object from the Diffusion Studio Core library. ```typescript import * as core from '@diffusionstudio/core'; const composition = new core.Composition(); ``` -------------------------------- ### Font Management in v2.x Source: https://docs.diffusion.studio/docs/v1-v2 Shows the transition from the static Font.load method in v1.x to the FontManager in v2.x for loading fonts. ```javascript // V1 const font = await core.Font.load({ family: 'Arial', weight: 400, source: 'arial.ttf' }) // V2 const fontManager = new core.FontManager() const font = await fontManager.load({ family: 'Arial', weight: 400, source: 'arial.ttf' }) // or const font = core.FontManager.load({ family: 'Arial', weight: 400, source: 'arial.ttf' }) ``` -------------------------------- ### Initialize an Empty Composition Source: https://docs.diffusion.studio/docs/rendering Create a new Composition object to be used for rendering. This is the initial step before setting up the encoder. ```typescript import * as core from '@diffusionstudio/core'; const composition = new core.Composition(); ``` -------------------------------- ### Create an Encoder Instance Source: https://docs.diffusion.studio/docs/rendering Instantiate an Encoder using a Composition object. This encoder will handle the video processing and encoding. ```typescript const encoder = new core.Encoder(composition); ``` -------------------------------- ### Render Media in V1 Source: https://docs.diffusion.studio/docs/v1-v2 In V1, rendering media returned a promise that needed to be awaited. ```typescript await new Encoder(...).render('https://example.com/location/file.mp4') ``` -------------------------------- ### Share Sources Between Clips Source: https://docs.diffusion.studio/docs/source Demonstrates reusing a single source instance across multiple clips for efficient asset management. ```javascript const source = await core.Source.from('https://example.com/video.mp4'); // Create multiple clips from the same source const clip1 = new core.VideoClip(source, { range: [0, 5] }); const clip2 = new core.VideoClip(source, { range: [10, 15] }); const clip3 = new core.VideoClip(source, { range: [20, 25] }); // All three clips share the same cached source data ``` -------------------------------- ### Create and Style a Text Clip Source: https://docs.diffusion.studio/docs/clips/text Demonstrates how to create a TextClip with various styling options including font loading, glow, strokes, shadows, and inline styles for specific text sections. Use this to apply complex text formatting. ```typescript import * as core from '@diffusionstudio/core'; const thin = await core.loadFont({ family: 'Geologica', weight: '300', size: 19 }); const bold = await core.loadFont({ family: 'Geologica', weight: '700', size: 24 }); await composition.add( new core.TextClip({ text: "The quick\nbrown fox jumps over the lazy dog.", align: 'center', baseline: 'middle', font: bold, maxWidth: '40%', leading: 1.3, glow: { intensity: 1, color: '#000000', radius: 10, opacity: 100, }, strokes: [{ width: 5, color: '#000000', lineJoin: 'round', lineCap: 'round', miterLimit: 4, }], shadows: [ { offsetX: 4, offsetY: 5, blur: 20, color: '#000000', opacity: 100, }, { offsetX: -8, offsetY: -4, blur: 20, color: '#FFFFFF', opacity: 90, }, ], x: '50%', y: '50%', styles: [{ start: 0, stop: 9, style: { font: thin, color: '#0000FF', casing: 'upper', } }] }) ); ``` -------------------------------- ### Load Image Source and Access Dimensions Source: https://docs.diffusion.studio/docs/source Use `Source.from` to load an image and access its width and height in pixels. Ensure the `core` library is imported. ```javascript const source = await core.Source.from('https://example.com/image.jpg'); // Image dimensions source.width; // 1920 (pixels) source.height; // 1080 (pixels) ``` -------------------------------- ### Apply Fade Transition to Image Clips Source: https://docs.diffusion.studio/docs/transitions Demonstrates how to add two ImageClips to a sequential layer and apply a dissolve transition to the first clip. Ensure both clips are in the same layer for transitions to work. ```typescript import * as core from '@diffusionstudio/core'; const layer = await composition.add( new core.Layer({ mode: 'SEQUENTIAL' }) ); await layer.add( new core.ImageClip('/image1.png', { height: '100%', duration: 3, transition: { duration: 1, type: 'dissolve', } }) ); await layer.add( new core.ImageClip('/image2.png', { height: '100%', duration: 3, }) ); ``` -------------------------------- ### Updated Composition Usage Source: https://docs.diffusion.studio/docs/v1-v2 Compares the v1.x and v2.x methods for attaching and detaching players, and shifting tracks. ```javascript // V1 const composition = new core.Composition() composition.attachPlayer(element) composition.shiftTrack(track) // V2 const composition = new core.Composition() composition.mount(element) composition.insertTrack(track) // Accepts position as second argument ``` -------------------------------- ### Configure Nginx for Required Headers Source: https://docs.diffusion.studio/docs Configure Nginx to set the necessary Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers for production deployment. ```nginx add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Embedder-Policy "credentialless" always; ``` -------------------------------- ### Create Video Clip Source: https://docs.diffusion.studio/docs/clips/video Creates a VideoClip from a VideoSource. Accepts blobs or file handles. Allows setting position and height for stretching. ```typescript const video = new core.VideoClip(source, { // also accepts blobs or file handles position: 'center', // ensures the clip is centered height: '100%', // stretches the clip to the full height }); ``` -------------------------------- ### Load Video Source from URL Source: https://docs.diffusion.studio/docs/clips/video Creates a VideoSource from a URL. This is useful for sharing resources between multiple VideoClips. ```typescript const source = await core.Source.from('https://diffusion-studio-public.s3.eu-central-1.amazonaws.com/videos/big_buck_bunny_1080p_30fps.mp4'); ``` -------------------------------- ### Create and Apply EllipseMask for Circular Crop Source: https://docs.diffusion.studio/docs/masks Demonstrates creating a circular EllipseMask centered in the composition and applying it to a VideoClip. ```typescript // Create a circular mask const circularMask = new core.EllipseMask({ x: composition.width / 2, y: composition.height / 2, width: 800, height: 800, }); // Apply to a video clip const videoClip = new core.VideoClip(source, { position: 'center', mask: circularMask, height: '100%', }); ``` -------------------------------- ### Configure Encoder for 4K 60 FPS Video Source: https://docs.diffusion.studio/docs/rendering Customize the encoder to output a 4K video at 60 frames per second from a default 1080p Composition. ```typescript const encoder = new core.Encoder(composition, { video: { fps: 60, resolution: 2, }, }); ``` -------------------------------- ### Upload Rendered Media in V2 Source: https://docs.diffusion.studio/docs/v1-v2 V2 allows direct uploading of the rendered Blob to a specified URL using fetch. ```typescript const blob = await new Encoder(...).render() await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'video/mp4', }, body: blob }); ``` -------------------------------- ### Render Media with Progress Callback in V2 Source: https://docs.diffusion.studio/docs/v1-v2 V2 supports a callback function during rendering to track progress and access data chunks. ```typescript await new Encoder(...).render((data: Uint8Array, position: number) => { console.log(data, position) }) ``` -------------------------------- ### New Filter Syntax for Clips Source: https://docs.diffusion.studio/docs/v1-v2 Demonstrates the updated syntax for applying filters to clips, moving from Pixi filters to Canvas Context API strings. ```javascript // V1 clip.filters = new BlurFilter(5) // V2 clip.filter = 'blur(5px)' // Multiple filters clip.filter = 'blur(5px) brightness(150%)' ``` -------------------------------- ### Subscribe to Composition Events Source: https://docs.diffusion.studio/docs/events Listen for playback, layer, and composition state changes using the `on` method. Ensure the Composition object is initialized before subscribing. ```typescript const composition = new core.Composition(); // Playback events composition.on('playback:start', () => { console.log('Playback started'); }); composition.on('playback:end', () => { console.log('Playback ended'); }); composition.on('playback:time', (time: number | undefined) => { console.log('Current playback time:', time); }); // Layer events composition.on('layer:add', () => { console.log('Layer added'); }); composition.on('layer:remove', () => { console.log('Layer removed'); }); // Composition events composition.on('resize', () => { console.log('Composition resized'); }); composition.on('restored', () => { console.log('Composition restored'); }); ``` -------------------------------- ### Configure Vite for Required Headers Source: https://docs.diffusion.studio/docs Configure Vite to set the necessary Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. ```javascript export default { server: { headers: { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'credentialless', } }, } ``` -------------------------------- ### Configure Next.js for Required Headers Source: https://docs.diffusion.studio/docs Configure Next.js to set the necessary Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. ```javascript /** @type {import('next').NextConfig} */ const nextConfig = { async headers() { return [ { source: '/:path*', headers: [ { key: 'Cross-Origin-Opener-Policy', value: 'same-origin', }, { key: 'Cross-Origin-Embedder-Policy', value: 'credentialless', }, ], }, ]; }, }; module.exports = nextConfig; ``` -------------------------------- ### Restore Checkpoint Assets (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 In v3, restoreCheckpoint only required the checkpoint data. In v4, assets must be serialized and passed separately along with the checkpoint. ```javascript // v3 await composition.restoreCheckpoint(checkpoint); ``` ```javascript // v4 // First, serialize your sources const sources = await Promise.all([ core.Source.from('/image1.png'), core.Source.from('/video1.mp4'), ]); const assets = core.serializeSources(sources); // Then restore with both checkpoint and assets await composition.restoreCheckpoint(checkpoint, assets); ``` -------------------------------- ### Mount Composition Player to DOM Source: https://docs.diffusion.studio/docs/composition Mounts the Composition player to a specified HTML element for visualization. It includes logic for centering and scaling the player within a container. ```typescript const container = document.getElementById('player-container') as HTMLDivElement; const player = document.getElementById('player') as HTMLDivElement; composition.mount(player); const scale = Math.min( container.clientWidth / composition.width, container.clientHeight / composition.height, ); player.style.width = `${composition.width}px`; player.style.height = `${composition.height}px`; player.style.transform = `scale(${scale})`; player.style.transformOrigin = 'center'; ``` -------------------------------- ### VideoClip with Source Asset Source: https://docs.diffusion.studio/docs/v3-v4 v4 requires media assets to be managed by the new Source API. Clips are now instantiated with a Source object instead of a direct file input. ```javascript // v3 const clip = new core.VideoClip(new File([], 'video.mp4')); ``` ```javascript // v4 const source = await core.Source.from('https://example.com/video.mp4'); const clip = new core.VideoClip(source, { range: [0, 10] }); ``` -------------------------------- ### Media Clip Offset and Caption Creation Source: https://docs.diffusion.studio/docs/v1-v2 Illustrates the changes in MediaClip methods for offsetting and creating captions. ```javascript // V1 mediaClip.offsetBy(2) await mediaClip.addCaptions() // V2 mediaClip.offset(2) await mediaClip.createCaptions() ``` -------------------------------- ### Default Encoder Configuration Source: https://docs.diffusion.studio/docs/rendering The default configuration object for the encoder, specifying settings for video and audio output. ```json { video: { enabled: true, // true by default codec: 'avc', bitrate: 10e6, fps: 30, resolution: 1, }, audio: { enabled: true, sampleRate: 48000, numberOfChannels: 2, bitrate: 128e3, codec: 'aac', }, } ``` -------------------------------- ### Render Video using showSaveFilePicker Source: https://docs.diffusion.studio/docs/rendering Initiate video rendering and save the output directly to a file using the browser's showSaveFilePicker API. This method is recommended for large videos as it writes chunks directly to disk. ```typescript const fileHandle = await window.showSaveFilePicker({ suggestedName: 'untitled_video.mp4', types: [ { description: 'Video File', accept: { 'video/mp4': ['.mp4'] }, }, ], }); await encoder.render(fileHandle); ``` -------------------------------- ### Handle Checkpoint Restoration Errors Source: https://docs.diffusion.studio/docs/checkpoints Wrap checkpoint restoration in a try-catch block to gracefully handle potential errors, especially when restoring from external storage. Log errors for debugging. ```javascript try { await composition.restoreCheckpoint(checkpoint, assets); } catch (error) { console.error('Failed to restore checkpoint:', error); // Handle the error appropriately } ``` -------------------------------- ### Default Composition Options Source: https://docs.diffusion.studio/docs/composition These are the default configuration values used when creating a Composition. They define canvas size, background color, and playback behavior. ```json { height: 1080, width: 1920, background: '#000000', playbackEndBehavior: 'loop', licenseKey: undefined, } ``` -------------------------------- ### Create Caption Clip with Custom Preset Source: https://docs.diffusion.studio/docs/clips/caption Create a CaptionClip and apply a specific appearance preset, such as PaperCaptionPreset. This allows for visual customization of the subtitles. ```typescript const clip = new core.CaptionClip(source, { preset: new core.PaperCaptionPreset(), }); ``` -------------------------------- ### Create a New Layer Source: https://docs.diffusion.studio/docs/layers Instantiates a new Layer object. It's recommended to add layers to the composition before adding clips. ```typescript import * as core from '@diffusionstudio/core'; const layer = new core.Layer(); ``` -------------------------------- ### Access Audio Source Properties Source: https://docs.diffusion.studio/docs/source Retrieve audio-specific properties like duration, sample rate, and number of channels from an AudioSource. ```javascript const source = await core.Source.from('https://example.com/audio.mp3'); // Basic properties source.duration; // 10 (seconds) source.sampleRate; // 44100 (Hz) source.numberOfChannels; // 2 (stereo) ``` -------------------------------- ### Create Caption Source from File Source: https://docs.diffusion.studio/docs/clips/caption Create a CaptionSource from an in-memory transcript object by converting it to a File object. The source will use the provided file name. ```typescript const transcript: core.Transcript = [/** Assume this contains your transcript */]; const blob = new Blob([JSON.stringify(transcript)]); const file = new File([blob], 'transcript.json', { type: 'application/json' }); const source = await core.Source.from(file); ``` -------------------------------- ### Progress Tracking (v4 New Feature) Source: https://docs.diffusion.studio/docs/v3-v4 v4 introduces progress tracking via an onProgress event handler, which was not available in v3. ```javascript // v4 (new feature) encoder.onProgress = (event) => { const { progress, total } = event; console.log(Math.round(progress * 100 / total) + '%'); }; ``` -------------------------------- ### AudioClip Sampling Method Change Source: https://docs.diffusion.studio/docs/v1-v2 Highlights the renaming of the AudioClip sampling method from 'fastsampler' to 'sample'. ```javascript // V1 AudioClip.sample() # has been removed // V2 AudioClip.fastsampler() + AudioClip.sample() ``` -------------------------------- ### Create and Apply RectangleMask to VideoClip Source: https://docs.diffusion.studio/docs/masks Demonstrates creating a RectangleMask with rounded corners and applying it to a VideoClip. The mask defines the visible region for the video. ```typescript import * as core from '@diffusionstudio/core'; const composition = new core.Composition(); // Create a RectangleMask const mask = new core.RectangleMask({ x: 480, y: 0, width: composition.width - 960, height: composition.height, radius: 100, }); // Load a video source const source = await core.Source.from( 'https://example.com/video.mp4' ); // Apply the mask to a video clip const videoClip = new core.VideoClip(source, { position: 'center', mask, height: '100%', }); const layer = await composition.add(new core.Layer()); await layer.add(videoClip); ``` -------------------------------- ### Updated Clip Timing and Trim Functionality Source: https://docs.diffusion.studio/docs/v1-v2 Shows the changes in clip timing properties (start/stop to delay/duration) and the new trim functionality. ```javascript // V1 clip.start = 2 clip.stop = 7 // V2 clip.delay = 2 clip.duration = 5 // Note: Now using duration instead of end time // New trim functionality clip.trim(2, 7) // Equivalent to V1's start/stop ``` -------------------------------- ### Add Custom Clip to Composition Source: https://docs.diffusion.studio/docs/clips/custom This snippet shows how to instantiate a custom 'AlienClip' and add it to a 'Composition' via a 'Layer'. It demonstrates setting custom properties like 'speed' and 'duration' during instantiation. Use this to integrate your custom clips into a project timeline. ```typescript const composition = new core.Composition(); // Add the custom AlienClip to the composition const layer = await composition.add(new core.Layer()); await layer.add(new AlienClip({ speed: 0.4, duration: 150 })); ``` -------------------------------- ### Render Media in V2 Source: https://docs.diffusion.studio/docs/v1-v2 In V2, rendering media returns a Blob directly. This is useful for immediate use or further processing. ```typescript const blob = await new Encoder(...).render() ``` -------------------------------- ### Composition Audio Method Removed Source: https://docs.diffusion.studio/docs/v2-v3 The composition.audio() method has been removed. ```typescript - composition.audio(); ``` -------------------------------- ### Caption Creation Update Source: https://docs.diffusion.studio/docs/v2-v3 Captions are now created at the top level and can be generated using just the audio clip or transcript. ```typescript - audioClip.createCaptions(); - audioTrack.createCaptions(); + composition.createCaptions(audioClip | transcript); ``` -------------------------------- ### Configure Express for Required Headers Source: https://docs.diffusion.studio/docs Configure an Express.js server to set the necessary Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers. ```javascript const express = require('express'); const app = express(); app.use((req, res, next) => { res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); res.setHeader('Cross-Origin-Embedder-Policy', 'credentialless'); next(); }); // ... rest of your app ``` -------------------------------- ### Playback Controls for Composition Source: https://docs.diffusion.studio/docs/composition Provides methods to control the playback of the Composition, including play, pause, and seeking to a specific time. ```typescript await composition.play(); await composition.pause(); await composition.seek(30); ``` -------------------------------- ### Restore Composition from Checkpoint Source: https://docs.diffusion.studio/docs/checkpoints Restores a composition using a previously created checkpoint and its associated serialized sources. The assets parameter is mandatory. ```typescript // Serialize sources before creating the checkpoint const assets = core.serializeSources(sources); // Later, restore the composition from the checkpoint const composition = new core.Composition(); await composition.restoreCheckpoint(checkpoint, assets); ``` -------------------------------- ### Take Screenshot of Composition Source: https://docs.diffusion.studio/docs/composition Captures a screenshot of the Composition at a specific time. The time is specified in seconds or a time string. ```typescript await composition.seek('10s'); const dataUrl = await composition.screenshot(); ``` -------------------------------- ### Creating CaptionClip from CaptionSource Source: https://docs.diffusion.studio/docs/v3-v4 In v4, CaptionClips are instantiated using a CaptionSource object. ```javascript // v4 const source = await core.Source.from('/captions.json'); const clip = new core.CaptionClip(source, { preset: new core.PaperCaptionPreset(), }); ``` -------------------------------- ### Access Video Source Properties Source: https://docs.diffusion.studio/docs/source Retrieve video-specific properties such as FPS, width, height, and bitrate from a VideoSource. ```javascript const source = await core.Source.from('https://example.com/video.mp4'); // All audio properties are also available (duration, sampleRate, numberOfChannels) // Video-specific properties source.fps; // 30 (average frame rate estimation) source.width; // 1920 (pixels) source.height; // 1080 (pixels) source.bitrate; // 1000000 (bits per second estimated) ``` -------------------------------- ### Local Font Loading (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 The method for accessing and loading local fonts has been updated from FontManager.localFonts() in v3 to core.getLocalFonts() in v4. ```javascript // v3 const local = await core.FontManager.localFonts(); const font = await manager.load(local[0].variants[0]); ``` ```javascript // v4 const localFonts = await core.getLocalFonts(); const font = await core.loadFont(localFonts[0].variants[0]); ``` -------------------------------- ### Composition Event Names (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 Composition event names have been updated to a namespaced format in v4, replacing the simpler names used in v3. ```javascript // v3 composition.on('currentframe', (event) => { console.log(event.detail); }); composition.on('play', console.log); composition.on('pause', console.log); ``` ```javascript // v4 composition.on('playback:time', (time: number | undefined) => { console.log('Current playback time:', time); }); composition.on('playback:start', () => { console.log('Playback started'); }); composition.on('playback:end', () => { console.log('Playback ended'); }); ``` -------------------------------- ### Create a PolygonClip (Hexagon) Source: https://docs.diffusion.studio/docs/clips/shapes PolygonClip generates regular polygons with a specified number of sides. Use it for triangles, hexagons, octagons, etc. ```typescript const polygon = new core.PolygonClip({ x: '50%', y: '50%', fill: '#FFFF00', sides: 6, // Creates a hexagon width: 200, height: 200, rotation: 30, // Optional rotation }); ``` -------------------------------- ### Removed Composition Methods (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 Several methods for managing layers in Composition have been removed or renamed in v4. Use 'new core.Layer()' and 'composition.add()' instead of 'composition.createLayer()' and 'composition.insertLayer()'. 'removeLayer()' is now 'remove()'. ```javascript // v3 const layer = composition.createLayer(); // ❌ Removed composition.removeLayer(layer); // ❌ Renamed await composition.insertLayer(layer); // ❌ Removed composition.createCaptions(); // ❌ Removed // v4 const layer = new core.Layer(); // Create layer directly await composition.add(layer); // Use add() instead composition.remove(layer); // Renamed from removeLayer() ``` -------------------------------- ### Extract Audio Samples Source: https://docs.diffusion.studio/docs/source Iterate over audio samples within a specified time range for waveform visualization. ```javascript // start and end are in seconds for (const audioSample of source.samplesInRange({ start: 0, end: 20 })) { // audioSample contains sample data that can be used to draw the audio waveform } ``` -------------------------------- ### Duration Handling in V1 Source: https://docs.diffusion.studio/docs/v1-v2 In V1, the `mediaClip.duration` property returned the full duration of the media clip. ```typescript mediaClip.start = 2 mediaClip.stop = 62 const duration = mediaClip.duration // Sets full duration ``` -------------------------------- ### Caption Track Generation Source: https://docs.diffusion.studio/docs/v1-v2 Demonstrates the change in method name for generating captions from a CaptionTrack. ```javascript // V1 const captions = await captionTrack.from(audioClip).generate() // V2 const captions = await captionTrack.from(audioClip).createCaptions() ``` -------------------------------- ### Clip Animation Changes Source: https://docs.diffusion.studio/docs/v1-v2 Illustrates the shift from individual property keyframes to a centralized animations array for clips. ```javascript // V1 - Individual keyframes per property clip.x = new core.Keyframe([80], [960]) clip.width = new core.Keyframe([60], [1000]) // V2 - Centralized animations array clip.animations = [ { key: 'x', frames: [{ frame: 80, value: 960 }] }, { key: 'width', frames: [{ frame: 60, value: 1000 }] } ] ``` -------------------------------- ### Layer Indexing (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 Layer indexing has changed from a method call in v3 to a property assignment in v4. Use 'layer.index = value' instead of 'layer.index(value)'. ```javascript // v3 layer.index(0); // Method call layer.index('top'); // v4 layer.index = 0; // Property assignment layer.index = 'top'; ``` -------------------------------- ### Add Video Clip to Composition Source: https://docs.diffusion.studio/docs/clips/video Adds a VideoClip to a composition. First, a Layer is created and then the video clip is added to that layer. ```typescript const layer = await composition.add(new core.Layer()); await layer.add(video); ``` -------------------------------- ### Compute Words Per Minute from Captions Source: https://docs.diffusion.studio/docs/source Calculate the words per minute from a caption source, useful for timing adjustments. ```javascript const source = await core.Source.from('https://example.com/captions.json'); // Calculate words per minute (useful for timing adjustments) const wpm = source.computeWpm(); ``` -------------------------------- ### Load Custom Web Font Source: https://docs.diffusion.studio/docs/clips/text Loads a custom web font from a provided URL. Ensure the URL points to a valid font file. ```typescript const roboto = await core.loadFont({ source: "https://fonts.gstatic.com/s/roboto/v32/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2", weight: '400', family: 'Roboto' }); ``` -------------------------------- ### Detect Silence Ranges in Audio Source: https://docs.diffusion.studio/docs/source Identify and retrieve time ranges where silence is detected within an audio source. ```javascript // Detect silence ranges in the audio const silences = await source.silences(); // Returns an array of silence ranges: [{ start: 5.2, end: 6.8 }, ...] ``` -------------------------------- ### Clip Delay Property (v3 vs v4) Source: https://docs.diffusion.studio/docs/v3-v4 The 'offset()' method for adjusting clip timing has been replaced by direct manipulation of the 'delay' property in v4. Timing is now in seconds; convert frame values by dividing by the frame rate (e.g., 30fps). ```javascript // v3 clip.offset(-30); // Time offset in frames clip.offset(-15); // v4 clip.delay += -1; // Delay in seconds (assuming 30fps: -30/30 = -1s) clip.delay += -0.5; // Delay in seconds (assuming 30fps: -15/30 = -0.5s) ``` -------------------------------- ### CSS for Centering Player Source: https://docs.diffusion.studio/docs/composition CSS styles to center the video player within its container using flexbox. ```css #player-container { display: flex; justify-content: center; align-items: center; } ``` -------------------------------- ### Transcript to CaptionSource Migration Source: https://docs.diffusion.studio/docs/v3-v4 v3's Transcript class is replaced by v4's CaptionSource for managing captions. This snippet shows the equivalent operations in both versions. ```javascript // v3 const transcript = core.Transcript.from(captions); const transcript = await core.Transcript.from('https://.../captions.json'); transcript.optimize(); transcript.toSRT(); transcript.slice(20); for (const group of transcript.iter({ count: [2] })) { // ... } ``` ```javascript // v4 // Create a CaptionSource from a transcript JSON file const source = await core.Source.from('/captions.json'); // Use CaptionSource methods const wpm = source.computeWpm(); const groups = source.groupBy({ count: 2 }); const srt = source.toSrt(); source.optimize(); // Create a CaptionClip from the source const clip = new core.CaptionClip(source); ``` -------------------------------- ### Generate Thumbnails from Video Source: https://docs.diffusion.studio/docs/source Extract a specified number of thumbnails at regular intervals within a given time range of a video source. ```javascript // Extract thumbnails at regular intervals // Useful for creating video preview timelines for (const thumbnail of source.thumbnailsInRange({ start: 0, // Start time in seconds end: 20, // End time in seconds count: 10, // Number of thumbnails to generate height: 100 // Thumbnail height in pixels (width maintains aspect ratio) })) { // thumbnail contains image data that can be used to draw thumbnails } ``` -------------------------------- ### Apply RectangleMask with Percentage Positioning to ImageClip Source: https://docs.diffusion.studio/docs/masks Shows how to use a RectangleMask with percentage-based positioning and dimensions for an ImageClip. Includes rounded corners. ```typescript const imageSource = await core.Source.from( 'https://example.com/image.jpg' ); const imageClip = new core.ImageClip(imageSource, { position: 'center', width: '100%', height: '100%', mask: new core.RectangleMask({ x: '10%', y: '10%', width: '80%', height: '80%', radius: 50, }), }); ``` -------------------------------- ### Monitor Video Export Progress Source: https://docs.diffusion.studio/docs/rendering Track the progress of a video export by listening to the 'progress' event on the encoder. This allows for real-time feedback on the rendering status. ```typescript encoder.onProgress = (event) => { const { progress, total } = event; console.log(Math.round(progress * 100 / total) + '%'); }; ``` -------------------------------- ### Animate Rectangle Properties Source: https://docs.diffusion.studio/docs/keyframe-animations Use this snippet to animate the position, size, and color of a rectangle. It demonstrates animating 'x', 'width', 'height', and 'fill' properties over time. ```javascript new core.RectangleClip({ animations: [ { key: 'x', easing: 'ease-in-out', extrapolate: 'clamp', frames: [ { time: 2.5, value: 960 }, { time: 4, value: 50 }, ], }, { key: 'width', easing: 'ease-out', frames: [ { time: 0, value: 0 }, { time: 1.5, value: 1000 }, { time: 4, value: 60 }, ], }, { key: 'height', easing: 'ease-in', frames: [ { time: 0, value: 0 }, { time: 1.5, value: 700 }, { time: 4, value: 40 }, ], }, { key: 'fill', frames: [ { time: 0, value: '#FF0000' }, { time: 4, value: '#00FF00' }, ], } ] }); ``` -------------------------------- ### Create a RectangleClip with Rounded Corners Source: https://docs.diffusion.studio/docs/clips/shapes Use RectangleClip for backgrounds, borders, and geometric shapes. Set 'keepAspectRatio' before size properties for correct interpretation. ```typescript import * as core from '@diffusionstudio/core'; const rectangle = new core.RectangleClip({ position: 'center', keepAspectRatio: true, width: 300, height: 200, fill: '#FF0000', radius: 10, // Rounded corners strokes: [ { width: 2, color: '#000000', }, ], animations: [ { key: 'fill', frames: [ { time: 0, value: '#FF0000' }, { time: 120, value: '#00FF00' }, ], }, ], }); ```