Control playback

Drive a dotLottie animation from C with a tick loop, control speed, direction and looping, jump to frames, and play segments or named markers.

Playback in the native runtime is driven by you. There is no internal timer — you decide when the animation advances and when it draws, which makes it straightforward to integrate with an existing game loop, render loop, or frame callback.

The tick loop

dotlottie_tick() advances the animation by an elapsed time and redraws only if the visible frame changed. It reports whether it drew, so you can skip presenting a frame identical to the last one.

bool rendered = false;

dotlottie_tick(player, dt, &rendered);

if (rendered) {
  present(buffer, width, height);
}
dt is in seconds, not milliseconds

Pass the time elapsed since your previous tick in seconds. A 60 fps frame is 0.0167, not 16.7. The example in the generated dotlottie_player.h derives dt from a millisecond clock without converting, which runs the animation 1000× too fast — if your timer reports milliseconds, divide by 1000.

A complete loop using a monotonic clock:

#include <time.h>

static double now_seconds(void) {
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  return ts.tv_sec + ts.tv_nsec / 1e9;
}

double last = now_seconds();

for (;;) {
  double current = now_seconds();
  float dt = (float)(current - last);
  last = current;

  bool rendered = false;
  dotlottie_tick(player, dt, &rendered);
  if (rendered) {
    present(buffer, width, height);
  }
}

Passing a dt of 0.0 renders nothing new, and negative values are clamped to zero. Pass NULL for rendered if you always present regardless.

Redrawing without advancing

dotlottie_render() draws the current frame without moving time forward. Use it after changing something that affects appearance but not position — a theme, a slot, the background, the layout — or to repaint a paused animation after a resize.

dotlottie_set_frame(player, 42.0f);
dotlottie_render(player);

Transport controls

dotlottie_play(player);
dotlottie_pause(player);
dotlottie_stop(player);

dotlottie_pause() freezes at the current frame; dotlottie_stop() also resets to the beginning. Enabling autoplay before loading starts playback automatically:

dotlottie_set_autoplay(player, true);

Read the current state with dotlottie_status():

StatusNumericMeaning
Idle0Created, nothing loaded yet
Playing1Advancing on each tick
Paused2Holding the current frame
Stopped3Reset to the start
Tweening4Interpolating between two frames

Speed and direction

dotlottie_set_speed(player, 2.0f);      /* double speed */
dotlottie_set_mode(player, Reverse);
ModeNumericBehavior
Forward0Start to end
Reverse1End to start
Bounce2Forward, then back, repeating
ReverseBounce3Backward, then forward, repeating

Speed is a plain multiplier: 0.5 is half speed, 2.0 is double. A speed of 0.0 stops the animation advancing while leaving it in the Playing state.

Looping

dotlottie_set_loop(player, true);
dotlottie_set_loop_count(player, 3);    /* 0 means loop forever */

dotlottie_set_loop_count() only applies when looping is enabled. Track progress with:

uint32_t completed = 0;
dotlottie_get_current_loop_count(player, &completed);

bool finished = dotlottie_is_complete(player);

With infinite looping, dotlottie_is_complete() never returns true.

Frames and timing

float total = 0.0f, duration = 0.0f, current = 0.0f;

dotlottie_get_total_frames(player, &total);
dotlottie_get_duration(player, &duration);     /* seconds */
dotlottie_get_current_frame(player, &current);

Jump directly to a frame — fractional values are allowed, which is what makes scrubbing smooth:

dotlottie_set_frame(player, total * 0.75f);
dotlottie_render(player);

Frames outside the playable range are rejected with InvalidParameter.

Frame interpolation

By default the player renders at sub-frame positions, producing smoother motion at high refresh rates. Turning it off snaps to whole frames and reduces rendering work:

dotlottie_set_use_frame_interpolation(player, false);

Segments

A segment restricts playback to a frame range. Pass a two-element array of [start, end]:

float segment[2] = { 30.0f, 90.0f };
dotlottie_set_segment(player, &segment);

Clear it by passing NULL to return to the full animation:

dotlottie_set_segment(player, NULL);

Read the active segment back into an array you own:

float current_segment[2];
if (dotlottie_get_segment(player, &current_segment) == DOTLOTTIE_SUCCESS) {
  printf("playing %.0f to %.0f\n", current_segment[0], current_segment[1]);
}

This returns InvalidParameter when no segment is set.

Markers

Markers are named frame ranges defined in the animation, and they are usually a better choice than hardcoded frame numbers — the designer can move them without you changing code.

dotlottie_set_marker(player, "walk-cycle");

Setting a marker applies its range as the current segment. Pass NULL to clear it.

Enumerate the markers a file defines:

uint32_t count = 0;
dotlottie_get_markers_count(player, &count);

for (uint32_t i = 0; i < count; i++) {
  const char *name = NULL;
  float start = 0.0f, end = 0.0f;

  if (dotlottie_get_marker(player, i, &name, &start, &end) == DOTLOTTIE_SUCCESS) {
    printf("%s: %.0f to %.0f\n", name, start, end);
  }
}

name points into memory the library owns — do not free it. Pass NULL for start or end if you only want the name.

To read the marker currently in effect, use the two-call string pattern:

size_t size = 0;
if (dotlottie_get_active_marker(player, NULL, &size) == DOTLOTTIE_SUCCESS) {
  char *active = malloc(size);
  dotlottie_get_active_marker(player, active, NULL);
  /* ... */
  free(active);
}

Background color

dotlottie_set_background(player, 255, 255, 255, 255);   /* opaque white */
dotlottie_set_background(player, 0, 0, 0, 0);           /* transparent */

Channels are 8-bit 0255. Note that colors in the slot API use floats from 0.0 to 1.0 instead.

Audio

For animations with embedded audio, built with the audio feature:

dotlottie_set_audio_volume(player, 0.5f);   /* 0.0 silent to 1.0 full */

Both audio functions return FeatureNotEnabled in a build without the feature. On Android, call dotlottie_init_android() with your JavaVM and context once before loading an animation with audio.

Learn more

Last updated: August 13, 2026 at 9:17 AMEdit this page