Write shapes, labels, and connectors into the deck and the PDF as objects - #138
Merged
Merged
Conversation
An editable slide now hands the writers a shape and a label as objects: the box and the kind, and the layout rectangle before the turn with the angle beside it. The picture over the page is left with what no element carries, which is the ink, and only where the writer cannot draw strokes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PowerPoint gets a shape with the preset geometry whose outline is the one the board draws, its adjust values worked back from the box, a fill that keeps its translucency, and a label as a text box turned about its own centre. The PDF gets the same outline as a path, with the curved parts as cubic Beziers, and a label as text under a turned matrix. The font resolver learns the families a label can be written in, so the faces are embedded rather than replaced by the default one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The WPF harness builds an editable slide for a board with one shape of each kind and a turned, bold, underlined label, and checks what it carries and what is left for the picture. The Core harness opens what the writers produce: a preset per kind in the slide XML, the corner adjust that tells a stadium from a rounded rectangle, the rotation and the runs of a label, and a PDF that embeds a face for every font a label offers. The export document gains the two mapping tables. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The overlay filter is the one conflict: main widened both lambdas for connectors, and this branch had already replaced them with a single predicate. The predicate keeps the connector, so nothing vanishes from an export until the next commit gives it an element of its own. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A connector leaves as its own element: where it runs, what draws it, and, for a curve, the control points of the cubic, so neither writer works the curve out a second time. PowerPoint gets a connector with straightConnector1 and the flips that turn it, or a freeform holding the cubic, either way with a triangle tail end; the PDF strokes the path the board strokes, stopped at the base of its own arrowhead, and fills the head. The overlay picture is now the ink alone. Two corrections that came out of a review of the shapes: the block arrow's shaft adjust is a fraction of the height rather than of the shorter side, which is what the preset measures it against, so a tall arrow is an arrow again; and the font check accepts the stand-in face a Windows without a family embeds, which is the resolver working rather than failing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A curved connector between two side midpoints that face each other has all four of its points on one line, so the box around them has no height and the freeform path had nothing to scale against. The path's own extents never reach zero now, and the harness carries that curve. The font check wrote every label into one document, where Arial and Times New Roman are named for their own sake and so answered for every family that falls back to them. It is a document per font now, so a face that quietly fell back to the page's own is a failure again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
marcosqlbi
added a commit
that referenced
this pull request
Sep 17, 2026
) Pull request 7 of the 1.6.0 plan in `docs/design-objects.md`: the release cut. The five features are on `main` — the grid (#134), selection by area (#135), text labels (#136), shapes and the Insert tab (#137), and connectors (#139) — and none of them touched the prose, so this is where a person is told what they got. **#138, the native editable export, must merge before this one**: the release notes and the guide both say shapes and labels leave as objects in a deck and a PDF, which is true once it lands. `VersionPrefix` goes 1.5.2 → 1.6.0, so `CHANGELOG.md` gains the matching section and the **Release notes** check applies to this pull request. `./scripts/release-notes.ps1 -Mode Verify -Version 1.6.0` passes, and `dotnet build Whiteboard.sln -c Release` is clean. ## What it affects - **`CHANGELOG.md`** — one `## 1.6.0 - 17 September 2026` section with three entries, which is the shape of 1.5.0 (3), 1.5.1 (1) and 1.5.2 (2): the Insert tab with shapes, connectors and text, selection by area, and the grid. The toolbar preference is one sentence inside the first entry rather than a fourth entry, because it is where somebody meets it. The first entry also carries the one thing a person deciding whether to upgrade has to know: a board holding any of the new objects does not open in 1.5.x. - **`README.md`** — three bullets in *Included in the application*, seven rows in *Controls*, the Preferences lists in the bullet and in the table, and the containers paragraph, which now says shapes and labels are containers and that a shape is picked up by its outline. - **`site/guide.html`** — a new *Shapes, connectors, and text* section after *Text and code*, a paragraph on area selection under *Containers*, one sentence on the grid under *Navigation*, and the Insert tab named in the command-strip section. - **`site/shortcuts.html`** — Insert, Lasso and Grid rows, the rubber band and Ctrl-to-add, and the Alt-mnemonic row extended with Alt+I, Edit L, View G, and Insert T. - **`site/index.html`** — two feature tiles, shapes/connectors/text and select by area. - **`docs/decisions.md`** — decision 31, why design objects are ordinary board objects, why a shape is taken by its outline, and why the grid is an application preference. The rest stays in `docs/design-objects.md`, whose status line is now shipped in 1.6.0. - **`TODO.md`** — the current version, which still said 1.3.0, and what 1.6.0 left out. ## Readings taken, since nobody could be asked - **`site/compare.html` is untouched.** It has no row saying Whiteboard lacks shapes, text, a grid or multi-select; the nearest, *Ink and objects*, is a statement about strokes travelling with a container and is still true. The brief said to change such cells and nothing else, so nothing else changed. - **`site/faq.html` is untouched.** No answer on it became wrong. - ***Architecture* in `README.md` is untouched.** The `Core` bullet names no types — it says "world geometry, camera math, retained board objects, commands, hit testing" — so there was no list for `ShapeGeometry`, `ConnectorGeometry` and `RotatedRectangle` to join, and the brief said to leave it alone in that case. - **Escape is an edited row, not a new one**, in both the README table and the shortcut list: Escape already had one, and a second would contradict it. - **`site/changelog.html` is untouched**, as it is generated from `CHANGELOG.md` at deployment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Shapes, labels, and connectors reached the editable deck and the vector PDF as pixels: #130, #132, and #131 each drew their objects into the transparent overlay picture so that nothing vanished from an export. That was the holding position the plan named in decision 10. This is the sixth pull request of the 1.6.0 plan, which replaces it: a shape leaves as a PowerPoint shape and as a PDF path, a label as a text box and as text on the page, and a connector as a PowerPoint connector and as a stroked path with a filled head. A deck can now be recoloured and typed into, and a PDF's labels can be selected and searched.
What it affects: the editable deck and the vector PDF only. A picture slide, a raster page,
preview.png, the Explorer thumbnail, and Ctrl+C all still go throughBoardSurfaceand are what they were. The overlay picture is written as a single predicate inEditableSlide.NeedsOverlay, which lists the kinds that have no element yet; after this it is the ink alone, and only on the path where the writer cannot draw strokes, so a vector page emits no overlay at all.mainwas merged in rather than rebased onto, and the overlay filter was the one conflict.PowerPoint
A shape becomes a
p:spwith the preset whose outline is the one the board draws, ana:solidFillcarryinga:alphafor a tinted fill ora:noFill, and ana:lnwith the width in EMU, a round join, and round caps. The adjust values are worked back from the box, because a preset measures them against its shorter side while the board's fractions are of the box — except the block arrow's shaft, which the preset measures against the height.roundRect,adj20000ellipsetrianglepentagonrightArrow,adj1the shaft fraction,adj2the head from the boxparallelogram,adjthe slant from the boxdiamondroundRect,adj50000p:spwitha:xfrm rot,wrap="none", autofit off, insets zero, anchor top-leftp:cxnSpwithstraightConnector1,flipH/flipVfor its directionp:spwith ana:custGeomholding the board's own cubica:tailEnd type="triangle" w="med" len="med"A label's runs carry
b,i,u="sng",szin hundredths of a point,a:solidFill, anda:latin typeface, one paragraph per line. Element order on the slide follows z-order, as it already did for pictures and text containers.flowChartTerminatorwas the other candidate for the stadium and was not taken: its ends are not semicircles on a box wider than it is tall, while a rounded rectangle whose corners have taken the whole of its shorter side is exactly whatShapeGeometrydraws.curvedConnector3was the other candidate for the curved arrow and was not taken either: it leaves its ends along the box's own axes whatever it is bound to, while the board's curve leaves along the side it is bound to, so the two bend differently often enough to be noticed.PDF
A shape is one path built from
ShapeGeometry.Describe— the description the screen is drawn from — with straight parts as lines and curved ones as cubic Béziers of a quarter turn at most, so a circle is a circle at any zoom rather than the 64-gon the hit test walks. It is filled with the tint through PDFsharp's alpha state and stroked with the outline. A label is text under a matrix turned about the label's centre, its lines spread over the height the board measured them at, underlined by a stroked line at the face's own underline position and thickness. A connector isConnectorGeometry.LinePathstroked with round caps andConnectorGeometry.Arrowheadfilled — the same two callsBoardSurfacemakes, in slide pixels — so the page and the screen agree about where the line stops and how big the head is.PDFsharp's Core build resolves no fonts by itself, so the writer already read Segoe UI and Consolas from the Windows fonts folder and embedded them; that resolver now knows every family a label offers, so a label's own face is embedded rather than replaced. The standard-14 mapping the task offered as the alternative is not needed.
segoeui,segoeuib,segoeuii,segoeuizcalibri,calibrib,calibrii,calibrizarial,arialbd,ariali,arialbigeorgia,georgiab,georgiai,georgiaztimes,timesbd,timesi,timesbiconsola,consolab,consolai,consolazcomic,comicbd,comici,comiczsegoepr,segoeprb, andsegoepragain for italicDecisions the plan did not settle
p:cxnSpcarrying a geometry of its own is legal but not something PowerPoint writes itself, and nobody here can open the file to find out how it takes it; a freeform with a cubic is exactly how PowerPoint stores a hand-drawn curve. A curve with no connection sites has nothing to re-route to either way. The straight kinds stay real connectors.rightArrowpinsadj1at 100000, and that maximum is a shaft as thick as the shape, which only reads as the height; every other adjust here does go through the shorter side. A tall arrow is the case the two readings differ on, and it is in the list below.stCxn/endCxnto the shape's id on the slide, and would then follow it when the shape is dragged in PowerPoint. It needs the writer's ids inside the element, so it is a follow-up rather than this pull request.CascadiaMono.ttf, a variable font whose bold and italic are axes rather than files, so embedding it would give a regular face for all four styles. Recorded indocs/export.md.a:xfrm rotand a PDF text matrix take without undoing a rotation first.ConnectorGeometrygainedControlsandFlatten, both public, so the writers use the board's own curve instead of deriving one.Polylineis now written in terms of them..pptxas a ZIP and readsslide1.xmlfor the preset names, the corner adjust that tells a stadium from a rounded rectangle,rot="2700000",u="sng", the flips, the two tail ends, and the cubic; and it reads the produced PDF for a base font per family, accepting the stand-in face where a Windows has no such family. The WPF harness checks what the board hands the writers for a board with one shape of each kind, a turned bold underlined label, a bound curved arrow, and a free straight line.To try by hand
docs/export.mdsays.🤖 Generated with Claude Code