Skip to content

Animations

Animations in iLoveVideoEditor are keyframe-based. Each animation targets a single property and runs between keyframes expressed in source seconds.

You can also build and preview animations visually in the Studio without writing any code.

Animation model

ts
type Animation = {
  id: string;
  property: string;
  keyframes: Keyframe[];
  easing?: Easing;
};

type Keyframe = {
  time: number;   // source seconds
  value: unknown;
  easing?: Easing;
};

Easing can be one of:

  • step — hold value until next keyframe
  • linear — constant speed
  • easeIn — accelerate
  • easeOut — decelerate
  • easeInOut — slow at both ends

Using animate()

The fluent API hides the raw keyframe structure. layer.animate(from, to, options) creates two keyframes at time: 0 and time: duration.

ts
bg.animate(
  { opacity: 0 },
  { opacity: 1 },
  { duration: '1s', easing: 'easeOut', wait: false },
);
OptionDescription
durationLength of the animation (any Time format)
easingDefault easing between the two keyframes
waitIf false, the flow pointer continues immediately

Chaining animations

Multiple .animate() calls on the same layer produce separate Animation entries.

ts
const text = $.addText({ text: 'Bounce', fontSize: 6 });

text.animate({ position: [0.5, 0.4] }, { position: [0.5, 0.6] }, { duration: '1s', wait: false });
text.animate({ position: [0.5, 0.6] }, { position: [0.5, 0.4] }, { duration: '1s', wait: false });

Parallel animations

Run unrelated animations at the same time:

ts
$.parallel([
  () => { text.animate({ opacity: 0 }, { opacity: 1 }, { duration: '1s' }); },
  () => { bg.animate({ scale: 1 }, { scale: 1.1 }, { duration: '1s' }); },
]);

Animating multiple properties

from and to can contain any number of properties:

ts
text.animate(
  { opacity: 0, scale: 0.8, rotation: -10 },
  { opacity: 1, scale: 1, rotation: 0 },
  { duration: '800ms', easing: 'easeOut' },
);

Animating effect parameters

Use dot-path notation to animate the parameter of an effect declared on the layer:

ts
$.addText(
  {
    text: 'Pulse',
    effects: [{ effect: 'glow', params: { intensity: 0, radius: 1, color: '#ff5a1f' } }],
  },
  { sourceDuration: 5 },
).animate(
  { 'effects.glow.intensity': 0 },
  { 'effects.glow.intensity': 1.5 },
  { duration: '1s', wait: false, easing: 'easeOut' },
);

The path is effects.<effectName>.<param>. It always targets the first effect with that name on the layer.

Manual keyframes

When building raw VideoJSON, you can attach animations directly:

json
{
  "type": "text",
  "animations": [
    {
      "id": "anim-1",
      "property": "opacity",
      "keyframes": [
        { "time": 0, "value": 0 },
        { "time": 1, "value": 1, "easing": "easeOut" }
      ]
    }
  ]
}

Time base

Keyframe time is measured in source seconds, not timeline seconds. For non-media layers this is the elapsed time since the layer started. For media layers, it is the absolute time inside the source clip.

If you change speed, the keyframe timing is stretched automatically.

Released under the MIT License.