timeline

class janim.anims.timeline.Timeline(*args, **kwargs)

Bases: object

Inherit this class and implement the construct() method to implement the logic of building animations

Call build() to get the constructed Timeline object

CONFIG: Config | None = None

Defining this variable in a subclass can serve to set configuration, for example:

class Example(Timeline):
    CONFIG = Config(
        font=['Consolas', 'LXGW WenKai Lite']
    )

    def construct(self) -> None:
        ...

See also: Config

ctx_var: ContextVar = <ContextVar name='Timeline.ctx_var'>
static get_context(raise_exc=True) Timeline | None

Call this method to get the current Timeline object being constructing

class ScheduledTask(at: float, func: Callable, args: list, kwargs: dict)

Bases: object

See schedule()

at: float
func: Callable
args: list
kwargs: dict
class TimeOfCode(time: float, line: int)

Bases: object

Marks the time corresponding to the line number of code execution in construct()

time: float
line: int
class PausePoint(at: 'float', at_previous_frame: 'bool')

Bases: object

at: float
at_previous_frame: bool
class PlayAudioInfo(audio: Audio, range: TimeRange, clip_range: TimeRange)

Bases: object

Parameter information for calling play_audio()

audio: Audio
range: TimeRange
clip_range: TimeRange
class SubtitleInfo(text: str, range: TimeRange, kwargs: dict, subtitle: Text | TypstText)

Bases: object

Parameter information for calling subtitle()

text: str
range: TimeRange
kwargs: dict
subtitle: Text | TypstText
class ExtraRenderGroup(t_range: 'TimeRange', func: 'RenderGroupFn', related_items: 'list[Item] | None')

Bases: object

t_range: TimeRange
func: RenderGroupFn
related_items: list[Item] | None
abstractmethod construct() None

Implement this method to build the animation logic

build_indent_ctx: ContextVar = <ContextVar name='Timeline.build_indent_ctx'>
build(*, quiet=False, hide_subtitles=False, show_debug_notice=False) BuiltTimeline

Build the animation and return it

with_config()

If called for the first time, it will apply the config defined in the Timeline subclass based on the current context and record it

If called subsequently, it will directly set to the recorded value, ensuring consistency across different contexts

schedule(at: float, func: Callable, *args, **kwargs) None

Schedule execution

Calls func when the progress reaches at, can pass *args and **kwargs

schedule_and_detect_changes(at: float, func: Callable, *args, **kwargs) None

Similar to schedule(), but records the state of changed items after calling func

timeout(delay: float, func: Callable, *args, **kwargs) None

Equivalent to schedule(self.current_time + delay, func, *args, **kwargs)

timeout_and_detect_changes(delay: float, func: Callable, *args, **kwargs) None

Similar to timeout(), but records the state of changed items after calling func

forward(dt: float = 1, *, _detect_changes=True, _record_lineno=True)

Advance by dt seconds

forward_to(t: float, *, _detect_changes=True) None

Advance to time t

prepare(*anims: SupportsAnim, at: float = 0, name: str | None = 'prepare', **kwargs) TimeRange
play(*anims: SupportsAnim, name: str | None = 'play', **kwargs) TimeRange
pause_point(*, offset: float = 0, at_previous_frame: bool = True) None

Mark that in the preview interface, execution will pause when reaching the current time point

  • at_previous_frame controls whether to pause at the previous frame (default) or at the current frame

  • offset represents how many seconds to offset, e.g., offset=2 means 2 seconds after the current position

  • In the GUI interface, you can use Ctrl+Left Arrow to quickly move to the previous pause point, and Ctrl+Right Arrow to quickly move to the next one

aas(file_path: str, subtitle: str | Iterable[str], **kwargs) TimeRange

Short form of audio_and_subtitle()

audio_and_subtitle(file_path: str, subtitle: str | Iterable[str], *, clip: tuple[float, float] | None | EllipsisType = Ellipsis, delay: float = 0, mul: float | Iterable[float] | None = None, **subtitle_kwargs) TimeRange

Play audio and display subtitles in the corresponding interval

  • If clip=... (default, ellipsis), it automatically determines the clipping interval, removing leading and trailing silence (you can pass clip=None to disable automatic clipping)

  • If mul is not None, the audio amplitude will be multiplied by this value

play_audio(audio: Audio, *, delay: float = 0, begin: float = 0, end: float = -1, clip: tuple[float, float] | None = None) TimeRange

Play audio at the current position

  • Can specify begin and end to represent the clipping segment

  • Can specify that playback starts delay seconds after the current position

  • If clip is specified, it will override begin and end (clip can be considered a shorthand for both)

Return value represents the playback time range

has_audio() bool

Whether this Timeline itself has playable audio

has_audio_for_all() bool

Considering all child Timelines, whether there is playable audio

subtitle(text: str | Iterable[str], duration: float = 1, *, delay: float = 0, scale: float | Iterable[float] = 0.8, use_typst_text: bool | Iterable[bool] = False, surrounding_color: JAnimColor = BLACK, surrounding_alpha: float = 0.5, font: str | Iterable[str] = [], depth: float = -100000.0, **kwargs) TimeRange
subtitle(text: str | Iterable[str], range: TimeRange, **kwargs) TimeRange

Add subtitle

  • Text can be passed as a list, displayed vertically

  • You can specify that the subtitle appears delay seconds after the current position

  • duration represents the duration

  • scale represents the scaling of text. You can pass a list to specify scaling for each text

  • use_typst_text indicates whether to use TypstText. You can pass a list to specify whether each text uses it

  • Set surrounding_alpha to 0 to disable the background box

Config also provides some configurable parameters:

  • subtitle_font globally configures the font used for subtitles

  • subtitle_to_edge_buff configures the distance from the subtitle to the bottom edge; defaults to DEFAULT_ITEM_TO_EDGE_BUFF

Return value represents the display time range

place_subtitle(subtitle: Text | TypstText, range: TimeRange) None

Called by subtitle() to place subtitles in appropriate positions:

  • For subtitles added in the same batch [a, b], a is placed above b

  • If [a, b] mentioned above still exists and a c is added, then c is placed at the top

has_subtitle() bool
class ItemAppearance(item: Item, aligner: TimeAligner)

Bases: object

Contains objects related to item display

  • self.stack is the AnimStack object

  • self.visiblility is a list storing the time points when items are shown/hidden - Even indices (0, 2, …) represent the time points when display starts, odd indices (1, 3, …) represent the time points when hiding occurs - For example, if the list is [3, 4, 8], it means display at 3s, hide at 4s, and display continuously after 8s - This recording method is the basis for Timeline.is_visible(), Timeline.show(), Timeline.hide() operations

  • self.renderer represents the renderer object being used

is_visible_at(t: float) bool

Whether the item is visible at time t

render(data: Item) None
class ItemAppearancesDict(time_aligner: TimeAligner)

Bases: defaultdict[Item, ItemAppearance]

track(item: Item) None

Causes item to automatically call detect_change() on each forward and play

track_item_and_descendants(item: Item, *, root_only: bool = False) None

Equivalent to calling track() on item and all its descendant items

detect_changes_of_all() None

Check item changes and record them as Display

detect_changes(items: Iterable[Item]) None

Check changes of items in the specified list and record them as Display

(Only checks itself, excluding descendant items)

compute_item(item: T, as_time: float, readonly: bool) T

See compute()

item_current(item: T, *, as_time: float | None = None, root_only: bool = False) T

See current()

is_visible(item: Item) bool

Determine whether a specific item is currently visible

See also: show(), hide()

show(*roots: Item, root_only=False) None

Show item

hide(*roots: Item, root_only=False) None

Hide item

hide_all() None

Hide all items currently displayed

visible_items() list[Item]
add_extra_render_group(t_range: TimeRange, func: RenderGroupFn, related_items: list[Item] | None) None
get_construct_lineno() int | None

Get the current line number being executed in construct()

get_lineno_at_time(time: float)

Get the corresponding line number based on time.

class GuiCommand(global_t: float, text: str, frame: FrameType)

Bases: object

exception GuiCommandInterrupt(command: GuiCommand)

Bases: Exception

debug(item: Item, msg: str | None = None) None

Display the item’s animation stack in the timeline

Tip

A yellow bar displayed in the timeline indicates in which ranges the item is visible

Warning

Some animations are overriding, such as direct data changes (Display) and .anim (MethodTransform). Don’t be confused if you don’t see the expected stack structure

static fmt_time(t: float) str
dbg_time(ext_msg: str = '') None
class janim.anims.timeline.SourceTimeline(*args, **kwargs)

Bases: Timeline

Compared to Timeline, this will display the source code in the background.

source_object() object
build(*, quiet=False, hide_subtitles=False, show_debug_notice=False) BuiltTimeline

Build the animation and return it

class janim.anims.timeline.ListedTimelines(*args, **kwargs)

Bases: Timeline

Specify a group of Timeline implementations and play them in sequence

Example:

class Section0(Timeline):
    def construct(self):
        ...

class Section1(Timeline):
    def construct(self):
        ...

class Section2(Timeline):
    def construct(self):
        ...

class Sections(ListedTimelines):
    includes = [Section1, Section2]
includes: list[type[Timeline]] = []
construct()
class janim.anims.timeline.AboveTimelines(*args, **kwargs)

Bases: ListedTimelines

Play all Timeline implementations previously defined in the same file, in order

Example:

class Section0(Timeline):
    def construct(self):
        ...

class Section1(Timeline):
    def construct(self):
        ...

class Section2(Timeline):
    def construct(self):
        ...

class Sections(AboveTimelines):
    pass

You can additionally use excludes to specify excluded items

Example:

...

class Sections(AboveTimelines):
    excludes = [Section0]
excludes: list[type[Timeline]] = []
construct()
class janim.anims.timeline.BuiltTimeline(timeline: Timeline)

Bases: object

Instance returned after running Timeline.build()

property cfg: Config | ConfigGetter
get_audio_samples_of_frame(fps: float, framerate: int, frame: int, *, count: int = 1) ndarray

Extract the audio stream of a specific frame

current_camera_info(*, as_time: float | None = None) CameraInfo

Get the current CameraInfo information

Here, “current” means the global_t moment from the last call to render_all(); you can also specify it by passing as_time

render_all(ctx: Context, global_t: float, *, camera: Camera | None = None) bool

Render all visible items

capture(global_t: float, *, transparent: bool = True, ctx: Context | None = None) Image
to_item(**kwargs) TimelineItem

Use this method to insert another Timeline into a Timeline

For example:

class Sub1(Timeline):
    def construct(self):
        text = Text('text from Sub1')
        text.points.shift(UP)
        self.play(
            Rotate(text, TAU, about_point=LEFT * 2),
            duration=4
        )


class Sub2(Timeline):
    def construct(self):
        text = Text('text from Sub2')
        text.points.shift(DOWN)
        self.play(
            Rotate(text, TAU, about_point=RIGHT * 2),
            duration=4
        )


class Test(Timeline):
    def construct(self):
        tl1 = Sub1().build().to_item().show()
        tl2 = Sub2().build().to_item().show()
        self.forward_to(tl2.end)

In this example, Sub1 and Sub2 are inserted into Test

Additional parameters:

  • delay: How many seconds to delay before starting playback of this Timeline

  • first_frame_duration: How many seconds the first frame lasts

  • keep_last_frame: Whether to keep displaying the last frame after the Timeline ends

to_playback_control_item(**kwargs) TimelinePlaybackControlItem

Use this method to insert another Timeline into a Timeline

And similar to Video, you can use start, stop, and seek to control playback progress

Example:

class Sub(Timeline):
    def construct(self):
        self.play(
            ItemUpdater(
                None,
                lambda p: Text(f'{p.global_t:.2f}')
            ),
            duration=8
        )


class Test(Timeline):
    def construct(self):
        sub = Sub().build().to_playback_control_item().show()
        sub.start()
        self.forward(2)
        sub.start(speed=0.1)
        self.forward(2)
        sub.seek(0).start(speed=4)
        self.forward(2)

Warning

By default, playback is not started; you need to use start to begin playback

Additional parameters:

  • keep_last_frame: Whether to keep displaying the last frame after the Timeline ends

class janim.anims.timeline.TimelineItem(built: BuiltTimeline, *, delay: float = 0, first_frame_duration: float = 0, keep_last_frame: bool = False, **kwargs)

Bases: Item

See BuiltTimeline.to_item() for details

class TIRenderer

Bases: Renderer

render(item: TimelineItem)
renderer_cls

alias of TIRenderer

start() Self

Start playing the sub-timeline from the current moment, keeping the first frame displayed before this moment

property end: float
class janim.anims.timeline.PlaybackControl(*args, loop: bool = False, **kwargs)

Bases: object

start(*, speed: int = 1) Self
stop() Self
seek(t: float) Self
compute_time(t: float, total: float | None = None) float
class janim.anims.timeline.TimelinePlaybackControlItem(built: BuiltTimeline, *, keep_last_frame: bool = False, **kwargs)

Bases: PlaybackControl, Item

See BuiltTimeline.to_playback_control_item() for details

class TPCIRenderer

Bases: Renderer

render(item: TimelinePlaybackControlItem)
renderer_cls

alias of TPCIRenderer