* fix(render): optimize table styles, chart lookups, line trimming, and canvas limits
* fix(render): give outer-shadow passes their own traversal budget
A shadowed group's silhouette pass shared the 100,000-visit limit with normal drawing, so a group with many children could use it up before anything visible was drawn.
* perf(render): resolve a table's style once per draw
Format Shape's Pattern fill set 25 % in accent 1 on background 1 and
offered no way to change it, and Format Background listed 10 of the 54
presets by their XML names. Both panes now show the same editor: a
gallery of the 54 DrawingML presets drawn in the fill's own colors,
each named in words, and Foreground and Background color menus.
With a pattern fill, Format Shape no longer shows the solid-fill Color
button, which replaced the pattern with a solid fill, or the
Transparency slider, which did not change a pattern. The renderer
exports the preset list and tiles for the gallery to draw.
PowerPoint draws a picture's own fill (p:pic/p:spPr) behind the picture, so
it shows through its transparent pixels: a synthetic deck with one
half-transparent PNG three times (no fill, an orange fill, a yellow fill
with a blue outline), exported as PDF, shows the orange and yellow boxes
behind the image. DeckCraft drew the outline but never the fill.
Old equation objects use this: an OLE object (p:oleObj, Equation.3) has a
fallback picture whose spPr gives it a coloured box behind the equation's
transparent metafile. The reader took only the picture's image as the
object's preview and dropped its fill and line.
- The shape-fill loop moves into Renderer::fill_geometry; a picture and an
embedded object's preview paint their own explicit fill with it before
the image (a style fill alone still draws nothing, as before).
- An embedded object without a fill or line of its own takes them from
its fallback picture's spPr; its frame keeps its own position.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A text box with a glow in its shape properties but no fill and no line got a
blurred ring round the whole box; PowerPoint shows only the text's own glow.
The glow of a frame with a line, and of a filled shape, is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
shape_at folds a 3-D camera's turn into the shape's transform, so
per_point() measured its foreshortening as if it were a group's
child-coordinate scale: in a 1:1 group, a shape under a turned camera
got a factor other than 1 and drew its extrusion depth, contour and
bevel at the wrong size. The factor is now measured on the transform
before the turn (m with the camera's affine taken back out), and the
turned transform still draws the geometry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A group's child coordinates scale its shapes' boxes, but extrusion
depths, contour widths and bevel sizes are points, as PowerPoint draws
them. The renderer applied them in the child space, so the group's scale
multiplied them: a 1 pt contour on a small extruded cube in a legacy
group (1360 child units across a 61 pt group) was drawn hundreds of
points wide, a band across the whole slide, and the cube's extrusion ran
off towards the vanishing point.
per_point() gives the shape-space units per point (the inverse of the
child-coordinate scale that line_space already separates for line
widths); the extrusion depth, contour width and bevel width and height
are converted with it before drawing. Outside a group it is 1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The render gate for an empty placeholder's fill checked only
s.fill.is_none(). A quick style that sets a style reference without
an explicit fill left s.fill as None, so the gate skipped the fill
even though the shape had been formatted — the style only appeared
after text was added.
The gate now also checks s.line and s.style: if any of the three has
a local override, the placeholder is considered formatted and the
fill is drawn. A truly unformatted empty placeholder still shows the
dashed outline and prompt.
The renderer lays every slide background over white (as PowerPoint does),
so a PNG export was always opaque. A new transparentBackground option leaves
the slide background out (both the white underlay and the background fill),
so only what is on the slide is drawn over transparency. Shapes filled with
the background (useBgFill) still show it.
- render: RenderOpts::transparent_background
- engine: file.export {transparentBackground} (PNG only; other formats
refuse it and write nothing), file.render {transparentBackground}
- UI: Transparent background checkbox in the Export dialog (PNG) and in
File > Export > Change File Type > PNG; the web download honours it
- CLI: render --transparent
Fix-ups in the merge (review): uniform-width and highlighter strokes are drawn as one path (on
the slide and in the live preview) so see-through ink doesn't darken where segments overlap;
segment pairs are destructured instead of indexed; tests that build pointer events set the new
pressure field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Make the slide show behave like PowerPoint for interactive decks.
- Hit testing resolves the topmost visible shape under the pointer.
Non-interactive shapes block shapes beneath them; the hand cursor
shows only over interactive shapes.
- Click-triggered animations (interactive sequences) play on shape
click, repeat after their last step, and apply in click order so
cycling "score ring" shapes work.
- Each slide keeps its own progress: returning to a slide through a
link or Back restores hidden shapes and animation state.
- A shape with a link and an animation follows the link immediately;
its animation clock only runs while the slide is shown and resumes
with the remaining time on return.
- With advance-on-click off, background clicks still play animation
steps but never change slide.
- A click on a playing step completes it at once.
Docs (gaps, animation and slide show parity, roadmap) are updated.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Copy puts HTML on the pasteboard with the same plain words, so Pages keeps
bold, italic and underline, and a paste of that HTML keeps them here. A
shape with no text copies out as a picture.
Co-authored-by: Cursor <cursoragent@cursor.com>
A default export is 2 pixels per point. Without a resolution, Preview
treats those pixels as 72 dpi and the picture opens at twice the slide's
size. PNG pHYs and JPEG JFIF density now say scale times 72, so the
default is 144 dpi. Screenshots stay untagged.
Co-authored-by: Cursor <cursoragent@cursor.com>
The preedit was already stored in the cell. It is now laid out the same
way the cell is drawn, and the editor underlines it in place, thicker
under the part being converted. The caret and the input method's
candidate window sit in that cell. Notes stay an egui text field.
Co-authored-by: Cursor <cursoragent@cursor.com>
A pen reading of 1 is the full pen width. A lighter touch draws a thinner
stroke, and a zero reading stays visible at 8% of the pen. A mouse, a
missing or non-finite reading, and a stroke whose samples are all the old
placeholder 0.5 still draw at the pen width. PPTX keeps one width per
stroke: the mean of the samples for a pressured stroke, the pen width for
a legacy one. Tilt is not read.
Co-authored-by: Cursor <cursoragent@cursor.com>
Radar and filled radar charts are drawn polar: spokes per category,
polygon gridlines and value labels up the first spoke. Stock charts
draw high-low lines with close dashes, or up/down bars between open
and close, and are saved as c:stockChart (hiLowLines, upDownBars)
instead of a line chart; c:upDownBars is read, and chart.options takes
upDownBars. New stock charts start as high-low-close and new combo
charts as columns with a line.
Co-authored-by: Cursor <cursoragent@cursor.com>