Skip to content

MLP222: image caught in Cairo's moving suffix

qual reports MLP222 when an ImageMobject sits at or after the first moving member of Cairo's effective display order during a rendering play: Cairo re-rasterizes every member from the first moving one onward each frame and composites it over the full frame, so the image pays per-pixel raster work every frame even when it never changes (DESIGN 3.4 / 4.3 Cairo stage).

  • Default severity: warning
  • Minimum confidence: high
  • Implementation phase: 3
  • Profiles: Cairo only (applicable_profiles restricted; OpenGL's PIL/full-frame costs are never transferred, DESIGN 7.3)
  • Fix: none

Threshold (documented constant in rules/performance/display_order.rs):

  • MLP222_MIN_PIXEL_AREA = 1280 × 720 — every active Cairo profile must rasterize at least this frame area (the DESIGN 7.3 screen-area gate; the image's own pixel area has no static fact, so its size is described qualitatively and never quantified).

The rule requires a Known display order with an exact first-moving index (an unknown z_index silences it) and skips plays whose animations target the image itself — an image being introduced or transformed moves because that is the play's purpose. Updater-driven or foreground motion, and being caught behind another mover, count.

Wrong

class Demo(Scene):
    def construct(self):
        mover = Square()
        photo = ImageMobject("photo.png")
        self.add(mover, photo)                    # photo drawn after the mover
        self.play(mover.animate.shift(RIGHT))     # photo re-rasterized per frame
class Demo(Scene):
    def construct(self):
        photo = ImageMobject("photo.png")
        mover = Square()
        self.add(photo, mover)                    # photo stays in the static base
        self.play(mover.animate.shift(RIGHT))