editor: complete floorplan construction documentation (#531)

* Add roof surface placement support for items

Items (e.g. solar panels) can now be placed on sloped roof surfaces.
The placement system computes euler rotation from the roof surface
normal so items sit flush on the slope instead of going inside.

- Add roofStrategy to placement-strategies with enter/move/click/leave
- Wire roof:enter/move/click/leave events in the placement coordinator
- Add calculateRoofRotation in placement-math using surface normals
- Support full 3D cursor rotation for sloped surfaces
- Items on roofs are parented to the level with world-space rotation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fixed conflict

* feat(floorplan): add construction dimension strings

* feat(floorplan): coordinate opening dimensions

* feat(floorplan): add opening documentation

* feat(floorplan): add construction dimensions and notes

* feat(floorplan): add interior dimensions and curved note leaders

* feat(floorplan): improve construction dimensions and document plan

* feat(floorplan): harden construction document output

* feat(floorplan): add annotation collision diagnostics

* feat(floorplan): size export annotations in paper space

* feat(floorplan): automatically separate overlapping labels

* fix(floorplan): resolve dense label overlaps

* fix(floorplan): remove stale collision warning overlays

* fix(floorplan): treat mark pills as collision obstacles

* feat(floorplan): place short dimension values outside

* fix(floorplan): preserve dimension string order

* fix(floorplan): avoid architectural geometry in label layout

* feat(floorplan): add dimension side fallback leaders

* docs(floorplan): update chapter 17 implementation status

* fix(floorplan): dimension subdivided interior walls

* feat: add associative floor plan dimensions

* feat: add continuous construction dimension strings

* feat: add structural floor plan grids

* feat: coordinate columns with structural grids

Snap column placement and movement to structural axes and intersections, derive associative grid references, and preserve floor-plan rotation by allowing secondary-button pointer moves through the grid drafting layer.

* feat: add architectural room documentation

Add room-role metadata, editable documentation fields, centered room labels, and persisted live/PDF visibility while preserving generic zone behavior.

* feat: generate architectural room schedules

Add registry-driven room schedule rows with unit-aware areas and heights, natural room ordering, enclosure resolution, and document-quality warnings.

* feat: add reliable room clear dimensions

Derive unit-aware clear dimensions from proven modeled inside wall faces for straight rectangular rooms, including rotated and split-wall enclosures, while suppressing unproven datums.

* feat: add architectural stair documentation

Add level-aware UP/DN graphics, derived flight and rail notes, plan break and overhead conventions, linked destination-level projection, and persisted live/PDF visibility.

* feat: add typed specialty construction notes

Add schema-validated specialty payloads, standardized plan notation, contract-scope metadata, configurable overhead outlines, and editor authoring controls.

* feat: add curved and circular dimensions

Add associative radius, diameter, center, chord, arc-length, angular, and coordinate modes with unit-aware notation, repeated-feature labels, 2D authoring, and document controls.

* feat: coordinate floor plan drawing types

Add persistent floor, foundation, reflected-ceiling, roof, and site plan views with per-dimension show, omit, reference, and foundation-controller behavior across live and PDF output.

* feat: add associative curved wall dimensions

Bind radius, center, chord, arc-length, and angular construction dimensions directly to curved wall geometry so annotations update when the host curve changes.

* fix: render automatic curved wall dimensions

The wall floor-plan builder explicitly skipped curved walls, leaving the associative authoring workflow as the only dimension path. Render a concentric arc-length dimension automatically and keep it governed by automatic-dimension visibility.

* fix: use radius callout for curved walls

Replace the automatic arc-length annotation with the source-standard radius method: computed center mark, radial leader, curve arrow, and R value. Keep adjacent linear strings responsible for locating the curve tangencies and depth.

* Implement construction dimension string editing

* Add construction dimension standards controls

* Apply drawing standards to automatic dimensions

* Add floorplan overhead and reference visibility controls

* Add view-specific dimension segment suppression

* Add persistent drawing sheet model

* Plot floorplan exports at fixed scale

* Apply paper-space annotation profiles

* Compose floorplan PDF sheets

* Support sheet paper sizes and preflight

* Persist pinned annotation layout overrides

* Expand annotation collision obstacles

* Add floorplan annotation preflight surface

* Add reusable drawing sheet general notes

* Add drawing sheet keyed note instances

* Add drawing sheet document markers

* Expand construction note leader terminators

* Add wall assembly layer model

* Resolve wall assembly datum references

* Add wall assembly floorplan graphics

* Add opening documentation dimension policies

* Add finish-face room clear dimensions

* Extend room clear dimensions to rectilinear rooms

* Add construction module advisories

* Add clearance advisory profiles

* Add dimension completeness audit

* Expand dimension completeness audit

* Include preflight issues in completeness audit

* feat: complete floorplan construction documentation

* refactor: remove construction note node

* feat: refine floorplan documentation and unit display

* fix(editor): improve floorplan PDF dimensions

* fix(floorplan): refresh annotation collision layout

* fix(floorplan): keep annotations clear and restore registry boundaries

* feat(floorplan): refine construction dimension references

* fix(floorplan): align documentation tools with architecture

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sudhir Yadav
2026-07-22 14:02:17 -04:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 2adb50a340
commit 77442861d9
181 changed files with 25002 additions and 800 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ Measurement nodes must remain in `AnyNode`, `LevelNode.children`, the built-in n
These functions are pure and receive the same read-only `GeometryContext` used by registered geometry. They must not import Three.js, editor state, or `useScene`. Feature IDs describe semantic roles (`wall:face:left`, `wall:height`, `roof:ridge:0`); labels never act as identifiers.
The wall contribution samples the existing curved-wall centerline and resolves face hits with normalized `t` plus clamped height. Exact plan-level wall corners bind to `wall:start` or `wall:end` before the thickness-aware face matcher runs. The roof-segment contribution reuses `getRoofSegmentPlanLinework` and the existing roof surface-height calculation, then applies segment and parent-roof transforms. Slab, ceiling, zone, and site use one shared polygon contribution with stable `vertex:<index>`, `boundary`, and `center` roles. An exact corner uses the point feature so it remains a corner when the polygon changes shape; continuous boundary anchors store normalized perimeter position. Do not duplicate any of those topology implementations in measurement code.
The wall contribution samples the existing curved-wall centerline and resolves face hits with normalized `t` plus clamped height. Exact plan-level wall corners bind to `wall:start` or `wall:end` before the thickness-aware face matcher runs. Curved walls additionally publish `wall:curve:center`, allowing radius, center-mark, chord, arc-length, and angular construction dimensions to bind their complete defining geometry and follow later curve edits. Arc-length and angular drafting use four explicit clicks: first arc/ray point, center/vertex, second arc/ray point, then label-line position; their anchors persist in point-center-point order. The roof-segment contribution reuses `getRoofSegmentPlanLinework` and the existing roof surface-height calculation, then applies segment and parent-roof transforms. Slab, ceiling, zone, and site use one shared polygon contribution with stable `vertex:<index>`, `boundary`, and `center` roles. An exact corner uses the point feature so it remains a corner when the polygon changes shape; continuous boundary anchors store normalized perimeter position. Do not duplicate any of those topology implementations in measurement code.
`resolveMeasurementNode` derives current free-point geometry from the scene snapshot. Renderers subscribe to referenced nodes, their parents, and ephemeral node overrides; the floor-plan cache uses `def.floorplanDependencies` and the same override-merged resolver. A host edit therefore changes measurement geometry and value during the drag and after commit without writing the measurement node or adding history entries.
+203
View File
@@ -0,0 +1,203 @@
# Floor Plan Chapter 17 Assessment
## Purpose
This document compares the guidance in `Chapter_17_Floor_Plan_Dimensions_and_Notes.pdf` with Pascal's current floor-plan implementation. It records what the chapter teaches, what the editor already supports, and the remaining construction-document gaps.
The review covered the full 19-page chapter and the floor-plan stack across:
- Core floor-plan, wall, opening, and measurement schemas.
- The registry-owned `FloorplanGeometry` contract.
- Editor 2D rendering and interaction layers.
- Node-specific floor-plan builders.
- Automatic wall and opening dimension planning.
- Persistent measurements and smart measurement.
- Door/window documentation and schedules.
- Per-level PDF export.
## What the chapter is teaching
The chapter is primarily about construction communication, not merely measuring geometry. Its main principles are:
1. A drawing must locate and size every construction-critical feature without requiring field workers to guess, scale the drawing, or perform unnecessary arithmetic.
2. Dimensions must be organized into consistent strings that remain readable and uncrowded.
3. The selected datum must match the construction method: centerline, face of stud, face of finish, masonry opening, rough opening, or another explicit reference.
4. Dimension graphics must follow a consistent standard: thin lines, extension-line gaps, extension-line overshoot, uniform terminators, readable aligned text, and predictable spacing.
5. Exterior strings normally progress from detailed opening/partition information to the overall building dimension.
6. Local or specific notes identify individual features through leaders. General notes apply to the whole drawing and are normally numbered in a dedicated sheet area.
7. Door/window schedules and feature notes may replace repeated dimensions when they communicate the information more clearly.
8. Drawing scale, paper-space text size, line weight, and sheet composition are part of the construction-document contract.
9. Curved, circular, masonry, concrete, and foundation-related construction require different dimension semantics from ordinary wood-frame walls.
## Current implementation
### Automatic construction dimensions
`packages/nodes/src/wall/construction-dimensions.ts` already produces coordinated level-wide construction dimensions. The exterior hierarchy includes:
1. Opening widths.
2. Door and window center locations.
3. Intersecting partition references.
4. Structural columns.
5. Facade jogs, projections, and recesses.
6. Overall facade dimensions.
7. A structural overall dimension when an exterior column row extends beyond the wall envelope.
The planner also supports:
- Collinear wall runs that form one facade.
- Disconnected facade runs.
- Angled exterior walls.
- Exterior-side classification.
- Wall-thickness-aware partition references.
- Interior partition strings, including geometrically enclosed partitions whose side metadata remains stale after wall splitting.
- Subdivision chains on every exterior orientation when internal walls divide a facade into multiple runs.
- Hosted door and window widths.
- Interior clear spans bounded by adjacent wall faces.
- Suppression of very short accidental segments.
- Associative updates when the contributing model geometry changes.
`packages/nodes/src/wall/floorplan.ts` integrates these dimensions into the registry-driven wall floor-plan builder.
### Dimension graphics
`packages/editor/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx` implements several conventions from the chapter:
- Aligned dimension lines.
- A gap between the feature and extension line.
- Extension lines that pass beyond the dimension line.
- Consistent 45-degree architectural slash terminators.
- Thin dimension and extension lines.
- Text above the dimension line.
- Text that remains readable when the plan is rotated.
- Explicit aligned baselines for stepped facade dimensions.
- Separate edit and document presentation profiles.
- True modeled wall thickness in document output while retaining interactive legibility in edit mode.
- Paper-space dimension text, tick, extension-gap, overshoot, and label-offset sizing in PDF output.
- Whole-millimetre document notation without an `mm` suffix, while retaining metre notation in the interactive editor.
- Short-segment values outside the dimension ticks when the value cannot fit inside.
### Automatic annotation layout
`packages/editor/src/components/editor-2d/renderers/floorplan-annotation-layout.ts` now resolves automatic dimension-value collisions in both the live floor plan and PDF composition. It supports:
- Label-to-label separation, including dense clusters.
- Stable same-string drawing order and priority for farther-out architectural strings.
- Movement along the dimension string before crossing into an adjacent tier.
- Fixed door/window mark pills as obstacles.
- Semantic architectural obstacles for walls, wall corners, door symbols and swing envelopes, windows, and columns.
- Sampled diagonal wall outlines, avoiding the oversized screen-aligned bounds produced by rotated walls.
- Outside-end placement for short values, followed by outside-start when the end side is blocked.
- Matching baseline extensions when a short value changes sides.
- A leader and true tick-to-tick baseline when both outside positions require further relocation.
The former orange/red dashed collision overlay was removed because it displayed stale pre-layout conflicts on top of labels that the automatic resolver had already made readable. Any future unresolved-collision reporting should live in a separate preflight surface rather than being painted over the drawing.
`packages/nodes/src/shared/construction-length.ts` formats imperial construction dimensions using feet, inches, and reduced fractions rounded to the nearest sixteenth.
### Persistent measurements
The existing measurement system is broader than the chapter's drafting examples. It supports:
- Distance.
- Angle.
- Area.
- Perimeter.
- Prism volume.
- Free and associative semantic anchors.
- Wall, roof, slab, ceiling, zone, and site features.
- Live updates when referenced geometry changes.
- Dangling-reference presentation and explicit detach behavior.
- 2D and 3D drafting and editing.
- Smart transient measurement reports.
The architecture is documented in `wiki/architecture/measurements.md`. These measurements are analysis annotations; they are not yet a complete replacement for architectural construction-dimension strings.
### Door and window documentation
`packages/nodes/src/shared/opening-documentation.ts` provides:
- Deterministic automatic door and window marks.
- Explicit mark overrides.
- Duplicate explicit-mark warnings.
- Mark bubbles and leaders.
- Door schedules.
- Window schedules.
- Nominal dimensions.
- Optional verified rough-opening dimensions.
- Window sill and head heights.
- Door operation, frame, and hardware fields.
The rough-opening fields intentionally remain optional rather than being invented from the nominal modeled opening size.
### Rooms, stairs, and other plan graphics
- Zones render a centered name but currently represent generic colored polygons rather than a complete architectural room model.
- Stairs render footprints, treads, and direction arrows, but do not yet emit a complete construction stair note.
- Columns can contribute structural center references to automatic exterior strings.
- The generic floor-plan registry already renders walls, doors, windows, slabs, ceilings, zones, roofs, stairs, columns, furniture, MEP nodes, and annotation nodes through a common geometry contract.
### PDF export
`packages/editor/src/lib/floorplan/floorplan-export.tsx` currently provides:
- Per-level PDF plan pages.
- North-up orientation that accounts for building rotation.
- Full and structure-only export scopes.
- Door and window schedule pages.
- Registry-driven geometry matching the live floor-plan builders.
- Conversion of non-scaling SVG strokes for PDF output.
- Preservation of persistent measurement value labels in full export.
- Respect for the existing measurement-visibility preference.
- Document-purpose wall rendering at modeled thickness.
- Document metric notation and initial paper-space sizing for construction dimensions and measurement labels.
- The same automatic annotation collision layout used by the live floor plan.
The plan is fitted to an A4 landscape page. It is not yet plotted at a fixed architectural scale.
## Important current limitations
### Interactive measurement and construction dimension are different concepts
The measurement system stores geometric analysis annotations. The wall planner creates automatic construction strings. There is no dedicated manual construction-dimension object that lets a drafter pick references, place a baseline, add points to a continuous string, and later reposition or suppress individual segments.
### The current datum is not truly face of stud
`WallNode` stores total thickness and finish materials but does not describe studs, sheathing, finish layers, veneer, air space, concrete block, or furring. Automatic dimensions can reference a generic wall face, but the model cannot yet prove that this face is a structural stud face or finish face.
### Paper-space control is only partially implemented
Exported construction dimensions and measurement labels now resolve their main text, tick, extension-gap, overshoot, and label-offset sizes from paper points. Note text, mark bubbles, room labels, remaining line-weight categories, and fixed user-selectable drawing scales still require the drawing-sheet work.
### Construction dimensions have no independent visibility layer
The live floor plan exposes independent visibility controls for automatic dimensions, manual dimensions, measurements, opening marks, structural grids, room labels, and stair annotations. Full export intentionally includes every supported annotation category regardless of the live-view toggles.
### Automatic collision layout has no persistent manual override
Automatic placement now handles adjacent labels, short values, opening marks, and the first set of architectural obstacles. It does not yet let a drafter pin a chosen label position, suppress a segment, or persist a view-specific layout override. Broader fixed-symbol coverage and a separate unresolved-collision preflight also remain.
### Curved and circular construction dimensions
Curved walls emit an automatic radius leader and center mark in live plans and document output, matching the chapter's curved-wall callout method. Manual associative construction dimensions cover radius, diameter, center, chord, arc-length, coordinate-pattern, and angular-pattern workflows, with curved-wall defining geometry resolved from stable semantic host features.
### Construction systems are not semantically modeled
The editor cannot yet apply different documentation rules for wood framing, masonry veneer, concrete block, structural masonry, or solid concrete because those assembly semantics do not exist in the wall model.
### The floor plan has no drawing-sheet model
The export layer produces plan and schedule pages, but there is no persistent drawing sheet with view identity, scale, title block, drawing number, note blocks, graphic scale, north arrow, or per-view annotation visibility.
## Features that should not be copied blindly
The chapter was published in 2012. Its example sizes and clearances are useful drafting and design references, but they should not be treated as current building-code requirements.
Any implementation of hallway, fixture, door, stair, appliance, or room-clearance checks should:
- Be configurable by jurisdiction and standard profile.
- Be presented as an advisory or verification result unless code provenance is known.
- Avoid embedding manufacturer-dependent rough openings or product sizes as universal facts.
- Avoid silently omitting dimensions merely because a feature is commonly considered standard.
The product should prefer explicit model data, verified manufacturer data, and user-controlled documentation policies.
@@ -0,0 +1,269 @@
# Floor-plan PDF export library research
Date: 2026-07-21
## Decision summary
The missing dimension values are a conversion-boundary problem, not a limitation of PDF text.
The current export builds an SVG in the DOM and asks `svg2pdf.js` to reinterpret that SVG as PDF.
That makes the result depend on how the converter handles nested transforms, inherited SVG styles,
font discovery, text baselines, paint order, and non-scaling strokes. Replacing `svg2pdf.js` with a
second automatic SVG converter leaves those same risks in place.
The reliable design is to render the existing semantic `FloorplanGeometry` directly into PDF
primitives. Dimension values must be emitted with the PDF library's native text API, and dimension
lines/ticks must be emitted with explicit point widths. That preserves selectable vector text and
removes SVG/CSS interpretation from the critical path.
Recommended choices:
1. **Smallest and lowest-risk:** keep jsPDF but stop sending dimension annotations through
`svg2pdf.js`. Draw dimensions as a native jsPDF overlay with `doc.text`, `doc.line`, and
`doc.rect`. This is the best implementation choice even though it is not a library replacement.
2. **If a different library is required:** use **PDFKit directly**, rendering from
`FloorplanGeometry`. It has the strongest current combination of browser support, native vector
drawing, transformation support, font embedding, and active maintenance.
3. **Do not choose another automatic SVG converter** as the primary fix. In particular,
`SVG-to-PDFKit` has been inactive since 2022 and documents unsupported features and browser font
loading caveats.
No production code was changed as part of this research.
## Current architecture and why it matters
The current code already has the right source model for a direct PDF backend:
- Node builders return semantic `FloorplanGeometry`, including `dimension`, `dimension-string`,
`dimension-label`, lines, paths, polygons, circles, and groups.
- [`floorplan-dimension-renderer.tsx`](../packages/editor/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx)
resolves each dimension's line endpoints, ticks, label point, label angle, font size, and label
placement.
- [`floorplan-export.tsx`](../packages/editor/src/lib/floorplan/floorplan-export.tsx) currently mounts
a React SVG off-screen and converts it with jsPDF + `svg2pdf.js`.
That means a new export backend does not need to infer measurements from DOM nodes. It can traverse
the same geometry tree and emit native PDF operations deterministically.
The current converter itself says that custom fonts must be registered before conversion, calls
itself "by no means perfect," and notes that its visual tests can vary because of text measurement.
Those are material warnings for small, rotated architectural labels.
[Official `svg2pdf.js` repository](https://github.com/yWorks/svg2pdf.js)
## Requirements
The selected approach should provide:
- visible dimension values at every rotation;
- selectable/searchable PDF text;
- embedded or otherwise deterministic fonts;
- explicit thin vector strokes in PDF points;
- lines, curves, polygons, circles, fills, clips, and nested transforms;
- browser-side generation and Blob/download support;
- compatibility with React and TypeScript in this monorepo;
- an API that can be tested without visual browser automation.
## Comparison
| Rank | Approach | Native/selectable text | Fonts | Transforms and thin vectors | Browser/TypeScript fit | Maintenance | Integration cost |
|---:|---|---|---|---|---|---|---|
| 1 | Direct jsPDF drawing, optionally as a hybrid overlay | Yes; `text()` emits PDF text and supports an angle or matrix | Custom TTF through VFS + `addFont` | Explicit `setLineWidth`; advanced mode exposes transformation matrices | Already installed and browser-first; official typings | Active; current 4.x docs and releases | Low for annotation overlay, medium for full renderer |
| 2 | Direct PDFKit renderer | Yes; native PDF text | TTF, OTF, WOFF, WOFF2, TTC, dfont; subsetting | Canvas-like vectors, SVG path data, save/restore, translate/rotate/scale/transform, explicit line width | Browser supported, but Blob stream/bundling and separate TS types add work | Active; current 0.19.x releases | Medium-high |
| 3 | Chromium print-to-PDF | Browser's own text/SVG renderer; generally preserves vector text | Uses loaded web fonts; Puppeteer waits for fonts by default | Browser-native SVG/CSS transforms and strokes | Not a pure browser-side library: needs print UI or a headless-browser service | Very active | Low rendering rewrite, high operational cost |
| 4 | `@react-pdf/renderer` | Native `<Text>` and SVG `<Text>` | `Font.register`; TTF and WOFF | SVG primitives, group transforms, explicit strokes; `Canvas` wraps PDFKit operations | Browser + server React APIs, Blob provider, bundled typings | Active releases and commits | High because DOM SVG is not reusable as-is |
| 5 | `pdf-lib` direct renderer | Native `drawText` with rotation | Standard fonts; custom fonts through `@pdf-lib/fontkit` | Lines, shapes, individual SVG path data, explicit thickness; lower-level transform work | Browser-compatible and TypeScript-native | Stable but inactive upstream since November 2021 | High |
| 6 | `SVG-to-PDFKit` automatic conversion | Supports SVG text/tspan/textPath | Requires pre-registration or a callback; does not wait for async browser font loading | Supports common transforms, but documents unsupported `vector-effect` | Browser possible through PDFKit; has a declaration file | Last commit August 2022; no published GitHub releases | Medium |
| 7 | Canvg raster fallback | No; text becomes pixels | Whatever the canvas resolved at rasterization time | Visually faithful at sufficient resolution, but all output is raster | Browser-friendly and TypeScript-based | Maintained; 4.0.3 released in 2025 | Low-medium |
## Approach details
### 1. Direct jsPDF primitives — recommended incremental implementation
jsPDF already exposes all operations needed for dimension annotations:
- `text(text, x, y, { angle, align, baseline })` for actual PDF text;
- transformation matrices in advanced mode;
- `setLineWidth(width)` in the document's declared units;
- custom font registration with `addFileToVFS`, `addFont`, and `setFont`.
The official source documentation shows that `text()` writes a PDF text object (`BT`, font
selection, text position, `Tj`, `ET`) rather than rasterizing the label. It also documents angle and
matrix transforms. [jsPDF text and line-width documentation](https://parallax.github.io/jsPDF/docs/jspdf.js.html),
[font and advanced-mode guide](https://parallax.github.io/jsPDF/docs/index.html)
Practical design:
1. Keep the current `svg2pdf.js` pass temporarily for non-annotation geometry.
2. Exclude all `dimension`, `dimension-string`, and `dimension-label` geometry from that SVG pass.
3. Resolve them into a small `PdfDimensionAnnotation` display list containing witness lines,
dimension line, tick segments, label text, label anchor, angle, font size, and background box.
4. Transform model coordinates into page points once.
5. Draw the background plate, lines, ticks, then `doc.text()` with explicit fill color and embedded
font.
6. Later, move walls and other geometry to the same native backend if desired.
Why this is ranked first: it eliminates the observed failure path while retaining the installed PDF
engine, page setup, headers, schedules, and save flow. It also provides a narrow regression-test
surface: generated PDF content can be inspected for each expected label string.
### 2. Direct PDFKit — recommended full replacement library
PDFKit runs in both Node and the browser. Its official documentation includes:
- selectable text and embedded font support for TTF, OTF, WOFF, WOFF2, TTC, and dfont;
- vector `moveTo`, `lineTo`, Bézier and quadratic curves;
- parsing of SVG **path data** (not an entire SVG DOM);
- save/restore, translate, rotate, scale, and arbitrary transform operations;
- explicit stroke widths and Blob output in the browser.
[PDFKit browser setup](https://pdfkit.org/docs/getting_started.html),
[vector and transform APIs](https://pdfkit.org/docs/vector.html),
[text and font APIs](https://pdfkit.org/docs/text.html)
PDFKit 0.19 raised its documented browser floor to Firefox 115 and Safari/iOS 16, and its current
release line continues to include text, font, SVG-path, and browser fixes.
[Official PDFKit releases](https://github.com/foliojs/pdfkit/releases)
Practical design:
1. Add an exhaustive `renderFloorplanGeometryToPdfKit` visitor.
2. Give the visitor a coordinate transform from model metres to PDF points, including the page's
Y-axis inversion and plan rotation.
3. Draw every dimension label using `doc.text()` after `save/translate/rotate`.
4. Register an exact project font before rendering and use explicit point sizes.
5. Pipe to a browser Blob stream and keep the existing download UX.
Tradeoffs: this is a cleaner long-term backend but a larger initial migration. PDFKit's npm package
does not currently advertise bundled declarations in its package manifest, so the TypeScript package
would normally also use `@types/pdfkit`. Browser output uses a Node-style stream, commonly adapted
with `blob-stream`. Both add integration weight compared with the existing jsPDF save flow.
### 3. Chromium/browser printing
Printing a dedicated page lets the browser render the same SVG, CSS, transforms, and fonts that it
renders on screen. `window.print()` is widely available, and print-specific CSS can control the
page. [MDN `window.print`](https://developer.mozilla.org/en-US/docs/Web/API/Window/print),
[MDN printing guide](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Media_queries/Printing)
For automatic downloads, Puppeteer's `Page.pdf()` uses Chromium print output. Its documented
options include CSS page-size preference, background graphics, and waiting for
`document.fonts.ready` (enabled by default).
[Puppeteer PDF guide](https://pptr.dev/guides/pdf-generation),
[Puppeteer PDF options](https://pptr.dev/api/puppeteer.pdfoptions)
This is the best path when exact browser-rendering parity outweighs infrastructure cost. It is not
a pure client library: either the user must use the print dialog, or the application needs a trusted
server/desktop process running Chromium. That is a substantial architectural change for the current
browser-side download.
### 4. `@react-pdf/renderer`
React-pdf produces PDFs in the browser and server and offers browser Blob/download components. It
has its own PDF primitives, including SVG `Line`, `Path`, `Text`, `Tspan`, and `G`. Its documented
presentation attributes include `strokeWidth`, `transform`, `textAnchor`, and
`dominantBaseline`. Group transforms apply to children. Its `Canvas` painter wraps PDFKit methods,
including `text`, `path`, `rotate`, `lineWidth`, `translate`, and `scale`.
[React-pdf SVG APIs](https://react-pdf.org/svg),
[components and Canvas API](https://react-pdf.org/components),
[font registration](https://react-pdf.org/fonts)
This is viable and actively maintained. It is not a drop-in renderer for the existing React DOM SVG:
the floor plan must be rebuilt with React-pdf's component types or drawn through its Canvas painter.
For a CAD-like plan, that gives no decisive rendering advantage over direct PDFKit while adding a
second React renderer and layout engine. It is more attractive if the broader drawing-sheet document
will be rebuilt declaratively.
### 5. `pdf-lib`
`pdf-lib` runs in browsers and is written in TypeScript. It provides native `drawText` with rotation,
explicit line thickness, rectangles/circles/ellipses, and individual SVG path drawing. Custom fonts
are embedded through `@pdf-lib/fontkit`.
[Official examples](https://pdf-lib.js.org/),
[`PDFPage` drawing API](https://pdf-lib.js.org/docs/api/classes/pdfpage),
[`DrawTextOptions`](https://pdf-lib.js.org/docs/api/interfaces/drawtextoptions)
It does not parse a complete SVG document; its SVG support is for one path-data string at a time.
Consequently, it requires the same complete `FloorplanGeometry` visitor as PDFKit, with a less
convenient graphics-state/transform API for this use case. The upstream repository's latest commit
and release are from November 2021, so it is not the preferred new dependency for a renderer being
introduced in 2026. [Official commit history](https://github.com/Hopding/pdf-lib/commits/master/),
[official releases](https://github.com/Hopding/pdf-lib/releases)
### 6. `SVG-to-PDFKit`
`SVG-to-PDFKit` is the only credible alternate JavaScript full-SVG converter found. Its documented
coverage includes SVG text/tspan/textPath, transforms, paths, clips, masks, fonts, gradients, and
patterns. However, it explicitly does not support `vector-effect`, warns that browser fonts must be
registered before conversion because it does not wait for asynchronous loading, warns that bugs
remain, and has not received a commit since August 2022.
[Official repository and support table](https://github.com/alafr/SVG-to-PDFKit),
[official commit history](https://github.com/alafr/SVG-to-PDFKit/commits/master/)
It is therefore not a sensible replacement for `svg2pdf.js`. It changes the converter without
removing the converter boundary.
### 7. Canvg raster fallback
Canvg parses SVG and renders it to Canvas; its stated purpose includes SVG rasterization.
[Official repository](https://github.com/canvg/canvg),
[official API](https://canvg.js.org/api)
Rendering the plan at high device-pixel density and embedding the canvas as PNG would make missing
text unlikely after `document.fonts.ready`, because the browser/canvas has already converted the
glyphs to pixels. It is an acceptable emergency fallback or diagnostic control. It does not meet the
core deliverable: dimension text is not selectable, all geometry becomes raster, thin lines depend
on export resolution, and large plans produce larger PDFs.
## Proposed implementation sequence
If implementation is approved, use this order:
1. Add a library-independent PDF display list or visitor over `FloorplanGeometry`.
2. Implement dimensions first: lines, ticks, background plates, and native text.
3. Embed one exact non-variable TTF font and wait for/load it explicitly.
4. Preserve all document sizes in PDF points; do not use CSS pixels for line weights.
5. Keep the existing SVG conversion only for unported geometry during the transition.
6. Add structural tests that inspect the generated PDF for expected text strings and page count.
7. Add fixture coverage for horizontal, vertical, diagonal, rotated-plan, short/outside-label,
metric, and imperial dimensions.
8. Only after the annotation path is proven, decide whether to port the remaining geometry and
remove `svg2pdf.js`.
For a mandated new library, substitute a direct PDFKit backend at steps 25 and port geometry kinds
incrementally. Do not introduce `SVG-to-PDFKit` as an intermediate layer.
## Acceptance criteria for the eventual implementation
- Every dimension value in the source geometry is present as extractable text in the generated PDF.
- Horizontal, vertical, and diagonal values remain readable at plan rotations of 0°, 45°, 90°, and
arbitrary building rotations.
- Dimension lines render at an explicit target such as 0.5 pt and ticks at 0.75 pt regardless of
plan scale.
- The chosen font is embedded or a deliberate standard PDF font is used.
- Label backing plates are drawn before text and do not obscure glyphs.
- Text extraction verifies representative metric and imperial labels.
- Geometry remains vector except for explicitly documented raster-only assets.
## Primary sources
- [jsPDF repository](https://github.com/parallax/jsPDF)
- [jsPDF documentation](https://parallax.github.io/jsPDF/docs/index.html)
- [jsPDF source/API documentation](https://parallax.github.io/jsPDF/docs/jspdf.js.html)
- [`svg2pdf.js` repository](https://github.com/yWorks/svg2pdf.js)
- [`svg2pdf.js` releases](https://github.com/yWorks/svg2pdf.js/releases)
- [PDFKit repository](https://github.com/foliojs/pdfkit)
- [PDFKit browser setup](https://pdfkit.org/docs/getting_started.html)
- [PDFKit vector graphics](https://pdfkit.org/docs/vector.html)
- [PDFKit text and fonts](https://pdfkit.org/docs/text.html)
- [PDFKit releases](https://github.com/foliojs/pdfkit/releases)
- [React-pdf components](https://react-pdf.org/components)
- [React-pdf SVG primitives](https://react-pdf.org/svg)
- [React-pdf fonts](https://react-pdf.org/fonts)
- [React-pdf releases](https://github.com/diegomura/react-pdf/releases)
- [`pdf-lib` documentation](https://pdf-lib.js.org/)
- [`pdf-lib` `PDFPage` API](https://pdf-lib.js.org/docs/api/classes/pdfpage)
- [`pdf-lib` repository](https://github.com/Hopding/pdf-lib)
- [`SVG-to-PDFKit` repository](https://github.com/alafr/SVG-to-PDFKit)
- [Canvg repository](https://github.com/canvg/canvg)
- [Puppeteer PDF generation](https://pptr.dev/guides/pdf-generation)
- [Puppeteer PDF options](https://pptr.dev/api/puppeteer.pdfoptions)
- [MDN printing guide](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Media_queries/Printing)