Overview
Helios uses a driver-based architecture to synchronize animations across different rendering contexts. The TimeDriver interface allows you to create custom implementations for specialized workflows beyond DOM and canvas.
TimeDriver interface
All drivers must implement the TimeDriver interface:
Required methods
init(scope: unknown)
Called once when the Helios instance is created. Use this to set up your rendering context.
update(timeInMs: number, options)
Called every frame to synchronize your rendering context to the given time.
waitUntilStable()
Return a promise that resolves when all assets are loaded and ready to render.
Optional methods
dispose() - Clean up resources when the instance is destroyed
subscribeToMetadata(callback) - Notify Helios about discovered audio tracks
getAudioContext() - Return Web Audio API context for mixing
getAudioSourceNode(trackId) - Return audio source node for a specific track
Built-in drivers
DomDriver
The default driver for HTML/CSS animations. It:
- Scans for animations using
document.getAnimations()
- Seeks animations via
animation.currentTime
- Discovers shadow DOM boundaries
- Syncs
<audio> and <video> elements
- Tracks audio metadata with
data-helios-track-id
NoopDriver
A no-op driver that does nothing. Useful for:
- Pure canvas compositions with manual timing
- Testing
- Headless environments without DOM
Creating a custom driver
Example: Three.js driver
Here’s a custom driver for synchronizing Three.js animations:
Using the custom driver
Custom tickers
Drivers control where animations happen. Tickers control when frames are rendered during preview.
Ticker interface
Built-in tickers
RafTicker - Uses requestAnimationFrame (default for browser)
TimeoutTicker - Uses setTimeout for Node.js environments
ManualTicker - Allows manual frame stepping for tests
Example: Fixed timestep ticker
Audio track discovery
Drivers can notify Helios about audio tracks for mixing and export.
Custom drivers must be deterministic. The same timeInMs should always produce identical visual output, regardless of how many times update() is called or in what order.
Best practices
Use existing drivers when possible - DomDriver handles most HTML/CSS/SVG use cases
Make drivers stateless - Don’t accumulate state across update() calls
Handle disposal properly - Clean up event listeners, contexts, and resources
Test with manual ticker - Use ManualTicker to verify frame-perfect accuracy
Document scope requirements - Make it clear what animationScope should contain
Next steps