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.
Helios provides first-class support for React through hooks and components that integrate seamlessly with React’s declarative programming model.
Quick start
Install dependencies
npm install @helios-project/core react react-dom
Create the useVideoFrame hook
import { useState , useEffect } from 'react' ;
import { Helios } from '@helios-project/core' ;
export function useVideoFrame ( helios : Helios ) {
const [ frame , setFrame ] = useState ( helios . getState (). currentFrame );
useEffect (() => {
// Update local state when helios state changes
const update = ( state : { currentFrame : number }) => setFrame ( state . currentFrame );
// Subscribe returns an unsubscribe function
return helios . subscribe ( update );
}, [ helios ]);
return frame ;
}
Create your first animation
import { Helios } from '@helios-project/core' ;
import { useVideoFrame } from './hooks/useVideoFrame' ;
const duration = 5 ;
const fps = 30 ;
const helios = new Helios ({ duration , fps });
// Bind to document timeline so it can be driven by the player/renderer
helios . bindToDocumentTimeline ();
// Expose to window for debugging/player control
if ( typeof window !== 'undefined' ) {
( window as any ). helios = helios ;
}
export default function App () {
const frame = useVideoFrame ( helios );
// Calculate animation values
const progress = frame / ( duration * fps );
const opacity = Math . min ( 1 , frame / 30 );
const scale = 1 + Math . sin ( progress * Math . PI * 4 ) * 0.2 ;
const rotation = progress * 360 ;
return (
< div style = { {
display: 'flex' ,
flexDirection: 'column' ,
alignItems: 'center' ,
justifyContent: 'center' ,
height: '100%' ,
color: 'white' ,
fontFamily: 'sans-serif'
} } >
< div style = { {
width: 200 ,
height: 200 ,
backgroundColor: '#61dafb' ,
borderRadius: 20 ,
display: 'flex' ,
alignItems: 'center' ,
justifyContent: 'center' ,
opacity: opacity ,
transform: `scale( ${ scale } ) rotate( ${ rotation } deg)` ,
boxShadow: '0 0 20px rgba(97, 218, 251, 0.5)'
} } >
< span style = { {
fontSize: '2rem' ,
fontWeight: 'bold' ,
color: '#282c34' ,
transform: `rotate(- ${ rotation } deg)`
} } >
React
</ span >
</ div >
< div style = { { marginTop: 40 , textAlign: 'center' } } >
< p > Frame: { frame . toFixed ( 2 ) } </ p >
< p > Progress: { ( progress * 100 ). toFixed ( 1 ) } % </ p >
< p > FPS: { fps } </ p >
</ div >
</ div >
);
}
Animation approaches
DOM animations
Canvas animations
Animate React components using inline styles and the useVideoFrame hook: import { useVideoFrame } from './hooks/useVideoFrame' ;
export default function DOMAnimation () {
const frame = useVideoFrame ( helios );
const progress = frame / ( duration * fps );
return (
< div style = { {
opacity: Math . min ( 1 , frame / 30 ),
transform: `translateX( ${ progress * 500 } px) rotate( ${ frame * 2 } deg)`
} } >
Animated content
</ div >
);
}
Use refs and useEffect to draw frame-by-frame animations: import { useRef , useEffect } from 'react' ;
import { useVideoFrame } from './hooks/useVideoFrame' ;
export default function CanvasAnimation () {
const canvasRef = useRef < HTMLCanvasElement >( null );
const frame = useVideoFrame ( helios );
useEffect (() => {
const canvas = canvasRef . current ;
if ( ! canvas ) return ;
const ctx = canvas . getContext ( '2d' );
if ( ! ctx ) return ;
const { width , height } = canvas ;
const progress = frame / ( duration * fps );
// Clear
ctx . fillStyle = '#111' ;
ctx . fillRect ( 0 , 0 , width , height );
// Draw animated shapes
const cx = width / 2 ;
const cy = height / 2 ;
const radius = 100 ;
ctx . save ();
ctx . translate ( cx , cy );
ctx . rotate ( progress * Math . PI * 2 );
ctx . strokeStyle = '#61dafb' ;
ctx . lineWidth = 5 ;
// Atom rings
for ( let i = 0 ; i < 3 ; i ++ ) {
ctx . save ();
ctx . rotate (( i * Math . PI ) / 3 );
ctx . beginPath ();
ctx . ellipse ( 0 , 0 , radius , radius / 2.5 , 0 , 0 , Math . PI * 2 );
ctx . stroke ();
ctx . restore ();
}
// Nucleus
ctx . fillStyle = '#61dafb' ;
ctx . beginPath ();
ctx . arc ( 0 , 0 , 20 , 0 , Math . PI * 2 );
ctx . fill ();
ctx . restore ();
}, [ frame ]);
return (
< canvas
ref = { canvasRef }
width = { 1920 }
height = { 1080 }
style = { { width: '100%' , height: '100%' } }
/>
);
}
Animation helpers
Helios provides utility functions for common animation patterns:
import { interpolate , spring } from '@helios-project/core' ;
import { useVideoFrame } from './hooks/useVideoFrame' ;
function HelperDemo () {
const frame = useVideoFrame ( helios );
// Interpolate x position: 0 -> 200 over frames 0-60
const x = interpolate ( frame , [ 0 , 60 ], [ 0 , 200 ], { extrapolateRight: 'clamp' });
// Spring scale: 0 -> 1 starting at frame 0
const scale = spring ({
frame ,
fps: 30 ,
from: 0 ,
to: 1 ,
config: { stiffness: 100 }
});
return (
< div style = { {
transform: `translateX( ${ x } px) scale( ${ scale } )` ,
width: 100 ,
height: 100 ,
background: 'hotpink'
} } >
Animated
</ div >
);
}
Sequencing components
Sequence component
Create time-based sequences that show/hide content:
import { useContext } from 'react' ;
import { sequence } from '@helios-project/core' ;
import { FrameContext } from './FrameContext' ;
export const Sequence = ({ from , durationInFrames , children }) => {
const parentFrame = useContext ( FrameContext );
const { isActive , relativeFrame } = sequence ({
frame: parentFrame ,
from ,
durationInFrames
});
if ( ! isActive ) return null ;
return (
< FrameContext.Provider value = { relativeFrame } >
{ children }
</ FrameContext.Provider >
);
};
Series component
Automatically sequence child components one after another:
import { Children , cloneElement , isValidElement } from 'react' ;
export const Series = ({ children }) => {
let currentFrom = 0 ;
return (
<>
{ Children . map ( children , ( child ) => {
if ( ! isValidElement ( child )) {
return child ;
}
const duration = child . props . durationInFrames || 0 ;
const newProps = { from: currentFrom };
currentFrom += duration ;
return cloneElement ( child , newProps );
}) }
</>
);
};
Frame context
Create a context for sharing frame state:
components/FrameContext.tsx
import { createContext } from 'react' ;
export const FrameContext = createContext ( 0 );
Usage example
import { useState , useEffect } from 'react' ;
import { FrameContext } from './components/FrameContext' ;
import { Sequence } from './components/Sequence' ;
import { Series } from './components/Series' ;
function MovingBox ({ color , label }) {
const frame = useContext ( FrameContext );
const x = frame * 5 ;
return (
< div style = { {
position: 'absolute' ,
left: ` ${ x } px` ,
width: 100 ,
height: 100 ,
backgroundColor: color
} } >
{ label }
</ div >
);
}
export default function App () {
const [ frame , setFrame ] = useState ( 0 );
useEffect (() => {
return helios . subscribe (( state ) => setFrame ( state . currentFrame ));
}, []);
return (
< FrameContext.Provider value = { frame } >
< Series >
< Sequence durationInFrames = { 60 } >
< MovingBox color = "#ff4444" label = "Seq 1" />
</ Sequence >
< Sequence durationInFrames = { 60 } >
< MovingBox color = "#4444ff" label = "Seq 2" />
</ Sequence >
</ Series >
</ FrameContext.Provider >
);
}
Best practices
Initialize Helios outside components
Create the Helios instance outside your component to avoid recreating it on every render: // Good: Single instance
const helios = new Helios ({ duration: 5 , fps: 30 });
helios . bindToDocumentTimeline ();
export default function App () {
const frame = useVideoFrame ( helios );
// ...
}
// Avoid: New instance on every render
export default function App () {
const helios = new Helios ({ duration: 5 , fps: 30 }); // ❌
// ...
}
Bind to document timeline
Always call bindToDocumentTimeline() to enable external control by the player or renderer: const helios = new Helios ({ duration: 5 , fps: 30 });
helios . bindToDocumentTimeline ();
Expose helios for debugging
Attach the Helios instance to window for easy debugging and player integration: if ( typeof window !== 'undefined' ) {
( window as any ). helios = helios ;
}
Use strict mode carefully
React 18+ Strict Mode causes double-mounting in development. This is fine for Helios, but be aware of potential duplicate subscriptions during development.
TypeScript support
Helios is written in TypeScript and provides full type definitions:
import type { Helios } from '@helios-project/core' ;
interface VideoFrameHookReturn {
frame : number ;
progress : number ;
}
export function useVideoFrame ( helios : Helios ) : number {
const [ frame , setFrame ] = useState < number >( helios . getState (). currentFrame );
// ...
return frame ;
}
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