Skip to content
Feeding a clanker? Grab this page as raw .md

FramePlayer API#

Bases: AnyWidget

Play a sequence of images as an inline, optionally-looping "video".

Hook up any iterable of frames — PIL images, file paths, URLs, bytes, base64 strings, or matplotlib figures (mixed is fine) — and the widget renders the current frame with play/pause/loop controls and a scrubber, so you don't need a second cell that reads a slider value and re-renders.

For long or high-resolution sequences, downsize the frames before passing them in — every frame is base64-inlined into the widget model.

Examples:

import marimo as mo
from PIL import Image
from wigglystuff import FramePlayer

frames = [Image.new("RGB", (128, 128), (i * 8 % 255, 0, 0)) for i in range(30)]
player = mo.ui.anywidget(FramePlayer(frames, interval_ms=80, loop=True))
player

Create a FramePlayer.

Parameters:

Name Type Description Default
frames Iterable[Any]

Iterable of frame sources (PIL Image, path, URL, bytes, base64 string, or matplotlib figure). Must be non-empty.

required
value int

Starting frame index.

0
interval_ms int

Milliseconds between frames while playing.

100
loop bool

Wrap back to the first frame at the end instead of stopping.

True
width int

Display width in pixels (0 = the image's natural width).

0
show_index bool

Show the "current / total" frame readout.

True
**kwargs Any

Forwarded to anywidget.AnyWidget.

{}
Source code in wigglystuff/frame_player.py
def __init__(
    self,
    frames: Iterable[Any],
    value: int = 0,
    interval_ms: int = 100,
    loop: bool = True,
    width: int = 0,
    show_index: bool = True,
    **kwargs: Any,
) -> None:
    """Create a FramePlayer.

    Args:
        frames: Iterable of frame sources (PIL Image, path, URL, bytes,
            base64 string, or matplotlib figure). Must be non-empty.
        value: Starting frame index.
        interval_ms: Milliseconds between frames while playing.
        loop: Wrap back to the first frame at the end instead of stopping.
        width: Display width in pixels (0 = the image's natural width).
        show_index: Show the "current / total" frame readout.
        **kwargs: Forwarded to ``anywidget.AnyWidget``.
    """
    encoded = self._encode_frames(frames)
    if not encoded:
        raise ValueError("frames must contain at least one frame.")
    if interval_ms <= 0:
        raise ValueError("interval_ms must be positive.")
    value = max(0, min(value, len(encoded) - 1))
    super().__init__(
        frames=encoded,
        value=value,
        interval_ms=interval_ms,
        loop=loop,
        width=width,
        show_index=show_index,
        **kwargs,
    )

n_frames property #

n_frames: int

Number of frames currently loaded.

set_frames #

set_frames(frames: Iterable[Any]) -> None

Replace the frame sequence, re-encoding and clamping value.

Source code in wigglystuff/frame_player.py
def set_frames(self, frames: Iterable[Any]) -> None:
    """Replace the frame sequence, re-encoding and clamping ``value``."""
    encoded = self._encode_frames(frames)
    if not encoded:
        raise ValueError("frames must contain at least one frame.")
    self.frames = encoded
    if self.value > len(encoded) - 1:
        self.value = len(encoded) - 1

Synced traitlets#

Traitlet Type Notes
frames list[str] Base64 data URIs, one per frame.
value int Index of the currently displayed frame.
interval_ms int Milliseconds between frames while playing.
playing bool Whether playback is currently running.
loop bool Wrap back to the first frame at the end instead of stopping.
width int Display width in pixels (0 = the image's natural width).
show_index bool Whether to show the "current / total" frame readout.