Skip to content

MLP220: Unbounded TracedPath alive over a long span

qual reports MLP220 when a TracedPath constructed without dissipating_time (or with a literal None) provably stays in the scene family across a long span of plays: the path appends the traced point every frame and never discards history, so its geometry grows O(F) and rasterizing the accumulated path across the run approaches O(F²).

  • Default severity: warning
  • Minimum confidence: high
  • Implementation phase: 3
  • Fix: none
  • Supersedes MLP204 / MLP211 on the same span (DESIGN §7.3)

Threshold (documented constant in rules/performance/traced_path.rs): MLP220_LONG_SPAN_SECONDS = 5.0 — the provable lower bound on the alive span (literal durations of plays where the path is definitely in the scene family and updating: play calls and provably dynamic waits, excluding plays that animate the path itself, whose updaters are suspended).

TracedPath itself is never banned: an unbounded trace is a legitimate effect, and the diagnostic says so. Evidence includes the alive span, the per-profile frame/point estimate when durations are literal, and the growth orders; unknown durations stay unquantified. Branch-dependent membership (Maybe) silences the rule.

Wrong

class Demo(Scene):
    def construct(self):
        dot = Dot()
        trace = TracedPath(dot.get_center)
        self.add(dot, trace)
        self.play(dot.animate.shift(RIGHT), run_time=4)
        self.play(dot.animate.shift(UP), run_time=3)
class Demo(Scene):
    def construct(self):
        dot = Dot()
        trace = TracedPath(dot.get_center, dissipating_time=0.5)
        self.add(dot, trace)
        self.play(dot.animate.shift(RIGHT), run_time=4)
        self.play(dot.animate.shift(UP), run_time=3)