MLP209: front-loaded dynamic object re-rasterizes a large static suffix¶
qual reports MLP209 when an animated, foreground, or
updater-bearing object sits near the front of Cairo's effective
display order — computed from the family flatten, the z_index stable
sort, and the foreground list, never from root add order alone — and a
provably large static suffix behind it is re-rasterized every frame of
the play.
- Default severity:
info(advisory: reordering changes what draws over what) - Minimum confidence:
medium(emitted athighwhen the play is on every path and the suffix is exact) - Implementation phase:
3 - Profiles: Cairo only (
applicable_profilesis restricted to the active Cairo profiles) - Fix: none
Threshold (documented constant in rules/performance/display_order.rs):
MLP209_STATIC_SUFFIX_GATE = N_moving_suffix >= 8— at least 8 display-list members after the first mover must be provably static (no animation target, no foreground promotion, no family updater anywhere in a covering mover's family). Suffix members that are themselves moving re-rasterize regardless of order, so they never count toward the gate — a suffix that is entirely moving stays silent.
Quantification discipline (binding DESIGN 7.3 prose): the position and
member count are reported only when the display order is Known and
the moving-suffix bounds are exact. An unknown z_index (a non-literal
set_z_index, an unknown mutation) poisons the order and silences the
rule — no number is ever produced from an unknown order.
Wrong¶
class Demo(Scene):
def construct(self):
background = Square()
panel = VGroup(Dot(), Dot(), Dot(), Dot(), Dot(), Dot(), Dot(), Dot())
self.add(background, panel)
background.add_updater(drift) # front member now moves
self.wait(2) # panel re-rasterized every frame
Right¶
class Demo(Scene):
def construct(self):
panel = VGroup(Dot(), Dot(), Dot(), Dot(), Dot(), Dot(), Dot(), Dot())
background = Square()
self.add(panel, background) # dynamic object drawn last
background.add_updater(drift)
self.wait(2) # static panel rasterized once
If the background must draw first, background.set_z_index(-1) with the
add order reversed keeps the stacking while the static run stays
together — verify the visual stacking, since the display order is part
of the picture.