Documentation
    Preparing search index...

    Class Timeline

    §16's timeline.

    elapsed  0 ─────── d ─────── 2d ─────── 3d      (loop(3), monotonic)
    local    0 ─── d   0 ─── d   0 ─── d            (what children see)
    

    Timeline.localTime is a position inside one iteration and is what children are mapped from; elapsed is total played time and is what marker bookkeeping runs in, because it only ever moves forward during forward playback. Looping then needs no special case: a marker at local time m simply occurs at m, m + d, m + 2d, … and the half-open crossing rule fires each of those exactly once.

    A child placed at s with total duration w is evaluated at clamp(localTime - s, 0, w):

    localTime:   0        s            s + w        d
                 │ start  │ ─ mapped ─ │  end pose  │
    

    Outside its window a child holds a boundary pose — its start pose before, its end pose after — which is what makes the whole timeline a pure function of time. The consequence is worth stating: a timeline keeps writing its children's properties for its entire duration, so a finished child still owns its property until the timeline stops. That is the point; anything else would make scrubbing backwards impossible.

    Index
    • get duration(): number

      Length of one iteration in seconds: the largest of every child's at + totalDuration and every marker's time, or 0 when empty.

      Labels do not extend the duration. A label names a time; it is a bookmark, not content, and addLabel("end", 30) on a two-second timeline describes a place, not two extra minutes of nothing. Markers do extend it, because a marker is authored content that must be reachable by playback.

      Infinity when a child never ends (tween.repeat(Infinity) or a nested loop(Infinity)), in which case the timeline never finishes either.

      Computed live while "idle" — children may still be configured — and frozen at Timeline.play, which is also when Timeline.at stops being legal.

      Returns number

    • get elapsedTime(): number

      Total played time in seconds, across loop iterations.

      Returns number

    • get finished(): boolean

      Whether playback has reached its end.

      A playback fact, not a time fact: Timeline.seek never sets or clears it, exactly as on a tween, so scrubbing a finished timeline inspects values without pretending it is running again.

      Returns boolean

    • get iteration(): number

      Zero-based index of the loop iteration currently playing.

      Returns number

    • get localTime(): number

      Position inside the current iteration, in seconds.

      Returns number

    • get loopCount(): number

      Total iterations set by Timeline.loop; 1 by default.

      Returns number

    • get playbackSpeed(): number

      The Timeline.speed multiplier.

      Returns number

    • get reversed(): boolean

      Whether Timeline.reverse put playback into reverse.

      Returns boolean

    • get totalDuration(): number

      duration × loopCount — the elapsed time at which playback finishes. Infinity for loop(Infinity), and 0 for an empty timeline (where 0 × Infinity would otherwise be NaN).

      Returns number

    • Names a time on the axis (§16: labels), for Timeline.at and Timeline.seek.

      Names are unique: redefining one throws rather than silently moving every entry that was placed by name.

      Parameters

      • name: string
      • timeSeconds: number

      Returns this

      FourError INVALID_APPLICATION_STATE — called after Timeline.play; the name is empty or already defined; or the time is negative or non-finite.

    • Advances playback by deltaSeconds × speed and writes the resulting pose. Called by the fixed-step AnimationSystem (plan P4-1); a timeline never advances itself and never reads a clock (§33).

      Markers in the crossed range fire, in time order, once each — including at exactly the end of the range and excluding exactly its start, so consecutive advances neither miss nor repeat one. Crossing an iteration boundary fires that iteration's remaining markers, re-arms every marker, and continues into the next iteration, so a single large delta over a looping timeline fires each marker once per iteration it spans.

      A no-op unless the timeline is "running" and unfinished.

      Parameters

      • deltaSeconds: number

      Returns this

      FourError INVALID_APPLICATION_STATE — the delta is negative or non-finite.

    • Places an entry on the axis at at seconds, or at a label's time when at is a string (§16: labels).

      The entry is one of:

      • a Tween, which must be unplayed — the timeline owns its playback and plays it at Timeline.play, so the §16 conflict registry claims happen there, in at() insertion order;
      • a Timeline, nested; the parent drives it and it must likewise be unplayed;
      • a callback, which is an event marker (§16). options configures it.
      timeline
      .addLabel("impact", 1.2)
      .at(0, tween(node.position, { x: 5 }, 0.8))
      .at("impact", () => spawnDust(), { replayOnSeek: true });

      Parameters

      Returns this

      FourError INVALID_APPLICATION_STATE — called after Timeline.play; the time is negative or non-finite; the label is unknown; the child has already been played or is already on this timeline; the entry would nest this timeline inside itself; or options is given for something that is not a marker.

    • Whether Timeline.addLabel defined name.

      Parameters

      • name: string

      Returns boolean

    • The time in seconds that name was defined at.

      Parameters

      • name: string

      Returns number

      FourError INVALID_APPLICATION_STATE — the label is unknown.

    • Number of total iterations: loop(1) is the default single pass, loop(3) plays the whole timeline three times, loop(Infinity) never ends.

      Deliberately not Tween.repeat's "additional cycles" counting: repeat and loop are different words and a reader who has to guess is a reader who will guess wrong. Markers re-arm on every wrap, so a marker on a loop(3) timeline fires three times.

      Parameters

      • count: number

      Returns this

      FourError INVALID_APPLICATION_STATE — not an integer >= 1 or Infinity.

    • Suspends advancing. A no-op unless the timeline is "running".

      Returns this

    • Starts playback at local time 0: freezes the duration, sorts the markers, plays every child in at() insertion order (which is where §16's property claims and their conflict warnings happen), and writes the pose at time 0.

      No marker fires here, not even one at time 0 — the cursor starts below zero and the first Timeline.advance crosses it. advance(0) is enough.

      A no-op on a timeline that is not "idle", exactly as on a tween: restarting would have to re-capture every child's start values from wherever the properties happen to sit.

      Returns this

    • Resumes advancing. A no-op unless the timeline is "paused".

      Returns this

    • Plays toward time 0 (§16: reversing). reverse(false) restores forward playback, mirroring Tween.yoyo(enabled)'s shape.

      Reverse traverses loop iterations backwards and finishes at elapsed time 0. Markers never fire while moving backwards: §16 defines a crossing as a forward event, and clip.ts makes the same call for a reversed range.

      Parameters

      • Optionalreversed: boolean

      Returns this

    • §16's scrubbing call: Timeline.seek restricted to a time in seconds.

      An alias, deliberately — §16 gives seeking and scrubbing identical marker semantics ("seek and scrubbing suppress them by default"), so a scrub that behaved differently would be inventing a third policy. It exists because a scrub bar reads better as scrub(t) than as seek(t), and because taking only a number keeps a label out of a slider's hands.

      Parameters

      • timeSeconds: number

      Returns this

    • Positions the timeline at a local time (or a label's time) and writes the pose for it — §16's scrubbing, and the positioning half of a snapshot restore (§34).

      Pure: seeking twice to the same time writes identical values, and seeking backwards is as valid as forwards. Neither Timeline.state nor Timeline.finished changes, so a seek is an evaluation and never a playback decision.

      Markers are suppressed, except that a { replayOnSeek: true } marker fires when the seek crosses it forwards (§16). A backward seek fires nothing and re-arms every marker it rewound past, so replaying forwards crosses them again — which is exactly what "restoring a mid-timeline snapshot positions playback without re-firing markers already crossed" needs.

      The time is clamped to [0, duration] — one iteration. Seeking rewinds a looping timeline to its first iteration: loop iterations are a fact about playback history, and a position on the axis cannot name one.

      Parameters

      • to: string | number

      Returns this

      FourError INVALID_APPLICATION_STATE — the timeline has never been played, the label is unknown, or the time is negative or non-finite.

    • Multiplier applied to every Timeline.advance delta, and to the delta a parent timeline maps into this one when nested.

      Legal at any time, including mid-playback — §16 lists playback speed as a playback control, not a build-time property. Must be positive and finite; reverse playback is Timeline.reverse, not a negative speed, so that "the advance that finishes playback" stays unambiguous.

      Parameters

      • multiplier: number

      Returns this

      FourError INVALID_APPLICATION_STATE — not finite and > 0.

    • Stops playback and every child, releasing their §16 property claims and leaving all animated values exactly where the last write put them.

      A stopped timeline writes nothing further: its children ignore writes too, so even a later Timeline.seek is inert. A no-op while "idle".

      Returns this