Rendley docs

Timeline

The Timeline drives the composition. It owns all layers and clips, controls playback, and tracks the current frame. You access it through Engine.getInstance().getTimeline().

Playback

const timeline = Engine.getInstance().getTimeline();

await timeline.play();
timeline.pause();
timeline.stop(); // pauses and moves to time 0
timeline.seek(5.5); // jump to second 5.5

The Engine also exposes shortcuts for the same methods: Engine.getInstance().play(), pause(), stop(), and seek(time).

Runnable example
// Put two shapes on the timeline and start playback from second 1.
const first = await layer.addClip({
  type: "shape",
  shape: "circle",
  startTime: 0,
  duration: 3,
  style: { fillColor: "#6d6ff2", width: 400, height: 400 },
});
first.style.setPosition(960, 540);

const second = await layer.addClip({
  type: "shape",
  shape: "circle",
  startTime: 3,
  duration: 3,
  style: { fillColor: "#FF4D6D", width: 400, height: 400 },
});
second.style.setPosition(960, 540);

const timeline = Engine.getInstance().getTimeline();
timeline.seek(1);
await timeline.play();

Property Keyframes

Clips expose a propertyAnimator for keyframing individual clip properties over local clip time. Use it to animate properties such as position, scale, rotation, or opacity without configuring an animation preset.

Runnable example
// Add a rectangle to animate.
const clip = await layer.addClip({
  type: "shape",
  shape: "rectangle",
  startTime: 0,
  duration: 4,
  style: { fillColor: "#6d6ff2", width: 700, height: 400 },
});

clip.style.setPosition(960, 540);

// Add keyframes in local clip time.
// At second 0, the clip starts shifted left and transparent.
clip.propertyAnimator.addKeyframe("positionX", 0, 560);
clip.propertyAnimator.addKeyframe("alpha", 0, 0);

// At second 1, it reaches its final position and opacity.
clip.propertyAnimator.addKeyframe("positionX", 1, 960);
clip.propertyAnimator.addKeyframe("alpha", 1, 1);

// Add a subtle scale pulse between seconds 1 and 2.
clip.propertyAnimator.addKeyframe("scale", 1, [1, 1]);
clip.propertyAnimator.addKeyframe("scale", 1.5, [1.2, 1.2]);
clip.propertyAnimator.addKeyframe("scale", 2, [1, 1]);

const timeline = Engine.getInstance().getTimeline();
timeline.seek(0);
await timeline.play();

Keyframe times are relative to the clip, not the global timeline. For example, a keyframe at time: 1 plays one second after the clip starts.

Frames Per Second

timeline.setFps(30);
timeline.getFps();
timeline.getFrameDuration(); // returns 1 / fps

The default is 30. Changing the FPS reflows the internal time tracking to the new cadence.

Frame Alignment

The SDK works in seconds on the public API but internally snaps to frames to avoid floating-point drift between preview and render.

import { AlignRoundEnum } from "@rendley/sdk";

const aligned = timeline.alignTime(2.31, AlignRoundEnum.NEAREST); // CEIL | FLOOR | NEAREST
const frameNumber = timeline.getFrameNumberFromTime(2.31);
const frameNumbers = timeline.getFrameNumberFromTimeValues([1.5, 2.5, 3.5]);

Use getFrameNumberFromTimeValues when you have many time values to convert. It is faster than calling getFrameNumberFromTime in a loop.

Creating and Removing Layers

const layer = timeline.createLayer(); // append
const layer = timeline.createLayer({ index: 2 }); // insert at index

timeline.removeLayer(layer.id);

See Layer for layer-level controls.

Looking Up Clips and Layers

timeline.getLayerById(layerId);
timeline.getLayerByClipId(clipId);
timeline.getClipById(clipId);
timeline.getClipsByMediaId(mediaId); // all clips that reference this media
timeline.getClipsBySubtitlesId(subtitlesId);
timeline.getClips(); // every clip across layers

Adjust Layout

adjustClipsLayout walks every layer and pushes overlapping clips to the next available empty space. It is useful after programmatic changes (for example, after calling setPlaybackSpeed which can mutate clip duration):

timeline.adjustClipsLayout();

The method returns true if it had to move anything.

Splitting and Trimming Clips

Two common edits: split a clip into two pieces at a point in time, and trim the ends of a clip.

Split at Time

layer.splitClip(clipId, time) cuts the clip at a timeline time (not a source time). It keeps the left piece in place and returns the newly created right piece.

Runnable example
const clip = await layer.addClip({
  type: "shape",
  shape: "rectangle",
  startTime: 0,
  duration: 6,
  style: { fillColor: "#6d6ff2", width: 900, height: 500 },
});
clip.style.setPosition(960, 540);

// Cut at second 3, produces two clips on the same layer, butted end to end.
const rightHalf = await layer.splitClip(clip.getId(), 3);

// Recolor the right half so the split is visible.
if (rightHalf && rightHalf.getType() === "shape") {
  (rightHalf as any).style.setFillColor("#FF4D6D");
}

Trim the Ends

setLeftTrim(seconds) hides content from the start of the clip. setRightTrim(seconds) hides content from the end. Both are in seconds, and both clamp to the clip’s real media duration.

clip.setLeftTrim(1.0); // skip the first second
clip.setRightTrim(0.5); // skip the last half second

const visible = clip.getTrimmedDuration(); // returns duration - leftTrim - rightTrim

For a video clip, trimming changes the visible range without re-encoding, playback and export seek into the source.

Trimming values are positive towards the inside the clip (both setLeftTrim(1) and setRightTrim(1) reduces the duration of the Clip by 1 second)

Moving Clips to Another Layer

layer.moveClipToLayer(clipId, destinationLayerId);

The destination layer reflows to fit (subject to adjustLayout). Useful for implementing drag-and-drop between tracks.

Duration

const end = timeline.getFitDuration(); // right-most clip end time across visible layers

Use this for trimming the preview bar or for configuring export ranges.

Volume

The timeline has a master volume that multiplies the volume of every audio and video clip:

timeline.setVolume(0.5);
timeline.getVolume();

Extract Audio

Take the audio track out of a video clip and get a standalone AudioClip on a new layer:

const audioClip = timeline.extractAudio(videoClip);

The original video clip is muted automatically. The returned audio clip is added to a new layer and can be moved, trimmed, or processed independently.

Subtitles Across Clips

Attach the same subtitles to multiple clips in a single call:

timeline.setSubtitles(subtitlesId, 0, [clipIdA, clipIdB]);

Omit the clipIds argument to apply subtitles to every clip in the timeline.

Partial Deserialization

loadSerializedData loads timeline state on top of the current Engine without resetting the rest of the project:

await timeline.loadSerializedData(serializedTimeline);

This is useful when you want to swap the composition but keep the Library, display, and settings intact.

Reset

To clear the timeline without affecting the Library or Display:

timeline.reset();

All layers, clips, and transitions are removed.