Skip to main content
Helios provides a comprehensive set of animation helpers to create smooth, natural motion in your video compositions. These utilities handle interpolation, spring physics, and easing functions.

interpolate()

Maps an input value from one range to another with support for easing and extrapolation.
import { interpolate } from '@helios-project/core';

const opacity = interpolate(frame, [0, 30], [0, 1]);
const scale = interpolate(frame, [0, 60, 120], [1, 1.5, 1]);

Parameters

input
number
required
The value to interpolate
inputRange
number[]
required
Array of input values (must be strictly monotonically increasing). Minimum 2 elements.
outputRange
number[]
required
Array of output values (must match length of inputRange)
options
InterpolateOptions
Configuration for extrapolation and easing

Returns

number - The interpolated value

Examples

Basic interpolation

import { interpolate } from '@helios-project/core';
import { useVideoFrame } from './hooks/useVideoFrame';

function AnimatedBox({ helios }) {
  const frame = useVideoFrame(helios);
  
  // Fade in over first 30 frames
  const opacity = interpolate(frame, [0, 30], [0, 1]);
  
  // Move from left to right
  const x = interpolate(frame, [0, 120], [0, 800]);
  
  return (
    <div style={{ opacity, transform: `translateX(${x}px)` }}>
      Content
    </div>
  );
}

Multi-point interpolation

// Create a bounce effect with multiple keyframes
const y = interpolate(
  frame,
  [0, 30, 60, 90, 120],
  [0, -100, -50, -75, 0]
);

With extrapolation

const x = interpolate(
  frame,
  [0, 60],
  [0, 200],
  { extrapolateRight: 'clamp' } // Stop at 200 after frame 60
);

With easing

import { interpolate, Easing } from '@helios-project/core';

const scale = interpolate(
  frame,
  [0, 60],
  [1, 2],
  { easing: Easing.cubic.out }
);

spring()

Calculates spring physics values for natural, bouncy motion using a damped harmonic oscillator simulation.
import { spring } from '@helios-project/core';

const scale = spring({
  frame,
  fps: 30,
  from: 0,
  to: 1,
  config: { stiffness: 100, damping: 10 }
});

Parameters

options
SpringOptions
required
Spring configuration object

Returns

number - The calculated spring value at the current frame

Examples

Basic spring animation

import { spring } from '@helios-project/core';

function SpringBox({ helios }) {
  const frame = useVideoFrame(helios);
  
  const scale = spring({
    frame,
    fps: 30,
    from: 0,
    to: 1
  });
  
  return (
    <div style={{ transform: `scale(${scale})` }}>
      Bouncy!
    </div>
  );
}

Configuring spring physics

// Tight, fast spring
const tightSpring = spring({
  frame,
  fps: 30,
  config: { stiffness: 200, damping: 15 }
});

// Loose, wobbly spring
const wobblySpring = spring({
  frame,
  fps: 30,
  config: { stiffness: 50, damping: 5 }
});

// Heavy, slow spring
const heavySpring = spring({
  frame,
  fps: 30,
  config: { mass: 5, stiffness: 100, damping: 20 }
});

Preventing overshoot

const scale = spring({
  frame,
  fps: 30,
  from: 0,
  to: 1,
  config: { overshootClamping: true } // Never goes above 1
});

calculateSpringDuration()

Estimates how many frames a spring animation needs to settle within a threshold.
import { calculateSpringDuration } from '@helios-project/core';

const duration = calculateSpringDuration(
  { fps: 30, config: { stiffness: 100, damping: 10 } },
  0.001 // threshold
);

Parameters

options
Omit<SpringOptions, 'frame'>
required
Spring configuration (same as spring() but without frame)
threshold
number
default:"0.001"
Distance from target value to consider the spring “settled”

Returns

number - Estimated duration in frames

Easing functions

Helios includes a comprehensive library of easing functions for use with interpolate() and other animations.
import { Easing } from '@helios-project/core';

Available easing functions

Basic

  • Easing.linear - No easing, linear interpolation
  • Easing.step(steps) - Step function with specified number of steps
  • Easing.bezier(x1, y1, x2, y2) - Custom cubic bezier curve

Polynomial

All polynomial easings have .in, .out, and .inOut variants:
  • Easing.quad - Quadratic (t²)
  • Easing.cubic - Cubic (t³)
  • Easing.quart - Quartic (t⁴)
  • Easing.quint - Quintic (t⁵)

Transcendental

  • Easing.sine - Sinusoidal easing
  • Easing.expo - Exponential easing
  • Easing.circ - Circular easing

Physical

  • Easing.back - Overshoots then returns
  • Easing.elastic - Elastic bounce effect
  • Easing.bounce - Bouncing ball effect

Examples

import { interpolate, Easing } from '@helios-project/core';

// Ease in (slow start)
const x1 = interpolate(frame, [0, 60], [0, 100], {
  easing: Easing.cubic.in
});

// Ease out (slow end)
const x2 = interpolate(frame, [0, 60], [0, 100], {
  easing: Easing.cubic.out
});

// Ease in-out (slow start and end)
const x3 = interpolate(frame, [0, 60], [0, 100], {
  easing: Easing.cubic.inOut
});

// Elastic bounce
const scale = interpolate(frame, [0, 60], [0, 1], {
  easing: Easing.elastic.out
});

// Custom bezier
const custom = interpolate(frame, [0, 60], [0, 1], {
  easing: Easing.bezier(0.68, -0.55, 0.265, 1.55)
});

// Step animation (5 steps)
const stepped = interpolate(frame, [0, 60], [0, 100], {
  easing: Easing.step(5)
});

Common patterns

Typewriter effect

import { interpolate } from '@helios-project/core';

function Typewriter({ text, frame, start, end }) {
  const visibleCount = Math.floor(
    interpolate(frame, [start, end], [0, text.length])
  );
  
  return <div>{text.slice(0, visibleCount)}</div>;
}

Stagger animations

function StaggeredList({ items, frame }) {
  return items.map((item, i) => {
    const delay = i * 10; // 10 frames between each
    const opacity = interpolate(
      frame,
      [delay, delay + 20],
      [0, 1],
      { extrapolateRight: 'clamp' }
    );
    
    return (
      <div key={i} style={{ opacity }}>
        {item}
      </div>
    );
  });
}

Combining helpers

function AnimatedElement({ frame }) {
  // Use interpolate for position
  const x = interpolate(frame, [0, 60], [0, 200]);
  
  // Use spring for scale
  const scale = spring({ frame, fps: 30, from: 0, to: 1 });
  
  // Use easing for rotation
  const rotation = interpolate(
    frame,
    [0, 120],
    [0, 360],
    { easing: Easing.cubic.inOut }
  );
  
  return (
    <div style={{
      transform: `translateX(${x}px) scale(${scale}) rotate(${rotation}deg)`
    }}>
      Content
    </div>
  );
}

Build docs developers (and LLMs) love