Custom Clip
Diffusion Studio is highly extensible using Pixi.js , an HTML5 creation engine. In this guide, we will walk through the steps of creating a custom Clip
object using Pixi.js. Before diving into the example, let’s first discuss the lifecycle of a Clip
object.
Clip Lifecycle
When Clip
objects are rendered to the canvas, they pass through several key phases:
Constructor
The constructor()
method is invoked first, during the initialization of the clip. This is where the initial state and values should be set up.
The method receives props
as arguments, and you must always call super(props)
to ensure the base class is properly initialized.
Init
The init()
method is called asynchronously before the Clip
is added to a track/composition. This makes it the ideal place for I/O operations, such as fetching assets or loading buffers.
Enter
This method is triggered right before the Clip
is drawn to the canvas. Use enter()
to perform any synchronous actions that need to be executed once, rather than on every render cycle.
Update
The update()
method is called on every redraw of the clip. It receives a Timestamp
argument, which you can use to implement time-based state changes. The update()
function may also return a promise—this is useful during video export to ensure frame accuracy. However, for playback, promises are not awaited to maintain smooth performance.
Exit
This method is called after the Clip
has been drawn to the canvas for the last time. It is commonly used to perform cleanup operations, such as removing filters or other resources to free memory.
Example: Custom Alien Clip
This example is inspired by the Pixi.js Texture Swap  guide. You can refer to it for additional insights.
import { ClipProps, Clip, Timestamp } from '@diffusionstudio/core';
import { Sprite, Assets } from 'pixi.js';
// Define custom Clip properties extending `ClipProps`, such as start, stop, etc.
interface AlienClipProps extends ClipProps {
speed?: number; // Optional speed property
}
// Create a new class extending `Clip` and apply your custom properties
class AlienClip extends Clip<AlienClipProps> {
// Declare custom fields
public sprite = new Sprite();
public speed = 0.2;
public constructor(props: AlienClipProps = {}) {
// Ensure parent class `Clip` is properly initialized
super(props);
// Perform synchronous actions such as setting sprite properties
this.sprite.anchor.set(0.5);
this.sprite.scale.set(2);
// Assign provided properties to the Clip instance
Object.assign(this, props);
// Add the sprite to the clip view (a container)
this.view.addChild(this.sprite);
}
// Initialize the clip, typically used for loading assets asynchronously
public async init(): Promise<void> {
this.sprite.texture = await Assets.load('https://pixijs.com/assets/flowerTop.png');
}
// Enter phase: invoked when the clip is about to be drawn to the canvas
public enter(): void {
// 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 update(time: Timestamp): void | Promise<void> {
// Ensure track and composition are defined before accessing them
this.sprite.x = this.track!.composition!.width / 2;
this.sprite.y = this.track!.composition!.height / 2;
// Adjust the sprite's angle based on elapsed time and configured speed
this.sprite.angle = time.millis * this.speed;
// Access the track or composition's scene graph if needed:
// this.track.view (track-level) or this.track.composition.stage (composition-level)
// This can be useful for collision detection, etc.
}
// Exit phase: invoked when the clip is no longer needed
public exit(): void {
// Cleanup resources (e.g., removing filters)
}
}
Adding the Clip to a Composition
To include this AlienClip
in a composition, you can do the following:
import { Composition } from '@diffusionstudio/core';
const composition = new Composition();
// Add the custom AlienClip to the composition
await composition.add(new AlienClip({ speed: 0.4, stop: 150 }));