AnimationTimeline

Qualified name: algan.animation\_timeline.timeline.AnimationTimeline

class AnimationTimeline[source]

Bases: object

Methods

add_mob_attr

begin_updater_dependency_trace

Trace Mob state read or written by event until restored.

begin_updater_write_capture

Capture attribute writes made by one updater during replay.

capture_updater_write

Save one replayed write when its updater is being finalized.

clear_buffers

enable_segment_windows

Opt attr_name into segment-window description.

end_updater

end_updater_dependency_trace

end_updater_write_capture

get_attr

get_inds

get_lifespan

The Lifespan of the mob with the given id, created on first access (start = end = "never").

get_timeline_inds

is_replaying

Whether frames are currently being materialized from the timeline.

modify_attribute

modify_attribute_and_record

note_hierarchy_change

Warn if parent's children just changed underneath a live updater.

note_replay_born_mob

Mark mob_id as a Mob that a replayed updater has just built.

peek_replay_inds

Rows a read must use while replaying one function.

preserving_authoring_state

Render frames without leaving derived state on the timeline.

record_function

record_updater

Register an updater starting at the context's current time and lasting until end_updater() (or forever).

register_despawn

register_migrated_edit

Register an edit created by a historical-topology migration.

register_spawn

register_updater_history_split

Teach persistent updaters about rows handed to historical clones.

release_wide_windows

Drop the materialized windows of the wide attributes.

replay_inds

Return the next recorded row set while replaying one function.

segment_window_for

The current batch's SegmentWindow for one mob's rows of attr_name, or None when the window was materialized densely.

set_active_edit_event

Set the function application that subsequently recorded attribute edits are attributed to, returning the previous one (so callers can restore it).

set_state_to_times

Materialize animated state at times.

trace_updater_mob_access

Record one updater Mob access and materialize newly seen rows.

begin_updater_dependency_trace(event)[source]

Trace Mob state read or written by event until restored.

begin_updater_write_capture(event)[source]

Capture attribute writes made by one updater during replay.

capture_updater_write(attr_name, indexes, value)[source]

Save one replayed write when its updater is being finalized.

enable_segment_windows(attr_name)[source]

Opt attr_name into segment-window description.

Called by the attribute’s owner (Surface.color_texture’s setter) because eligibility is a property of how the attribute is consumed: the primitive build must know how to sample endpoint states, which only the texture path does. Idempotent.

get_lifespan(mob_id)[source]

The Lifespan of the mob with the given id, created on first access (start = end = “never”).

is_replaying()[source]

Whether frames are currently being materialized from the timeline.

True inside set_state_to_times(), which re-executes recorded animations and updaters to rebuild the state of a batch of frames. Authoring is over by then, so anything an updater does here must not change the Scene: see _discard_replay_born_mobs().

Return type:

bool

note_hierarchy_change(parent)[source]

Warn if parent’s children just changed underneath a live updater.

A recorded animation stores the rows it resolved (modify_attribute_and_record()), and replay hands them straight back (replay_inds()), so re-parenting after the fact cannot touch it. The updater loop in set_state_to_times() sets no replay event, so every write inside an updater re-resolves its rows from the hierarchy as it stands when the frames are materialized – which is the hierarchy at the end of the script, not the one in force at the frame being drawn. Editing a subtree a live updater addresses therefore rewrites frames that updater already covered, including frames before the edit.

Nothing here changes what is rendered. It says so at the line that did it, while the script is still being authored and the fix is one move of an add_updater / remove_updater pair.

note_replay_born_mob(mob_id)[source]

Mark mob_id as a Mob that a replayed updater has just built.

peek_replay_inds(attr_name, mob_id, include_descendants)[source]

Rows a read must use while replaying one function.

A replayed function has to read the same rows it will write, or the value it computes is indexed differently from the buffer slots it lands in. replay_inds() only answers for the edit at the cursor, which is right for writes – they consume the recorded edits in order – but wrong for reads, because a function need not read its attributes in the order it writes them. _apply_basis_change() reads the recursive basis before writing the recursive location, so an at-the-cursor match misses and the read silently falls back to the current hierarchy’s rows.

That fallback is only harmless while the two agree. They stop agreeing as soon as anything reallocates a descendant’s rows after the function was recorded – detach_history (and so every wave_color() auto-resolution restore) hands the old rows to a clone and appends fresh ones at the end of the buffer, which reorders the sorted descendant union. The read then returns some other Mob’s values, and the write scatters them across unrelated rows.

So search forward from the cursor for the edit this read pairs with, without consuming it. Returns None when the function records no matching write, in which case the caller’s live-topology rows are the correct answer.

preserving_authoring_state(preserve_replay_resolution=True)[source]

Render frames without leaving derived state on the timeline.

Materializing frames resolves replay windows (_resolve_replay_windows()), which freezes every edit’s and event’s context-rescaled end time into a plain replay_end float. That is correct once authoring is finished, but a render started from inside an unfinished context bakes in timestamps the enclosing contexts have not rescaled yet (a runtime rescales its block retroactively, on exit). Nothing invalidates those floats afterwards – only recording a new edit does – so the stale, too-early ends survive into the next render, where AttributeTimeline.prepare_for_queries() uses them verbatim as edit timestamps and the affected animations stop advancing early.

Every render that leaves the Scene re-renderable wraps itself in this: save_frame(), show_frame(), and save_video() with reset=False. The frames come out of the timeline as it stands, and the Scene carries nothing away from the render, so authoring can continue and render again – including from inside a block that has not finished yet. Lifespans created for the transient mobs a render builds are dropped for the same reason.

record_updater(function, caller, args, kwargs, animation_context)[source]

Register an updater starting at the context’s current time and lasting until end_updater() (or forever). Returns its id.

register_migrated_edit(attr_name, attr_timeline, source_edit, migrated_edit)[source]

Register an edit created by a historical-topology migration.

Surface resolution changes can split an already-recorded edit and add a replacement carrying the same execution sequence. That is the only path that inserts into (rather than appends to) global edit order, so it marks the order dirty and invalidates a resolved checkpoint only when the changed source lies inside that checkpoint.

register_updater_history_split(descendant_map)[source]

Teach persistent updaters about rows handed to historical clones.

release_wide_windows()[source]

Drop the materialized windows of the wide attributes.

A window materialized on the render device (see _wide_attr_materialize_device()) is a whole image per frame of the batch, and nothing reads it once the batch’s primitives are built: the primitive holds its own copy (the legacy premultiply’s clone, or under texture_opacity_in_kernel a one-frame clone of a collapsed window – an UNCOLLAPSED window is deliberately aliased there, so for an animating texture this release only drops the timeline’s reference and the memory follows the primitive’s lifetime instead), the merge decodes that into the buffer the arena is filled from, and the next batch’s preparation replaces the window outright. Left in place it would sit beside the next batch’s window while this one renders – two batches of texture frames on the device for one batch of pixels. The narrow attributes are untouched: their windows are small, and the render thread still reads camera and light state from them.

replay_inds(attr_name, mob_id, include_descendants, consume=False)[source]

Return the next recorded row set while replaying one function.

segment_window_for(attr_name, mob_id)[source]

The current batch’s SegmentWindow for one mob’s rows of attr_name, or None when the window was materialized densely. Valid between one set_state_to_times() and the next.

set_active_edit_event(event)[source]

Set the function application that subsequently recorded attribute edits are attributed to, returning the previous one (so callers can restore it).

set_state_to_times(times, active_mobs=None)[source]

Materialize animated state at times.

active_mobs is the render window’s conservative actor working set. When supplied, built-in animations query only rows reachable from that set while keeping the full global-row buffer layout used by replay. Omitting it preserves the original all-row behavior for public callers.

Replay runs inside a non-recording context, because it calls each recorded function’s undecorated body: the record_funcs=False wrap that animated_function normally applies is absent, so a recorded function whose body calls another animated function (Cylinder.set_start_point -> _move_between_points -> move_to) would record a new event on every replay – growing the timeline without bound as batches are prepared, and re-resolving replay windows every time. A render never saw this because its batch loop runs inside the same context (_batch_prep_context()); doing it here means every caller is safe, including the benchmarks and probes that drive prep directly.

The context matches the render’s exactly, so entering it inside a render is inert – the values are already set and inherited.

trace_updater_mob_access(mob, include_descendants=False)[source]

Record one updater Mob access and materialize newly seen rows.

The initial updater invocation records the common dependency set at authoring time. The same trace remains active during materialization, so time-dependent branches can safely discover extra Mobs on demand.