API Reference
Complete API documentation for the Stoked UI Video Renderer across Rust, WASM, and TypeScript interfaces.
Rust Compositor API
Core Types
Compositor
Main compositor instance for frame composition.
pub struct Compositor {
width: u32,
height: u32,
background: Color,
}
impl Compositor {
/// Create a new compositor with specified dimensions
pub fn new(width: u32, height: u32) -> Result<Self, CompositorError>;
/// Set background color
pub fn with_background(self, color: Color) -> Self;
/// Compose a single frame from layers
pub fn compose(&self, layers: &[Layer]) -> Result<Frame, CompositorError>;
/// Compose multiple frames in parallel
pub fn compose_batch(&self, batch: Vec<Vec<Layer>>) -> Result<Vec<Frame>, CompositorError>;
}
Example:
let compositor = Compositor::new(1920, 1080)?
.with_background(Color::black());
Layer
Represents a compositable layer.
pub struct Layer {
pub content: LayerContent,
pub transform: Transform,
pub blend_mode: BlendMode,
pub visible: bool,
pub z_index: i32,
}
pub enum LayerContent {
SolidColor(Color),
Image(ImageData),
Text(TextData),
}
impl Layer {
/// Create a solid color layer
pub fn solid_color(color: Color, transform: Transform) -> Self;
/// Create an image layer from file path
pub fn image(path: impl AsRef<Path>, transform: Transform) -> Result<Self, CompositorError>;
/// Create an image layer from raw data
pub fn from_image_data(data: Vec<u8>, width: u32, height: u32, transform: Transform) -> Self;
/// Set blend mode
pub fn with_blend_mode(self, mode: BlendMode) -> Self;
/// Set visibility
pub fn with_visible(self, visible: bool) -> Self;
/// Set z-index
pub fn with_z_index(self, z: i32) -> Self;
}
Example:
let layer = Layer::solid_color(Color::rgb(255, 0, 0), Transform::new())
.with_blend_mode(BlendMode::Multiply)
.with_z_index(1);
Transform
Transformation properties for layers.
pub struct Transform {
pub x: f32,
pub y: f32,
pub scale_x: f32,
pub scale_y: f32,
pub rotation: f32, // degrees
pub opacity: f32, // 0.0 to 1.0
}
impl Transform {
/// Create default transform (0, 0, 1x, 1x, 0°, 100%)
pub fn new() -> Self;
/// Set position
pub fn with_position(self, x: f32, y: f32) -> Self;
/// Set uniform scale
pub fn with_scale(self, scale: f32) -> Self;
/// Set non-uniform scale
pub fn with_scale_xy(self, scale_x: f32, scale_y: f32) -> Self;
/// Set rotation in degrees
pub fn with_rotation(self, degrees: f32) -> Self;
/// Set opacity (0.0 to 1.0)
pub fn with_opacity(self, opacity: f32) -> Self;
}
Example:
let transform = Transform::new()
.with_position(100.0, 200.0)
.with_scale(0.5)
.with_rotation(45.0)
.with_opacity(0.8);
Color
RGBA color representation.
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl Color {
/// Create RGBA color
pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self;
/// Create RGB color (alpha = 255)
pub fn rgb(r: u8, g: u8, b: u8) -> Self;
/// Predefined colors
pub fn black() -> Self;
pub fn white() -> Self;
pub fn transparent() -> Self;
}
Example:
let red = Color::rgb(255, 0, 0);
let semi_transparent_blue = Color::new(0, 0, 255, 128);
BlendMode
Layer blending modes.
pub enum BlendMode {
Normal, // Standard alpha blending
Multiply, // Darkens by multiplying colors
Screen, // Lightens by inverting and multiplying
Overlay, // Combines multiply and screen
Add, // Adds color values
Subtract, // Subtracts color values
Lighten, // Takes lighter of two colors
Darken, // Takes darker of two colors
}
Example:
let layer = Layer::solid_color(color, transform)
.with_blend_mode(BlendMode::Multiply);
Frame
Composed output frame.
pub struct Frame {
data: RgbaImage,
}
impl Frame {
/// Save frame to PNG file
pub fn save(&self, path: impl AsRef<Path>) -> Result<(), CompositorError>;
/// Get frame as raw RGBA bytes
pub fn as_bytes(&self) -> &[u8];
/// Get frame dimensions
pub fn dimensions(&self) -> (u32, u32);
/// Get underlying image
pub fn image(&self) -> &RgbaImage;
}
Example:
let frame = compositor.compose(&layers)?;
frame.save("output.png")?;
let bytes = frame.as_bytes();
let (width, height) = frame.dimensions();
Effects
Image effects that can be applied to layers.
pub enum Effect {
Blur { radius: f32 },
Brightness { amount: f32 }, // -1.0 to 1.0
Contrast { amount: f32 }, // -1.0 to 1.0
Saturation { amount: f32 }, // -1.0 to 1.0
HueRotate { degrees: f32 }, // 0.0 to 360.0
}
impl Effect {
/// Apply effect to image
pub fn apply(&self, image: &RgbaImage) -> Result<RgbaImage, CompositorError>;
}
Example:
let blur = Effect::Blur { radius: 10.0 };
let brightened = Effect::Brightness { amount: 0.3 };
let image = blur.apply(&image)?;
let image = brightened.apply(&image)?;
Error Types
pub enum CompositorError {
InvalidDimensions(u32, u32),
ImageLoadError(String),
ImageSaveError(String),
CompositionError(String),
EffectError(String),
}
impl std::error::Error for CompositorError {}
impl std::fmt::Display for CompositorError {
// Standard error formatting
}
WASM Preview API
PreviewRenderer
Browser-based WASM renderer.
class PreviewRenderer {
/**
* Create a new WASM renderer
* @param canvas - HTML canvas element for rendering
* @param width - Canvas width in pixels
* @param height - Canvas height in pixels
*/
constructor(canvas: HTMLCanvasElement, width: number, height: number);
/**
* Render a frame from layer data
* @param layersJson - JSON string of WasmLayer[]
*/
render_frame(layersJson: string): void;
/**
* Clear the canvas
*/
clear(): void;
/**
* Get performance metrics as JSON
*/
get_metrics(): string;
/**
* Free WASM memory (call when done)
*/
free(): void;
}
Example:
import init, { PreviewRenderer } from '@stoked-ui/wasm-preview';
await init();
const canvas = document.getElementById('preview') as HTMLCanvasElement;
const renderer = new PreviewRenderer(canvas, 1920, 1080);
const layers = [
{
id: 'bg',
type: 'solidColor',
color: [50, 50, 50, 255],
transform: { x: 0, y: 0, scale_x: 1, scale_y: 1, rotation: 0, opacity: 1 },
blend_mode: 'normal',
visible: true,
z_index: 0,
}
];
renderer.render_frame(JSON.stringify(layers));
WASM Types
WasmLayer
interface WasmLayer {
id: string;
type: 'solidColor' | 'image' | 'text';
// For solidColor type
color?: [number, number, number, number]; // RGBA 0-255
// For image type
imagePath?: string;
// Transform properties
transform: {
x: number;
y: number;
scale_x: number;
scale_y: number;
rotation: number; // degrees
opacity: number; // 0.0 to 1.0
};
// Blending and visibility
blend_mode?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'add' | 'lighten' | 'darken';
visible: boolean;
z_index: number;
}
RenderMetrics
interface RenderMetrics {
width: number;
height: number;
ready: boolean;
lastFrameTime?: number; // milliseconds
fps?: number;
}
TypeScript/React API
useWasmRenderer Hook
React hook for WASM renderer integration.
interface UseWasmRendererResult {
canvasRef: React.RefObject<HTMLCanvasElement>;
renderFrame: (layers: WasmLayer[]) => void;
clear: () => void;
isLoading: boolean;
error: Error | null;
metrics: RenderMetrics | null;
benchmark: (layerCount: number) => Promise<number>;
}
function useWasmRenderer(
width: number,
height: number
): UseWasmRendererResult;
Parameters:
width- Canvas width in pixelsheight- Canvas height in pixels
Returns:
canvasRef- Ref to attach to canvas elementrenderFrame- Function to render layersclear- Clear the canvasisLoading- WASM module loading stateerror- Error state if initialization failsmetrics- Performance metricsbenchmark- Run performance benchmark
Example:
import { useWasmRenderer } from '@stoked-ui/wasm-preview';
function VideoPreview() {
const { canvasRef, renderFrame, isLoading, metrics } = useWasmRenderer(1920, 1080);
useEffect(() => {
if (!isLoading) {
renderFrame([
{
id: 'bg',
type: 'solidColor',
color: [30, 30, 30, 255],
transform: { x: 0, y: 0, scale_x: 1, scale_y: 1, rotation: 0, opacity: 1 },
blend_mode: 'normal',
visible: true,
z_index: 0,
}
]);
}
}, [isLoading, renderFrame]);
return <canvas ref={canvasRef} />;
}
Helper Functions
createSolidColorLayer
function createSolidColorLayer(
color: [number, number, number, number],
transform?: Partial<WasmLayer['transform']>,
options?: { zIndex?: number; blendMode?: WasmLayer['blend_mode'] }
): WasmLayer;
Example:
const layer = createSolidColorLayer(
[255, 0, 0, 255],
{ x: 100, y: 100, scale_x: 0.5, scale_y: 0.5 },
{ zIndex: 1, blendMode: 'multiply' }
);
Node.js Integration API
RustCompositorService (NestJS)
Service for integrating Rust compositor via CLI.
interface CompositionRequest {
width: number;
height: number;
layers: LayerData[];
outputPath: string;
}
interface LayerData {
type: 'solidColor' | 'image';
color?: [number, number, number, number];
imagePath?: string;
transform: {
x: number;
y: number;
scale_x: number;
scale_y: number;
rotation: number;
opacity: number;
};
blend_mode?: string;
z_index: number;
}
@Injectable()
class RustCompositorService {
/**
* Compose a single frame
*/
async composeFrame(request: CompositionRequest): Promise<string>;
/**
* Compose multiple frames in batch
*/
async composeBatch(requests: CompositionRequest[]): Promise<string[]>;
}
Example:
@Injectable()
export class VideoService {
constructor(private compositor: RustCompositorService) {}
async renderFrame() {
const result = await this.compositor.composeFrame({
width: 1920,
height: 1080,
layers: [
{
type: 'solidColor',
color: [255, 0, 0, 255],
transform: { x: 100, y: 100, scale_x: 0.5, scale_y: 0.5, rotation: 0, opacity: 1 },
z_index: 0,
}
],
outputPath: '/tmp/output.png',
});
return result;
}
}
CLI API
Command Line Interface
# Compose a single frame
video-render compose --input <json-file> --output <png-file>
# Benchmark performance
video-render bench --layers <count> --iterations <count>
# Get version info
video-render --version
Input JSON Format
{
"width": 1920,
"height": 1080,
"layers": [
{
"type": "solidColor",
"color": [255, 0, 0, 255],
"transform": {
"x": 100,
"y": 100,
"scale_x": 0.5,
"scale_y": 0.5,
"rotation": 0,
"opacity": 1.0
},
"blend_mode": "normal",
"z_index": 0
}
],
"outputPath": "/tmp/output.png"
}
Performance Characteristics
Rust Compositor
| Operation | Performance | Notes |
|---|---|---|
| Simple frame (3 layers, 1080p) | ~4ms | 11x faster than Node.js |
| Complex frame (10 layers, 1080p) | ~12ms | 10x faster than Node.js |
| 4K frame (5 layers) | ~25ms | 11x faster than Node.js |
| Batch processing (100 frames) | Parallel | Uses all CPU cores |
WASM Preview
| Metric | Value | Notes |
|---|---|---|
| Bundle size (gzipped) | ~95KB | Includes compositor |
| Initial load time | <100ms | One-time WASM compilation |
| Frame rendering (1080p) | <16ms | 60 FPS sustained |
| Memory usage | ~50MB | For 1080p canvas |
Memory Management
// WASM cleanup
renderer.free(); // Call when done to free WASM memory
// React cleanup
useEffect(() => {
return () => {
rendererRef.current?.free();
};
}, []);
Type Definitions
Complete TypeScript Types
// Layer types
type LayerType = 'solidColor' | 'image' | 'text';
type BlendMode = 'normal' | 'multiply' | 'screen' | 'overlay' | 'add' | 'lighten' | 'darken';
// Color as RGBA tuple
type Color = [number, number, number, number];
// Transform interface
interface Transform {
x: number;
y: number;
scale_x: number;
scale_y: number;
rotation: number;
opacity: number;
}
// Complete layer interface
interface WasmLayer {
id: string;
type: LayerType;
color?: Color;
imagePath?: string;
transform: Transform;
blend_mode?: BlendMode;
visible: boolean;
z_index: number;
}
// Metrics interface
interface RenderMetrics {
width: number;
height: number;
ready: boolean;
lastFrameTime?: number;
fps?: number;
}
// Error types
class CompositorError extends Error {
constructor(message: string);
}
class WasmLoadError extends Error {
constructor(message: string);
}
Best Practices
Rust Backend
// ✅ Good: Reuse compositor instance
let compositor = Compositor::new(1920, 1080)?;
for layers in frames {
let frame = compositor.compose(&layers)?;
frame.save(path)?;
}
// ❌ Bad: Create new compositor each time
for layers in frames {
let compositor = Compositor::new(1920, 1080)?;
let frame = compositor.compose(&layers)?;
}
WASM Preview
// ✅ Good: Single renderer, multiple renders
const renderer = new PreviewRenderer(canvas, 1920, 1080);
layers.forEach(layerSet => renderer.render_frame(JSON.stringify(layerSet)));
// ❌ Bad: Multiple renderers
layers.forEach(layerSet => {
const renderer = new PreviewRenderer(canvas, 1920, 1080);
renderer.render_frame(JSON.stringify(layerSet));
});
React Integration
// ✅ Good: Memoize layers
const layers = useMemo(() => generateLayers(props), [props]);
useEffect(() => renderFrame(layers), [layers, renderFrame]);
// ❌ Bad: Recreate layers every render
useEffect(() => {
const layers = generateLayers(props); // New array every time
renderFrame(layers);
});
Next Steps
- Quick Start Guide - Get started with implementation
- Rust Backend Examples - Server-side composition examples
- WASM Frontend Examples - Browser preview examples
- Node.js Integration - Backend service integration