Skip to main content
Framer Motion can be synchronized with Helios by using MotionValue and useTransform to drive animations based on Helios frame updates.

Installation

Install Framer Motion alongside Helios:
npm install framer-motion @helios-project/core react react-dom

Basic integration

The integration pattern involves:
  1. Creating a MotionValue to represent progress
  2. Syncing the MotionValue to Helios frame updates
  3. Using useTransform to derive animation values
  4. Applying transforms to motion components
import React, { useEffect } from 'react';
import { motion, useMotionValue, useTransform } from 'framer-motion';
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.helios = helios;
}

export default function App() {
    const { currentFrame, duration, fps } = useVideoFrame(helios);

    // 1. Create a MotionValue to represent "time" or "progress"
    const progress = useMotionValue(0);

    // 2. Sync MotionValue to Helios frame on every update
    useEffect(() => {
        const p = currentFrame / (duration * fps);
        progress.set(p);
    }, [currentFrame, duration, fps, progress]);

    // 3. Drive animations using useTransform
    // Rotate 360 degrees over the full duration
    const rotate = useTransform(progress, [0, 1], [0, 360]);

    // Scale up and down
    const scale = useTransform(progress, [0, 0.5, 1], [1, 1.5, 1]);

    // Change color
    const backgroundColor = useTransform(
        progress,
        [0, 0.5, 1],
        ["#ff0055", "#0099ff", "#ff0055"]
    );

    return (
        <div style={{
            width: '100vw',
            height: '100vh',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            backgroundColor: '#111',
            color: 'white',
            fontFamily: 'sans-serif',
            flexDirection: 'column'
        }}>
            <motion.div
                style={{
                    width: 150,
                    height: 150,
                    borderRadius: 30,
                    rotate,
                    scale,
                    backgroundColor
                }}
            />
            <div style={{ marginTop: 40, fontSize: 24 }}>
                Frame: {Math.round(currentFrame)} / {duration * fps}
            </div>
        </div>
    );
}

useVideoFrame hook

Create a custom hook to sync React state with Helios:
import { useState, useEffect } from 'react';

export function useVideoFrame(helios) {
    const [state, setState] = useState({
        currentFrame: helios.getState().currentFrame,
        duration: helios.duration,
        fps: helios.fps
    });

    useEffect(() => {
        // Update local state when helios state changes
        const update = (newState) => {
            setState({
                currentFrame: newState.currentFrame,
                duration: helios.duration,
                fps: helios.fps
            });
        };

        // Subscribe returns an unsubscribe function
        return helios.subscribe(update);
    }, [helios]);

    return state;
}

Integration pattern

Progress-based animation

Calculate normalized progress (0 to 1):
const p = currentFrame / (duration * fps);
progress.set(p);

Transform mappings

Map progress to animation values:
// Simple linear transform
const rotate = useTransform(progress, [0, 1], [0, 360]);

// Multi-keyframe transform
const scale = useTransform(progress, [0, 0.5, 1], [1, 1.5, 1]);

// Color transforms
const backgroundColor = useTransform(
    progress,
    [0, 0.5, 1],
    ["#ff0055", "#0099ff", "#ff0055"]
);

Applying to motion components

Use the style prop to apply MotionValues:
<motion.div
    style={{
        rotate,
        scale,
        backgroundColor
    }}
/>

Why this works

Framer Motion’s MotionValue and useTransform provide:
  • Reactive animation values without triggering re-renders
  • Declarative transform mappings
  • Smooth interpolation between keyframes
  • Full compatibility with Helios frame control
This approach ensures deterministic rendering while maintaining Framer Motion’s developer experience.

Build docs developers (and LLMs) love