Quickstart
This guide will walk you through creating your first Helios composition from scratch. In about 10 minutes, you’ll have a working animated video.
We’ll build a simple canvas animation that you can preview in your browser and render to MP4. This example uses vanilla JavaScript, but Helios works with React, Vue, Svelte, and other frameworks.
What we’re building
A 5-second animation featuring:
A circle moving across the screen
A rotating square in the center
Smooth, frame-perfect playback
Setup your project
Create a new project directory
mkdir my-first-helios-video
cd my-first-helios-video
npm init -y
Install dependencies
npm install @helios-project/core @helios-project/player vite
This installs:
@helios-project/core - The animation engine
@helios-project/player - Preview player
vite - Development server and bundler
Create project files
Create the following file structure: my-first-helios-video/
├── package.json
├── index.html
└── src/
└── main.ts
Create your composition
HTML entry point
Create index.html :
<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title > My First Helios Video </ title >
< style >
* {
margin : 0 ;
padding : 0 ;
box-sizing : border-box ;
}
body {
width : 100 vw ;
height : 100 vh ;
overflow : hidden ;
background : #000 ;
}
#composition-canvas {
display : block ;
width : 100 % ;
height : 100 % ;
}
</ style >
</ head >
< body >
< canvas id = "composition-canvas" ></ canvas >
< script type = "module" src = "/src/main.ts" ></ script >
</ body >
</ html >
Composition logic
Create src/main.ts :
import { Helios , HeliosState } from '@helios-project/core' ;
const canvas = document . getElementById ( 'composition-canvas' ) as HTMLCanvasElement ;
const ctx = canvas . getContext ( '2d' ) ! ;
// Setup canvas to match window size
const resizeCanvas = () => {
canvas . width = window . innerWidth ;
canvas . height = window . innerHeight ;
};
resizeCanvas ();
window . addEventListener ( 'resize' , resizeCanvas );
// Video configuration
const duration = 5 ; // seconds
const fps = 30 ;
// Initialize Helios engine
const helios = new Helios ({
duration ,
fps ,
});
// Bind to document timeline so the player can drive us
helios . bindToDocumentTimeline ();
// Draw function - called on every frame update
function draw ( currentFrame : number ) {
const time = currentFrame / fps * 1000 ; // Convert to milliseconds
const progress = ( time % ( duration * 1000 )) / ( duration * 1000 ); // 0 to 1
const { width , height } = canvas ;
// Clear canvas
ctx . fillStyle = '#111' ;
ctx . fillRect ( 0 , 0 , width , height );
// Draw moving circle
const x = progress * width ;
const y = height / 2 ;
const radius = 50 ;
ctx . fillStyle = 'royalblue' ;
ctx . beginPath ();
ctx . arc ( x , y , radius , 0 , Math . PI * 2 );
ctx . fill ();
// Draw rotating square
const squareSize = 100 ;
ctx . save ();
ctx . translate ( width / 2 , height / 2 );
ctx . rotate ( progress * Math . PI * 2 );
ctx . fillStyle = 'tomato' ;
ctx . fillRect ( - squareSize / 2 , - squareSize / 2 , squareSize , squareSize );
ctx . restore ();
}
// Subscribe to Helios state changes
helios . subscribe (( state : HeliosState ) => {
draw ( state . currentFrame );
});
// Expose helios globally for debugging and player control
declare global {
interface Window {
helios : Helios ;
}
}
window . helios = helios ;
Understanding the code
Let’s break down what’s happening:
Initialize Helios
const helios = new Helios ({
duration: 5 , // 5 second video
fps: 30 , // 30 frames per second = 150 total frames
});
This creates a Helios instance that manages the animation timeline.
Bind to document timeline
helios . bindToDocumentTimeline ();
This connects Helios to the browser’s native animation system, allowing the player and renderer to control playback.
Subscribe to frame updates
helios . subscribe (( state : HeliosState ) => {
draw ( state . currentFrame );
});
Every time Helios updates (play, pause, seek), your draw function is called with the current frame number.
Calculate progress
const progress = ( time % ( duration * 1000 )) / ( duration * 1000 );
Convert the current frame to a 0-1 progress value. This makes it easy to animate properties smoothly.
Expose to window
The player and renderer look for window.helios to control your composition.
Preview your composition
Add dev script to package.json
{
"scripts" : {
"dev" : "vite"
}
}
Start the dev server
Open your browser to http://localhost:5173. You should see your animation!
Test the preview controls
Open your browser console and try: // Play the animation
helios . play ();
// Pause
helios . pause ();
// Jump to frame 75 (middle of the video)
helios . seek ( 75 );
// Get current state
console . log ( helios . getState ());
Add the player component
For a better preview experience with UI controls, use the Helios Player:
Create a player HTML file
Create preview.html : <! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title > Helios Player Preview </ title >
</ head >
< body >
< helios-player
src = "./index.html"
width = "1920"
height = "1080"
></ helios-player >
< script type = "module" >
import '@helios-project/player' ;
</ script >
</ body >
</ html >
Preview with player controls
Navigate to http://localhost:5173/preview.html You now have:
Play/pause button
Seek bar
Frame counter
Export options
The player loads your composition in a sandboxed iframe, providing isolation and standard HTMLMediaElement controls.
Render to video
Now let’s render your composition to an MP4 file.
Install the renderer
npm install @helios-project/renderer
Create a render script
Create render.ts : import { Renderer } from '@helios-project/renderer' ;
import { resolve } from 'path' ;
const renderer = new Renderer ({
width: 1920 ,
height: 1080 ,
fps: 30 ,
mode: 'canvas' , // Use canvas rendering strategy
});
const compositionUrl = `file:// ${ resolve ( './dist/index.html' ) } ` ;
const outputPath = './output.mp4' ;
console . log ( 'Starting render...' );
await renderer . render ( compositionUrl , outputPath );
console . log ( `Video saved to ${ outputPath } ` );
Update package.json scripts
{
"scripts" : {
"dev" : "vite" ,
"build" : "vite build" ,
"render" : "npm run build && npx tsx render.ts"
}
}
Install tsx for running TypeScript
Render your video
This will:
Build your composition with Vite
Launch headless Chrome
Capture each frame
Encode to MP4 with FFmpeg
Your video will be saved as output.mp4!
Make sure your composition is built before rendering. The renderer needs the bundled files, not source files.
Using animation helpers
Helios includes powerful animation utilities. Let’s enhance our composition:
import { Helios , interpolate , spring } from '@helios-project/core' ;
helios . subscribe (( state : HeliosState ) => {
const { currentFrame } = state ;
// Smooth easing with interpolate
const x = interpolate (
currentFrame ,
[ 0 , 150 ], // Input range (frames)
[ 0 , canvas . width ], // Output range (pixels)
{ easing : ( t ) => t * t * ( 3 - 2 * t ) } // Smoothstep easing
);
// Spring physics for bounce
const scale = spring ({
frame: currentFrame ,
fps: 30 ,
from: 1 ,
to: 2 ,
config: { tension: 300 , friction: 10 }
});
// Draw with animated values
ctx . save ();
ctx . translate ( x , canvas . height / 2 );
ctx . scale ( scale , scale );
ctx . fillStyle = 'royalblue' ;
ctx . beginPath ();
ctx . arc ( 0 , 0 , 50 , 0 , Math . PI * 2 );
ctx . fill ();
ctx . restore ();
});
Available helpers
import { interpolate } from '@helios-project/core' ;
// Linear interpolation
const opacity = interpolate (
currentFrame ,
[ 0 , 30 ], // Frames 0-30
[ 0 , 1 ], // Opacity 0-100%
);
// With easing
const x = interpolate (
currentFrame ,
[ 0 , 150 ],
[ 0 , 1920 ],
{ easing : ( t ) => Math . pow ( t , 2 ) } // Ease in quad
);
// Clamp extrapolation
const scale = interpolate (
currentFrame ,
[ 30 , 60 ],
[ 1 , 2 ],
{ extrapolateLeft: 'clamp' , extrapolateRight: 'clamp' }
);
Next steps
Explore examples Check out 80+ examples in the GitHub repository covering:
GSAP animations
Three.js 3D scenes
Chart.js visualizations
Lottie animations
Framer Motion
And more
Learn the API Dive deeper into Helios capabilities:
Audio tracks and mixing
Captions and subtitles
Input props and schemas
Timeline markers
Distributed rendering
Framework integration Use Helios with your preferred framework:
React with useVideoFrame() hook
Vue with composables
Svelte with stores
Solid.js integration
Production rendering Deploy Helios for scale:
Docker containerization
AWS Lambda distributed rendering
Google Cloud Run
Local orchestrator for parallel rendering
Troubleshooting
Canvas is blank
Make sure you:
Resize the canvas to match the window
Clear the canvas before drawing
Subscribe to Helios state updates
Animation doesn’t update
Verify that:
helios.bindToDocumentTimeline() is called
window.helios is exposed
You’re calling helios.play() or seeking manually
Render produces black frames
Check that:
Your composition is built (npm run build)
The composition URL is correct (use file:// protocol)
The canvas has proper dimensions
TypeScript errors
Add type declarations:
declare global {
interface Window {
helios : Helios ;
}
}
Tips for success
Start simple
Begin with basic shapes and movements. Add complexity gradually.
Use progress values
Convert frames to 0-1 progress for easier math: const progress = currentFrame / ( duration * fps );
Preview often
The dev server provides instant feedback. Use it liberally.
Expose to window
Always export window.helios so the player and renderer can control your composition.
Test different frame rates
30fps is standard, but try 60fps for smoother motion or 24fps for a cinematic feel.
Congratulations! You’ve created your first Helios video. The same patterns you learned here scale to complex, production-ready compositions.