Documentation Index
Fetch the complete documentation index at: https://mintlify.com/BintzGavin/helios/llms.txt
Use this file to discover all available pages before exploring further.
Pixi.js is a fast 2D rendering engine built on WebGL. Helios provides deterministic frame control for exporting Pixi.js animations to video.
Basic setup
Pixi.js requires disabling its internal ticker and using Helios for frame updates.
import { Helios } from '@helios-project/core';
import { Application, Graphics } from 'pixi.js';
async function init() {
// Initialize Pixi
const app = new Application();
await app.init({
resizeTo: window,
backgroundColor: 0x111111,
});
// Append canvas to DOM
document.getElementById('app')!.appendChild(app.canvas);
// Initialize Helios
const helios = new Helios({
fps: 30,
duration: 5,
});
// Create a rotating rectangle
const graphics = new Graphics();
graphics.rect(0, 0, 100, 100).fill({ color: 0xff4444 });
graphics.pivot.set(50, 50);
graphics.position.set(app.screen.width / 2, app.screen.height / 2);
app.stage.addChild(graphics);
// Handle Resize
window.addEventListener('resize', () => {
graphics.position.set(app.screen.width / 2, app.screen.height / 2);
});
// Bind to document.timeline so the Renderer can drive us
helios.bindToDocumentTimeline();
// Sync with Helios
helios.subscribe((state) => {
const time = state.currentFrame / helios.fps;
graphics.rotation = time * Math.PI; // Rotate 180 degrees per second
});
// Expose helios for the Renderer/Bridge
(window as any).helios = helios;
}
init();
React integration
For React applications, manage Pixi.js lifecycle in a useEffect hook.
import React, { useRef, useEffect } from 'react';
import { Helios } from '@helios-project/core';
import { Application, Graphics } from 'pixi.js';
const duration = 5;
const fps = 30;
const helios = new Helios({ duration, fps });
helios.bindToDocumentTimeline();
if (typeof window !== 'undefined') {
window.helios = helios;
}
export default function App() {
const containerRef = useRef(null);
useEffect(() => {
let app = null;
let unsubscribe = null;
let mounted = true;
const init = async () => {
const pixiApp = new Application();
await pixiApp.init({
resizeTo: window,
backgroundColor: 0x111111,
antialias: true
});
if (!mounted) {
pixiApp.destroy({ removeView: true, children: true });
return;
}
app = pixiApp;
if (containerRef.current) {
containerRef.current.appendChild(app.canvas);
}
// Create a simple rotating rectangle
const rect = new Graphics();
rect.rect(-50, -50, 100, 100);
rect.fill(0x61dafb);
rect.x = app.screen.width / 2;
rect.y = app.screen.height / 2;
app.stage.addChild(rect);
// Sync with Helios
unsubscribe = helios.subscribe((state) => {
const time = state.currentTime;
// Rotate based on time
rect.rotation = time * Math.PI;
// Keep centered on resize
rect.x = app.screen.width / 2;
rect.y = app.screen.height / 2;
});
};
init();
return () => {
mounted = false;
if (unsubscribe) unsubscribe();
if (app) {
app.destroy({ removeView: true, children: true });
}
};
}, []);
return (
<div ref={containerRef} style={{ width: '100%', height: '100%' }} />
);
}
Custom React hook
Create a reusable hook to sync with Helios frames:
import { useState, useEffect } from 'react';
export function useVideoFrame(helios) {
const [frame, setFrame] = useState(helios.getState().currentFrame);
useEffect(() => {
const update = (state) => setFrame(state.currentFrame);
return helios.subscribe(update);
}, [helios]);
return frame;
}
Usage:
import { useVideoFrame } from './hooks/useVideoFrame';
function MyComponent() {
const frame = useVideoFrame(helios);
// Use frame in your rendering logic
}
Critical patterns
Disable Pixi.js ticker
Pixi.js has an internal ticker for animations. Don’t use it with Helios:
// DON'T DO THIS
app.ticker.add(() => {
// This creates non-deterministic rendering
});
// DO THIS INSTEAD
helios.subscribe((state) => {
const time = state.currentFrame / helios.fps;
// Update your graphics based on Helios time
});
Use Helios time for animations
Calculate all animations from state.currentFrame or state.currentTime:
helios.subscribe((state) => {
const time = state.currentFrame / helios.fps;
// Position animation
sprite.x = Math.sin(time * 2) * 100 + app.screen.width / 2;
// Rotation animation
sprite.rotation = time * Math.PI;
// Alpha animation
sprite.alpha = (Math.sin(time) + 1) / 2;
});
Async initialization
Pixi.js v8+ requires async initialization. Always await app.init():
const app = new Application();
await app.init({
resizeTo: window,
backgroundColor: 0x111111,
});
Sprite batching
Pixi.js automatically batches sprites with the same texture. Keep sprites using the same texture together:
// Good: sprites batched together
const texture = await Assets.load('sprite.png');
for (let i = 0; i < 1000; i++) {
const sprite = new Sprite(texture);
app.stage.addChild(sprite);
}
// Bad: forces multiple draw calls
for (let i = 0; i < 1000; i++) {
const texture = await Assets.load('sprite.png');
const sprite = new Sprite(texture);
app.stage.addChild(sprite);
}
Graphics objects
Reuse Graphics objects instead of recreating them each frame:
// Good: create once, update properties
const graphics = new Graphics();
app.stage.addChild(graphics);
helios.subscribe((state) => {
const time = state.currentTime;
graphics.rotation = time;
});
// Bad: recreates every frame
helios.subscribe((state) => {
const graphics = new Graphics(); // Memory leak!
graphics.rect(0, 0, 100, 100);
app.stage.addChild(graphics);
});
Texture management
Preload textures and dispose of them when done:
import { Assets } from 'pixi.js';
// Preload textures
const textures = await Assets.load([
'sprite1.png',
'sprite2.png',
'background.png'
]);
// Use textures
const sprite = new Sprite(textures['sprite1.png']);
// Clean up when unmounting
useEffect(() => {
return () => {
Assets.unload('sprite1.png');
};
}, []);
Canvas resolution
Set resolution based on your export target:
const app = new Application();
await app.init({
width: 1920,
height: 1080,
resolution: window.devicePixelRatio || 1,
autoDensity: true,
});
Higher resolutions increase memory usage and render time.
Filters and effects
Filters are GPU-intensive. Use sparingly:
import { BlurFilter } from 'pixi.js';
const blur = new BlurFilter();
sprite.filters = [blur];
// Limit filter updates
helios.subscribe((state) => {
if (state.currentFrame % 5 === 0) {
blur.blur = Math.sin(state.currentTime) * 10;
}
});
Package dependencies
{
"dependencies": {
"pixi.js": "^8.0.0",
"@helios-project/core": "latest"
},
"devDependencies": {
"@types/node": "^20.0.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
}
Common issues
Canvas not appearing
Ensure you await Pixi.js initialization and append the canvas:
const app = new Application();
await app.init({ resizeTo: window });
document.getElementById('app')!.appendChild(app.canvas);
Animation stuttering
Verify Helios is properly bound and you’re not mixing ticker with Helios:
// Don't use both!
helios.bindToDocumentTimeline(); // Use this
// app.ticker.add(...); // Not this
Memory leaks in React
Always destroy the Pixi.js app on unmount:
useEffect(() => {
const init = async () => {
const app = new Application();
await app.init();
// ... setup
};
init();
return () => {
app?.destroy({ removeView: true, children: true });
};
}, []);
Blurry graphics
Set autoDensity and match device pixel ratio:
await app.init({
resolution: window.devicePixelRatio || 1,
autoDensity: true,
});