Skip to main content
Helios provides first-class support for React through hooks and components that integrate seamlessly with React’s declarative programming model.

Quick start

1

Install dependencies

npm install @helios-project/core react react-dom
2

Create the useVideoFrame hook

hooks/useVideoFrame.ts
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;
}
3

Create your first animation

App.tsx
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

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>
    );
}

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:
components/Sequence.tsx
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:
components/Series.tsx
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

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 }); // ❌
    // ...
}
Always call bindToDocumentTimeline() to enable external control by the player or renderer:
const helios = new Helios({ duration: 5, fps: 30 });
helios.bindToDocumentTimeline();
Attach the Helios instance to window for easy debugging and player integration:
if (typeof window !== 'undefined') {
    (window as any).helios = helios;
}
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

Build docs developers (and LLMs) love