diff --git a/ROADMAP.md b/ROADMAP.md index 1c0d9958..eb980b68 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -137,6 +137,7 @@ app's JSON control channel (`deckcraft --control PORT`). | 2026-10-22 | Slide Show: while animations play, each frame draws only the slide's shapes over the slide's backdrop (background, master and layout graphics), rendered once and ahead of time. A full-slide picture with a glow in the layout re-rendered at every frame held animations to 2–3 frames a second (~390 ms a frame at 1080p); now ~28 ms | | 2026-10-22 | Animation Pane ▸ Play From: with an effect selected, the pane's play button starts the canvas preview at that effect, with the effects before it already played. With nothing selected it is still Play All | | 2026-10-21 | Opening a .pptx puts the text of shapes without an anchor at the top even when the theme's shape defaults (`spDef`) centre new shapes, as PowerPoint for Mac draws them; checked with a synthetic probe and on a private 166-deck corpus (51 slides closer to PowerPoint's PDF, none further) | +| 2026-10-23 | A shape with no fill and no line (a text box) no longer draws its shape-level glow as a halo round its box; the text's own glow is all PowerPoint shows | | 2026-10-18 | Native chart sidecar bytes move from JSON arrays into referenced ZIP entries, with shared media byte/item limits and bounded reads; older inline sidecars still load. Synthetic format regressions cover large workbooks and malformed members | | 2026-10-18 | Slide thumbnails and the Slide Sorter render only the slides in view: on a deck of more than 600 slides they used to evict their own thumbnails, so the pane flashed white and never finished (#969) | | 2026-10-18 | Resizing with the mouse snaps the edge being dragged to the slide, guides and other shapes: a fixed edge that already lined up used to take the snap and leave the dragged edge free, and a fixed edge near a line shifted the dragged one (#961) | diff --git a/crates/render/src/lib.rs b/crates/render/src/lib.rs index cf124a9f..28df6567 100644 --- a/crates/render/src/lib.rs +++ b/crates/render/src/lib.rs @@ -1437,7 +1437,10 @@ impl Renderer { } ctx.pop_layer(); } - if let Some(g) = &e.glow { + // A shape with no fill and no line (a text box) draws nothing to glow around: its text's + // own glow is all PowerPoint shows, not a halo round the box. + let glows = fill_alpha.is_some() || content.is_some() || outline.is_some(); + if let Some(g) = e.glow.as_ref().filter(|_| glows) { let c = rctx.color(&g.color, ph); ctx.set_transform(Affine::IDENTITY); // Measured on PowerPoint's export: a glow of radius r is half strength about half of r diff --git a/crates/render/src/tests.rs b/crates/render/src/tests.rs index 4ee1c889..e0ca08fe 100644 --- a/crates/render/src/tests.rs +++ b/crates/render/src/tests.rs @@ -431,6 +431,22 @@ fn glow_of_an_unfilled_shape_follows_its_line() { assert!(img.pixel(300, 94)[0] < 240); } +#[test] +fn glow_of_a_shape_with_no_fill_and_no_line_is_not_drawn() { + // A text box (no fill, no line) with a glow in its shape properties: PowerPoint shows no halo + // round the box (its text carries its own glow), so the box's edge and surroundings stay white. + let mut sh = Shape { id: ShapeId(611), xfrm: Some(Xfrm::new(100.0, 100.0, 400.0, 300.0)), fill: Some(Fill::None), ..Default::default() }; + sh.effects = Some(deckcraft_model::Effects { + glow: Some(deckcraft_model::style::Glow { color: ColorRef::rgb(deckcraft_color::Rgba::rgb(255, 255, 0)), radius: 15.0 }), + ..Default::default() + }); + let img = render_slide(&deck_with(vec![sh]), 0, &RenderOpts { scale: 1.0, ..Default::default() }); + for (x, y) in [(300, 250), (300, 100), (300, 95), (96, 250)] { + let px = img.pixel(x, y); + assert!(px[2] > 245, "({x}, {y}): {px:?}"); + } +} + #[test] fn placeholder_prompts_only_in_edit_view() { let p = Presentation::default();