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.
Three.js is a powerful 3D graphics library built on WebGL. Helios provides precise frame control for rendering Three.js scenes to video.
Basic setup
Three.js requires manual rendering driven by Helios instead of using requestAnimationFrame.
import * as THREE from 'three';
import { Helios } from '@helios-project/core';
// Setup Three.js
const canvas = document.getElementById('composition-canvas') as HTMLCanvasElement;
if (!canvas) throw new Error('Canvas not found');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
const scene = new THREE.Scene();
// Camera
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
// Lighting
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1).normalize();
scene.add(light);
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
// Object
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Resize Logic
const onResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', onResize);
onResize();
// Setup Helios
const helios = new Helios({ duration: 5, fps: 30 });
helios.bindToDocumentTimeline();
// Drive Animation
function draw(frame: number) {
const time = frame / 30; // fps hardcoded to match Helios config
// Rotate cube based on time
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
}
helios.subscribe((state) => {
draw(state.currentFrame);
});
// Initial draw
draw(0);
// Expose for debugging
(window as any).helios = helios;
(window as any).scene = scene;
React Three Fiber integration
For React applications, use @react-three/fiber with Helios controlling the frame loop.
import React, { useState, useEffect } from 'react';
import { Canvas, RootState } from '@react-three/fiber';
import { Helios } from '@helios-project/core';
import Scene from './Scene';
// Singleton Helios instance
const helios = new Helios({
fps: 30,
duration: 10,
autoSyncAnimations: true
});
helios.bindToDocumentTimeline();
if (typeof window !== 'undefined') {
(window as any).helios = helios;
}
export default function App() {
const [r3fState, setR3fState] = useState<RootState | null>(null);
useEffect(() => {
if (!r3fState) return;
// Drive R3F loop manually
return helios.subscribe((state) => {
// R3F's advance(timestamp) sets the internal clock.elapsedTime
// We pass time in seconds because Three.js clocks work in seconds
const timeInSeconds = state.currentFrame / state.fps;
// Explicitly advance the R3F state
r3fState.advance(timeInSeconds);
});
}, [r3fState]);
return (
<Canvas
frameloop="never"
onCreated={(state) => setR3fState(state)}
style={{ width: '100%', height: '100%', background: '#111' }}
camera={{ position: [0, 0, 5] }}
>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} />
<Scene />
</Canvas>
);
}
Scene component
import React, { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { Mesh } from 'three';
export default function Scene() {
const meshRef = useRef<Mesh>(null);
useFrame((state) => {
// state.clock.elapsedTime matches what we passed to advance()
const t = state.clock.elapsedTime;
if (meshRef.current) {
meshRef.current.rotation.x = t;
meshRef.current.rotation.y = t * 0.5;
}
});
return (
<mesh ref={meshRef}>
<boxGeometry args={[2, 2, 2]} />
<meshStandardMaterial color="orange" />
</mesh>
);
}
Critical patterns
Disable automatic rendering
Three.js and React Three Fiber both have built-in render loops. You must disable them:
- Vanilla Three.js: Don’t call
requestAnimationFrame or renderer.setAnimationLoop()
- React Three Fiber: Set
frameloop="never" on the <Canvas> component
Use Helios time, not system time
Always calculate animations from state.currentFrame / fps instead of Date.now() or performance.now():
helios.subscribe((state) => {
const time = state.currentFrame / state.fps; // Deterministic
cube.rotation.x = time; // Repeatable across renders
});
Handle resize properly
Update camera aspect ratio and renderer size on window resize:
const onResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', onResize);
WebGL context limits
Browsers limit the number of WebGL contexts. Destroy renderers when unmounting:
useEffect(() => {
const renderer = new THREE.WebGLRenderer();
return () => {
renderer.dispose();
// Also dispose geometries and materials
geometry.dispose();
material.dispose();
};
}, []);
Scene complexity
Three.js performance depends on:
- Polygon count: Keep meshes under 100k triangles for smooth rendering
- Draw calls: Merge geometries to reduce draw calls
- Texture size: Use power-of-2 textures (512x512, 1024x1024) for GPU efficiency
- Lighting: Limit real-time shadows and use baked lighting where possible
Rendering resolution
Match the renderer size to your target export resolution:
// For 1080p export
renderer.setSize(1920, 1080);
// For 4K export
renderer.setSize(3840, 2160);
Higher resolutions increase render time proportionally.
Frame rate vs quality
Lower FPS reduces total render time but may affect motion smoothness:
- 30 fps: Standard for most content, good balance
- 60 fps: Smooth motion, doubles render time
- 24 fps: Cinematic feel, fastest render
Package dependencies
{
"dependencies": {
"three": "^0.182.0",
"@helios-project/core": "latest"
},
"devDependencies": {
"typescript": "^5.0.0",
"vite": "^7.1.2"
}
}
For React Three Fiber:
{
"dependencies": {
"three": "^0.182.0",
"@react-three/fiber": "^8.0.0",
"@helios-project/core": "latest",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Common issues
Black screen on render
Ensure you have lighting in your scene:
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
scene.add(light);
const ambient = new THREE.AmbientLight(0x404040);
scene.add(ambient);
Animation not playing
Verify Helios is bound to the document timeline:
helios.bindToDocumentTimeline();
And that you’re subscribing to state changes:
helios.subscribe((state) => {
// Update scene based on state.currentFrame
});
Canvas not resizing
Update both camera and renderer on resize events:
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});