playTimeline function

Playable playTimeline(
  1. TimelineExpr expr, {
  2. Map<AnimateGroup, BoundGroup>? into,
})

An arrangement as something that plays.

Nothing is resolved here: a placed group IS the group, and a group holds the node it animates. Binding is building the tree, which is why a compiled motion needs no document and no scene to play — it hands its own timeline over.

into caches one BoundGroup per group, so a group placed twice writes through one writer rather than two that fight.

Implementation

Playable playTimeline(
  TimelineExpr expr, {
  Map<AnimateGroup, BoundGroup>? into,
}) {
  var bound = into ?? <AnimateGroup, BoundGroup>{};
  Playable build(TimelineExpr e) => switch (e) {
    AnimateGroup g => bound.putIfAbsent(g, () => BoundGroup._(g)),
    ParExpr p => _Par([for (var c in p.children) build(c)]),
    SeqExpr s => _Seq([for (var c in s.children) build(c)]),
    AtExpr a => _At(a.offset, build(a.child)),
    SpeedExpr s => _Speed(s.factor, build(s.child)),
    RepeatExpr r => _Repeat(r.times, build(r.child)),
  };
  return build(expr);
}