Quick start
Create your first animation
main.ts
import { Helios } from '@helios-project/core';
import './style.css';
// Initialize Helios engine
const helios = new Helios({
duration: 5,
fps: 30,
autoSyncAnimations: true
});
// Expose for the Player and debugging
(window as any).helios = helios;
// Enable external control (e.g. from Renderer)
helios.bindToDocumentTimeline();
Add animation logic
// Subscribe to frame updates
helios.subscribe((state) => {
const { currentFrame } = state;
const progress = currentFrame / (helios.duration * helios.fps);
// Update DOM elements
const box = document.getElementById('box');
if (box) {
box.style.transform = `translateX(${progress * 500}px) rotate(${currentFrame * 2}deg)`;
box.style.opacity = String(Math.min(1, currentFrame / 30));
}
});
Animation approaches
- DOM animations
- Canvas animations
Directly manipulate DOM elements in the subscribe callback:
import { Helios } from '@helios-project/core';
const helios = new Helios({ duration: 5, fps: 30 });
helios.bindToDocumentTimeline();
const box = document.createElement('div');
box.style.width = '100px';
box.style.height = '100px';
box.style.backgroundColor = 'red';
document.body.appendChild(box);
helios.subscribe((state) => {
const progress = state.currentFrame / (state.duration * state.fps);
// Animate position
const x = progress * 500;
box.style.transform = `translateX(${x}px)`;
// Animate opacity
box.style.opacity = String(Math.min(1, state.currentFrame / 30));
});
(window as any).helios = helios;
Draw frame-by-frame animations on a canvas:
import { Helios } from '@helios-project/core';
const helios = new Helios({
fps: 30,
duration: 5,
autoSyncAnimations: true
});
// Create Canvas element
const canvas = document.createElement('canvas');
canvas.width = 1920;
canvas.height = 1080;
canvas.style.width = '100%';
canvas.style.height = '100%';
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d')!;
// Animate using subscribe
helios.subscribe((state) => {
// Clear
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const progress = state.currentFrame / (state.duration * state.fps);
// Draw box
const x = (progress * (canvas.width - 200)) + 100;
const y = canvas.height / 2;
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.rect(x - 50, y - 50, 100, 100);
ctx.fill();
});
// Enable external control
helios.bindToDocumentTimeline();
// Expose for debugging
(window as any).helios = helios;
Animation helpers
Use Helios utility functions for common animation patterns:import { Helios, interpolate, spring } from '@helios-project/core';
const helios = new Helios({
fps: 30,
duration: 5,
autoSyncAnimations: true
});
const helperBox = document.createElement('div');
helperBox.className = 'box';
helperBox.style.backgroundColor = 'hotpink';
helperBox.style.position = 'absolute';
helperBox.style.top = '250px';
helperBox.style.left = '50px';
helperBox.style.width = '100px';
helperBox.style.height = '100px';
document.body.appendChild(helperBox);
helios.subscribe((state) => {
const { currentFrame } = state;
// Interpolate x position: 0 -> 200 over frames 0-60
const x = interpolate(currentFrame, [0, 60], [0, 200], { extrapolateRight: 'clamp' });
// Spring scale: 0 -> 1 starting at frame 0
const scale = spring({
frame: currentFrame,
fps: 30,
from: 0,
to: 1,
config: { stiffness: 100 }
});
helperBox.style.transform = `translateX(${x}px) scale(${scale})`;
});
helios.bindToDocumentTimeline();
(window as any).helios = helios;
Manual sequencing
Implement sequences with conditional logic:import { Helios } from '@helios-project/core';
const helios = new Helios({
fps: 30,
duration: 5,
autoSyncAnimations: true
});
const app = document.getElementById('app')!;
// Create sequence boxes
function createBox(color: string, text: string) {
const box = document.createElement('div');
box.className = 'box';
box.style.backgroundColor = color;
box.textContent = text;
box.style.position = 'absolute';
box.style.display = 'none';
box.style.width = '100px';
box.style.height = '100px';
return box;
}
const seq1 = createBox('red', 'Seq 1');
app.appendChild(seq1);
const seq2 = createBox('blue', 'Seq 2');
app.appendChild(seq2);
const seq3 = createBox('green', 'Seq 3');
app.appendChild(seq3);
// Subscribe to updates
helios.subscribe((state) => {
const { currentFrame } = state;
// Sequence 1: 0 - 30
if (currentFrame >= 0 && currentFrame < 30) {
seq1.style.display = 'flex';
} else {
seq1.style.display = 'none';
}
// Sequence 2: 30 - 60
if (currentFrame >= 30 && currentFrame < 60) {
seq2.style.display = 'flex';
} else {
seq2.style.display = 'none';
}
// Sequence 3: 60 - 90
if (currentFrame >= 60 && currentFrame < 90) {
seq3.style.display = 'flex';
} else {
seq3.style.display = 'none';
}
});
helios.bindToDocumentTimeline();
(window as any).helios = helios;
Advanced patterns
Multiple animations
Orchestrate multiple elements:import { Helios, interpolate } from '@helios-project/core';
const helios = new Helios({ duration: 5, fps: 30 });
const elements = [
{ el: document.getElementById('box1')!, delay: 0, color: 'red' },
{ el: document.getElementById('box2')!, delay: 15, color: 'blue' },
{ el: document.getElementById('box3')!, delay: 30, color: 'green' }
];
helios.subscribe((state) => {
elements.forEach(({ el, delay }) => {
const localFrame = Math.max(0, state.currentFrame - delay);
const x = interpolate(localFrame, [0, 60], [0, 400], { extrapolateRight: 'clamp' });
el.style.transform = `translateX(${x}px)`;
});
});
helios.bindToDocumentTimeline();
State machines
Implement complex animation states:import { Helios } from '@helios-project/core';
enum AnimationState {
INTRO = 'intro',
MAIN = 'main',
OUTRO = 'outro'
}
const helios = new Helios({ duration: 5, fps: 30 });
let currentState: AnimationState = AnimationState.INTRO;
helios.subscribe((state) => {
const { currentFrame } = state;
// Determine state
if (currentFrame < 30) {
currentState = AnimationState.INTRO;
} else if (currentFrame < 120) {
currentState = AnimationState.MAIN;
} else {
currentState = AnimationState.OUTRO;
}
// Execute state-specific logic
switch (currentState) {
case AnimationState.INTRO:
// Intro animations
break;
case AnimationState.MAIN:
// Main animations
break;
case AnimationState.OUTRO:
// Outro animations
break;
}
});
helios.bindToDocumentTimeline();
Best practices
Cache DOM queries
Cache DOM queries
Query DOM elements once, not in every frame:
// Good: Query once
const box = document.getElementById('box');
helios.subscribe((state) => {
if (box) {
box.style.transform = `translateX(${state.currentFrame * 5}px)`;
}
});
// Avoid: Query every frame
helios.subscribe((state) => {
const box = document.getElementById('box'); // ❌
// ...
});
Use requestAnimationFrame for smoothness
Use requestAnimationFrame for smoothness
For interactive animations, combine with
requestAnimationFrame:let latestState = helios.getState();
helios.subscribe((state) => {
latestState = state;
});
function render() {
// Use latestState for rendering
const progress = latestState.currentFrame / (helios.duration * helios.fps);
// Update DOM...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
Always bind to document timeline
Always bind to document timeline
Enable external control for rendering and playback:
const helios = new Helios({ duration: 5, fps: 30 });
helios.bindToDocumentTimeline();
(window as any).helios = helios;
Clean up when needed
Clean up when needed
Unsubscribe when removing animations:
const unsubscribe = helios.subscribe((state) => {
// Animation logic
});
// Later, when cleaning up:
unsubscribe();
TypeScript support
Helios is built with TypeScript and provides full type safety:import type { Helios, HeliosState } from '@helios-project/core';
const helios: Helios = new Helios({
duration: 5,
fps: 30,
autoSyncAnimations: true
});
helios.subscribe((state: HeliosState) => {
const { currentFrame, duration, fps } = state;
// Type-safe state access
});
Next steps
Animation helpers
Learn about interpolation, spring physics, and easing functions
Canvas rendering
Create high-performance canvas animations
Sequences
Build complex multi-scene animations
Export videos
Render your animations to video files