diff --git a/crates/render/src/lib.rs b/crates/render/src/lib.rs
--- a/crates/render/src/lib.rs
+++ b/crates/render/src/lib.rs
@@ -267,6 +267,7 @@ impl Default for RenderOpts<'_> {
     }
 }
 
+#[derive(Clone)]
 struct SlideFields {
     num: u32,
     /// Text for every date field instead of the date ([`RenderOpts::date_text`]).
@@ -667,6 +668,10 @@ impl Renderer {
 
     /// Background plus the master and layout graphics the slide shows.
     fn backdrop(&mut self, ctx: &mut RenderContext, f: &Frame, rctx: &Ctx, slide: &Slide, view: Affine) {
+        // Backdrop graphics never take shape states: their ids may clash with the slide's shapes.
+        let bopts = RenderOpts { state: None, date_text: f.opts.date_text.clone(), ..*f.opts };
+        let bf = Frame { pres: f.pres, opts: &bopts, fields: f.fields.clone() };
+        let f = &bf;
         self.background(ctx, f, rctx, Some(slide), view);
         let (show_layout, show_master) = resolve::show_master_shapes(slide, rctx.layout);
         if show_master {
@@ -742,14 +747,12 @@ impl Renderer {
         self.in_shadow_pass = false;
         let (mut ctx, w, h, view) = Self::canvas(pres, opts, needs_filters(pres, old.0) || needs_filters(pres, new.0));
         let (Some(co), Some(cn)) = (Ctx::for_slide(pres, old.0), Ctx::for_slide(pres, new.0)) else { return self.finish(ctx, w, h) };
-        // Backdrop graphics never take shape states: their ids may clash with the frame's shapes.
-        let bopts = RenderOpts { state: None, date_text: opts.date_text.clone(), ..*opts };
         if mix < 1.0 {
-            let f = Frame { pres, opts: &bopts, fields: Self::fields(pres, old.1, opts) };
+            let f = Frame { pres, opts, fields: Self::fields(pres, old.1, opts) };
             self.backdrop(&mut ctx, &f, &co, old.0, view);
         }
         if mix > 0.0 {
-            let f = Frame { pres, opts: &bopts, fields: Self::fields(pres, new.1, opts) };
+            let f = Frame { pres, opts, fields: Self::fields(pres, new.1, opts) };
             let layered = mix < 1.0;
             if layered {
                 ctx.push_layer(None, None, Some(mix as f32), None, None);
diff --git a/crates/render/src/tests.rs b/crates/render/src/tests.rs
--- a/crates/render/src/tests.rs
+++ b/crates/render/src/tests.rs
@@ -1776,6 +1776,26 @@ fn the_editor_pasteboard_draws_shapes_off_the_slide() {
     assert!(drawn.x0 <= -100.0 && drawn.y1 >= 660.0 && drawn.x1 >= 960.0, "{drawn:?}");
 }
 
+#[test]
+fn animation_state_skips_layout_and_master_shapes_sharing_a_slide_shape_id() {
+    let mut p = Presentation::default();
+    let bar = |x| Shape {
+        id: ShapeId(77),
+        xfrm: Some(Xfrm::new(x, 400.0, 100.0, 60.0)),
+        fill: Some(Fill::solid(ColorRef::rgb(Rgba::rgb(200, 0, 0)))),
+        ..Default::default()
+    };
+    let lid = p.slides[0].layout;
+    let m = std::sync::Arc::make_mut(&mut p.masters[0]);
+    m.shapes.push(bar(100.0));
+    m.layouts.iter_mut().find(|l| l.id == lid).expect("layout").shapes.push(bar(400.0));
+    let hide = |_: ShapeId| ShapeState { visible: false, ..Default::default() };
+    let img = render_slide(&p, 0, &RenderOpts { scale: 1.0, state: Some(&hide), ..Default::default() });
+    for x in [150, 450] {
+        assert_eq!(img.pixel(x, 430)[..3], [200, 0, 0], "the backdrop bar at x={x} stays");
+    }
+}
+
 #[test]
 fn master_graphics_off_the_slide_show_on_the_pasteboard() {
     let mut p = Presentation::default();
