@pascal-app/editor 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/package.json +11 -9
  2. package/src/components/editor/action-menu-button.tsx +83 -0
  3. package/src/components/editor/bake-thumbnail.tsx +315 -4
  4. package/src/components/editor/capture-level-picker.tsx +72 -0
  5. package/src/components/editor/custom-camera-controls.tsx +202 -57
  6. package/src/components/editor/delete-confirmation-dialog.tsx +297 -7
  7. package/src/components/editor/duplicate-node.ts +244 -0
  8. package/src/components/editor/editor-layout-mobile.tsx +36 -25
  9. package/src/components/editor/editor-layout-v2.tsx +131 -58
  10. package/src/components/editor/export-manager.tsx +34 -8
  11. package/src/components/editor/first-person/build-collider-world.test.ts +51 -0
  12. package/src/components/editor/first-person/build-collider-world.ts +6 -2
  13. package/src/components/editor/first-person/mechanism-targets.test.ts +75 -0
  14. package/src/components/editor/first-person/mechanism-targets.ts +36 -0
  15. package/src/components/editor/first-person-controls.tsx +205 -2
  16. package/src/components/editor/floating-action-menu.tsx +63 -207
  17. package/src/components/editor/floor-aware-camera-controls.test.ts +442 -0
  18. package/src/components/editor/floor-aware-camera-controls.ts +324 -0
  19. package/src/components/editor/floor-openings-overlay.tsx +243 -0
  20. package/src/components/editor/floor-region-controls.tsx +846 -0
  21. package/src/components/editor/floor-region-webgpu-materials.test.ts +12 -0
  22. package/src/components/editor/floor-surface.test.ts +165 -0
  23. package/src/components/editor/floor-surface.ts +182 -0
  24. package/src/components/editor/floorplan-background-selection.test.ts +11 -2
  25. package/src/components/editor/floorplan-background-selection.ts +1 -3
  26. package/src/components/editor/floorplan-panel.tsx +344 -342
  27. package/src/components/editor/footprint-height-handle.tsx +204 -0
  28. package/src/components/editor/group-actions.ts +54 -2
  29. package/src/components/editor/handles/handle-hit-priority.test.tsx +63 -0
  30. package/src/components/editor/handles/handle-hit-priority.tsx +37 -0
  31. package/src/components/editor/handles/swallow-next-click.test.ts +28 -0
  32. package/src/components/editor/handles/use-handle-drag.ts +269 -197
  33. package/src/components/editor/index.tsx +294 -169
  34. package/src/components/editor/join-walls-pill.tsx +44 -0
  35. package/src/components/editor/node-action-menu.tsx +68 -70
  36. package/src/components/editor/node-arrow-handles.tsx +25 -6
  37. package/src/components/editor/open-wall-ends-3d-layer.tsx +273 -0
  38. package/src/components/editor/open-wall-ends-hint.tsx +89 -0
  39. package/src/components/editor/quick-measurement-hud.tsx +3 -2
  40. package/src/components/editor/registry-action-contributions.test.tsx +63 -0
  41. package/src/components/editor/registry-action-contributions.tsx +80 -1
  42. package/src/components/editor/room-controls.tsx +847 -0
  43. package/src/components/editor/room-floor-highlight.tsx +128 -0
  44. package/src/components/editor/room-handles-2d.tsx +354 -0
  45. package/src/components/editor/room-handles.tsx +675 -0
  46. package/src/components/editor/room-highlight.tsx +225 -0
  47. package/src/components/editor/room-labels.test.ts +357 -0
  48. package/src/components/editor/room-labels.tsx +990 -0
  49. package/src/components/editor/room-transform-ghost.tsx +256 -0
  50. package/src/components/editor/room-webgpu-materials.test.ts +27 -0
  51. package/src/components/editor/selection-manager.tsx +451 -317
  52. package/src/components/editor/slab-hole-highlights.tsx +3 -0
  53. package/src/components/editor/snapshot-capture-overlay.tsx +4 -0
  54. package/src/components/editor/snapshot-capture.test.ts +52 -4
  55. package/src/components/editor/snapshot-capture.ts +30 -5
  56. package/src/components/editor/thumbnail-generator.test.ts +308 -0
  57. package/src/components/editor/thumbnail-generator.tsx +1035 -229
  58. package/src/components/editor/use-floorplan-background-placement.ts +31 -11
  59. package/src/components/editor/vector-edge-extractor.tsx +121 -0
  60. package/src/components/editor/views/host-view.tsx +61 -0
  61. package/src/components/editor/views/plugins-view.tsx +670 -0
  62. package/src/components/editor/views/scene-region.tsx +59 -0
  63. package/src/components/editor/views/use-editor-views.ts +57 -0
  64. package/src/components/editor/views/view-bar.tsx +220 -0
  65. package/src/components/editor/wall-justification.test.ts +140 -0
  66. package/src/components/editor/wall-move-side-handles.tsx +43 -142
  67. package/src/components/editor/wall-push-arrow.tsx +92 -0
  68. package/src/components/editor/wall-region-handles.tsx +509 -0
  69. package/src/components/editor/wall-snap-beacon-layer.tsx +3 -0
  70. package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +8 -4
  71. package/src/components/editor-2d/floorplan-open-wall-ends-layer.test.tsx +86 -0
  72. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +290 -0
  73. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +11 -1
  74. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +113 -102
  75. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.test.ts +156 -0
  76. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +278 -0
  77. package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +77 -0
  78. package/src/components/editor-2d/renderers/{floorplan-draft-wall-measurement.tsx → floorplan-draft-measurement.tsx} +8 -8
  79. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +4 -1
  80. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +38 -8
  81. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +291 -227
  82. package/src/components/editor-2d/svg-paths.ts +12 -15
  83. package/src/components/procedural-items/inspector.tsx +40 -15
  84. package/src/components/systems/ceiling/ceiling-selection-affordance-system.test.ts +97 -14
  85. package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +18 -18
  86. package/src/components/systems/zone/zone-system.test.ts +47 -0
  87. package/src/components/systems/zone/zone-system.tsx +29 -68
  88. package/src/components/tools/item/placement-history.test.tsx +474 -0
  89. package/src/components/tools/item/placement-strategies.ts +8 -4
  90. package/src/components/tools/item/use-draft-node.test.tsx +432 -1
  91. package/src/components/tools/item/use-draft-node.ts +166 -95
  92. package/src/components/tools/item/use-placement-coordinator.tsx +93 -46
  93. package/src/components/tools/paint-region/use-paint-tint.ts +37 -0
  94. package/src/components/tools/paint-region/wall-paint-region-tool.tsx +466 -0
  95. package/src/components/tools/registry/move-registry-node-tool.tsx +3 -1
  96. package/src/components/tools/select/box-select-tool.tsx +2 -12
  97. package/src/components/tools/select/plane-box-select-tool.test.tsx +79 -0
  98. package/src/components/tools/select/plane-box-select-tool.tsx +35 -22
  99. package/src/components/tools/select/select-candidates.test.ts +37 -4
  100. package/src/components/tools/select/select-candidates.ts +15 -11
  101. package/src/components/tools/shared/cursor-sphere.tsx +36 -12
  102. package/src/components/tools/site/site-boundary-editor.tsx +1 -2
  103. package/src/components/tools/stair/stair-defaults.ts +0 -3
  104. package/src/components/tools/stair/stair-tool.tsx +90 -42
  105. package/src/components/tools/tool-manager.tsx +46 -20
  106. package/src/components/tools/wall/wall-drafting.test.ts +19 -4
  107. package/src/components/tools/zone/zone-tool.tsx +4 -12
  108. package/src/components/ui/action-menu/action-button.tsx +3 -0
  109. package/src/components/ui/action-menu/camera-actions.tsx +2 -1
  110. package/src/components/ui/action-menu/control-modes.tsx +2 -35
  111. package/src/components/ui/action-menu/measurement-control.tsx +3 -10
  112. package/src/components/ui/build-panel/build-panel.tsx +235 -0
  113. package/src/components/ui/command-palette/editor-commands.tsx +4 -30
  114. package/src/components/ui/command-palette/index.tsx +5 -24
  115. package/src/components/ui/controls/finish-swatch.tsx +110 -0
  116. package/src/components/ui/controls/material-paint-panel.tsx +97 -26
  117. package/src/components/ui/controls/material-picker.tsx +4 -1
  118. package/src/components/ui/controls/scene-material-list.tsx +4 -32
  119. package/src/components/ui/controls/select-control.tsx +65 -0
  120. package/src/components/ui/floating-level-selector.tsx +9 -14
  121. package/src/components/ui/helpers/building-helper.tsx +4 -1
  122. package/src/components/ui/helpers/contextual-helper-panel.tsx +154 -70
  123. package/src/components/ui/helpers/helper-manager.test.tsx +69 -0
  124. package/src/components/ui/helpers/helper-manager.tsx +325 -14
  125. package/src/components/ui/helpers/item-helper.tsx +8 -0
  126. package/src/components/ui/helpers/registered-tool-helper.tsx +8 -1
  127. package/src/components/ui/icon-ref.tsx +45 -1
  128. package/src/components/ui/level-duplicate-dialog.tsx +1 -1
  129. package/src/components/ui/node-icon-image.tsx +16 -0
  130. package/src/components/ui/panels/collections/collections-popover.tsx +20 -14
  131. package/src/components/ui/panels/floor-foundation-panel.tsx +551 -0
  132. package/src/components/ui/panels/floor-opening-panel.tsx +143 -0
  133. package/src/components/ui/panels/mobile-panel-sheet.tsx +2 -2
  134. package/src/components/ui/panels/mobile-selection-bar.tsx +2 -2
  135. package/src/components/ui/panels/multi-field-value.test.ts +26 -3
  136. package/src/components/ui/panels/multi-field-value.ts +6 -3
  137. package/src/components/ui/panels/multi-parametric-inspector.tsx +52 -2
  138. package/src/components/ui/panels/multi-selection-panel.tsx +43 -4
  139. package/src/components/ui/panels/node-display.ts +8 -3
  140. package/src/components/ui/panels/panel-manager.tsx +103 -68
  141. package/src/components/ui/panels/panel-wrapper.tsx +78 -36
  142. package/src/components/ui/panels/parametric-field-control.tsx +1 -1
  143. package/src/components/ui/panels/parametric-inspector.tsx +4 -4
  144. package/src/components/ui/panels/reference-panel.tsx +2 -3
  145. package/src/components/ui/panels/room-construction-rows.tsx +774 -0
  146. package/src/components/ui/panels/room-name-options.test.ts +55 -0
  147. package/src/components/ui/panels/room-name-options.ts +47 -0
  148. package/src/components/ui/panels/room-openings-field.tsx +110 -0
  149. package/src/components/ui/panels/room-panel.tsx +725 -0
  150. package/src/components/ui/panels/shape-choice.tsx +58 -0
  151. package/src/components/ui/panels/wall-region-list.tsx +109 -0
  152. package/src/components/ui/primitives/color-dot.tsx +36 -24
  153. package/src/components/ui/primitives/sidebar.tsx +2 -0
  154. package/src/components/ui/right-stack.test.ts +29 -0
  155. package/src/components/ui/right-stack.tsx +145 -0
  156. package/src/components/ui/sidebar/icon-rail.tsx +5 -0
  157. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +31 -4
  158. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +5 -5
  159. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -4
  160. package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +1 -5
  161. package/src/components/ui/sidebar/panels/site-panel/collection-tree-node.tsx +197 -0
  162. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -5
  163. package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +1 -5
  164. package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +1 -5
  165. package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -5
  166. package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +24 -11
  167. package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +1 -5
  168. package/src/components/ui/sidebar/panels/site-panel/index.tsx +176 -211
  169. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +30 -8
  170. package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +1 -3
  171. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +4 -1
  172. package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +1 -3
  173. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +1 -4
  174. package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +1 -3
  175. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +21 -13
  176. package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +1 -5
  177. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -5
  178. package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +1 -5
  179. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +0 -27
  180. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -3
  181. package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -5
  182. package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +1 -5
  183. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +9 -4
  184. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +0 -2
  185. package/src/components/ui/sidebar/tab-bar.tsx +10 -0
  186. package/src/components/ui/sidebar/use-plugin-panels.tsx +15 -5
  187. package/src/components/viewer/floorplan-compass-button.tsx +9 -1
  188. package/src/components/viewer/floorplan-preview.tsx +5 -6
  189. package/src/components/viewer/viewer-hover-label.tsx +34 -0
  190. package/src/components/viewer/viewer-rooms.tsx +175 -0
  191. package/src/components/viewer/viewer-scene-header.tsx +181 -145
  192. package/src/components/viewer/viewer-selection-manager.tsx +124 -0
  193. package/src/components/viewer/viewer-stage.tsx +2 -2
  194. package/src/components/viewer-zone-system.tsx +3 -8
  195. package/src/hooks/use-auto-save.integration.test.tsx +123 -9
  196. package/src/hooks/use-auto-save.ts +34 -8
  197. package/src/hooks/use-keyboard.test.ts +178 -3
  198. package/src/hooks/use-keyboard.ts +89 -71
  199. package/src/hooks/use-open-wall-ends.test.ts +99 -0
  200. package/src/hooks/use-open-wall-ends.ts +238 -0
  201. package/src/hooks/use-placement-notice.test.ts +48 -0
  202. package/src/hooks/use-placement-notice.ts +42 -0
  203. package/src/hooks/use-selected-room.ts +143 -0
  204. package/src/index.tsx +246 -39
  205. package/src/lib/ceiling-edit-session.test.ts +321 -0
  206. package/src/lib/ceiling-edit-session.ts +206 -0
  207. package/src/lib/ceiling-region-session.test.ts +179 -0
  208. package/src/lib/continuation.test.ts +19 -1
  209. package/src/lib/continuation.ts +25 -4
  210. package/src/lib/door-interaction.ts +14 -0
  211. package/src/lib/editor-level-display.test.ts +96 -0
  212. package/src/lib/editor-level-display.ts +48 -0
  213. package/src/lib/editor-views.ts +144 -0
  214. package/src/lib/export-geometry-wait.test.ts +90 -0
  215. package/src/lib/floor-edit-session.ts +153 -0
  216. package/src/lib/floor-footprints.test.ts +563 -0
  217. package/src/lib/floor-footprints.ts +395 -0
  218. package/src/lib/floor-foundation-support.test.ts +283 -0
  219. package/src/lib/floor-opening-draft.ts +218 -0
  220. package/src/lib/floor-openings.test.ts +216 -0
  221. package/src/lib/floor-region-geometry.ts +191 -0
  222. package/src/lib/floor-region-session.test.ts +485 -0
  223. package/src/lib/floor-region-session.ts +589 -0
  224. package/src/lib/floor-region-snap.ts +101 -0
  225. package/src/lib/floor-step-hover.test.ts +32 -0
  226. package/src/lib/floorplan/annotation-visibility.ts +17 -0
  227. package/src/lib/floorplan/dimension-drive.test.ts +360 -0
  228. package/src/lib/floorplan/dimension-drive.ts +479 -0
  229. package/src/lib/floorplan/floorplan-export.test.ts +12 -8
  230. package/src/lib/floorplan/floorplan-export.tsx +32 -8
  231. package/src/lib/floorplan/floorplan-extension.ts +32 -0
  232. package/src/lib/floorplan/floorplan-mode.test.ts +4 -0
  233. package/src/lib/floorplan/floorplan-mode.ts +2 -0
  234. package/src/lib/floorplan/floorplan-pdfkit-document.ts +339 -18
  235. package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +138 -8
  236. package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +56 -25
  237. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +138 -0
  238. package/src/lib/floorplan/floorplan-readonly.ts +6 -0
  239. package/src/lib/floorplan/geometry.ts +13 -6
  240. package/src/lib/floorplan/index.ts +0 -9
  241. package/src/lib/floorplan/items.ts +5 -2
  242. package/src/lib/floorplan/marks.test.ts +213 -0
  243. package/src/lib/floorplan/marks.ts +238 -0
  244. package/src/lib/floorplan/open-wall-ends.test.ts +268 -0
  245. package/src/lib/floorplan/open-wall-ends.ts +162 -0
  246. package/src/lib/floorplan/pdf-fonts/GeistMono-Bold.ttf +0 -0
  247. package/src/lib/floorplan/pdf-fonts/GeistMono-Regular.ttf +0 -0
  248. package/src/lib/floorplan/pdf-fonts/LICENSE-GeistMono.txt +92 -0
  249. package/src/lib/floorplan/pdf-fonts/LICENSE-LiberationSans.txt +102 -0
  250. package/src/lib/floorplan/pdf-fonts/LiberationSans-Bold.ttf +0 -0
  251. package/src/lib/floorplan/pdf-fonts/LiberationSans-Regular.ttf +0 -0
  252. package/src/lib/floorplan/schedules.test.ts +189 -0
  253. package/src/lib/floorplan/schedules.ts +339 -0
  254. package/src/lib/floorplan/sheet-export.test.ts +100 -0
  255. package/src/lib/floorplan/sheet-export.ts +318 -0
  256. package/src/lib/floorplan/site-plan/build-site-plan-drawing.ts +779 -0
  257. package/src/lib/floorplan/site-plan/contours.test.ts +43 -0
  258. package/src/lib/floorplan/site-plan/contributors.ts +97 -0
  259. package/src/lib/floorplan/site-plan/coverage.ts +232 -0
  260. package/src/lib/floorplan/site-plan/drawing-type-switch.test.ts +15 -0
  261. package/src/lib/floorplan/site-plan/drawing-type-switch.tsx +86 -0
  262. package/src/lib/floorplan/site-plan/front-edge.test.ts +103 -0
  263. package/src/lib/floorplan/site-plan/front-edge.ts +156 -0
  264. package/src/lib/floorplan/site-plan/geometry.test.ts +275 -0
  265. package/src/lib/floorplan/site-plan/geometry.ts +557 -0
  266. package/src/lib/floorplan/site-plan/index.ts +71 -0
  267. package/src/lib/floorplan/site-plan/site-annotations.test.ts +366 -0
  268. package/src/lib/floorplan/site-plan/site-annotations.ts +1083 -0
  269. package/src/lib/floorplan/site-plan/site-parts.ts +379 -0
  270. package/src/lib/floorplan/site-plan/site-plan-layer.tsx +138 -0
  271. package/src/lib/floorplan/site-plan/street-name.test.ts +69 -0
  272. package/src/lib/floorplan/site-plan/street-name.ts +302 -0
  273. package/src/lib/floorplan/site-plan/yards.test.ts +69 -0
  274. package/src/lib/floorplan/types.ts +1 -27
  275. package/src/lib/fresh-planar-placement.test.ts +36 -0
  276. package/src/lib/fresh-planar-placement.ts +59 -36
  277. package/src/lib/geometry-script/author.ts +152 -0
  278. package/src/lib/geometry-script/client.ts +152 -0
  279. package/src/lib/geometry-script/protocol.ts +12 -0
  280. package/src/lib/gesture-lifecycle.test.ts +595 -0
  281. package/src/lib/gesture-lifecycle.ts +290 -0
  282. package/src/lib/glb-export-zone-holes.test.ts +41 -0
  283. package/src/lib/glb-export.test.ts +485 -0
  284. package/src/lib/glb-export.ts +237 -119
  285. package/src/lib/history.test.ts +6 -0
  286. package/src/lib/history.ts +7 -0
  287. package/src/lib/hud-title.ts +109 -0
  288. package/src/lib/hydration-gated-storage.ts +49 -0
  289. package/src/lib/ifc-export.test.ts +174 -0
  290. package/src/lib/ifc-export.ts +201 -0
  291. package/src/lib/ifc-parts.ts +15 -0
  292. package/src/lib/inspector-expanded.test.ts +44 -0
  293. package/src/lib/inspector-expanded.ts +36 -0
  294. package/src/lib/interaction/scope.ts +18 -0
  295. package/src/lib/keyboard-pan.test.ts +129 -7
  296. package/src/lib/keyboard-pan.ts +161 -12
  297. package/src/lib/live-gesture-round-trip.test.ts +360 -0
  298. package/src/lib/lot/__fixtures__/map-dossier-miami-shores.json +1 -0
  299. package/src/lib/lot/__fixtures__/map-dossier-stpete.json +1 -0
  300. package/src/lib/lot/clean-ring.test.ts +186 -0
  301. package/src/lib/lot/clean-ring.ts +217 -0
  302. package/src/lib/lot/dossier.test.ts +202 -0
  303. package/src/lib/lot/dossier.ts +498 -0
  304. package/src/lib/lot/drop-in.test.ts +326 -0
  305. package/src/lib/lot/drop-in.ts +407 -0
  306. package/src/lib/lot/index.ts +43 -0
  307. package/src/lib/lot/lot-patch.test.ts +340 -0
  308. package/src/lib/lot/lot-patch.ts +394 -0
  309. package/src/lib/lot/parcel-provider.ts +43 -0
  310. package/src/lib/lot/terrain.test.ts +161 -0
  311. package/src/lib/lot/terrain.ts +266 -0
  312. package/src/lib/material-catalog-model.ts +3 -1
  313. package/src/lib/material-paint-panel-model.ts +9 -5
  314. package/src/lib/material-paint.ts +4 -0
  315. package/src/lib/mezzanine-actions.test.ts +342 -0
  316. package/src/lib/mezzanine-draft.test.ts +501 -0
  317. package/src/lib/mezzanine-draft.ts +278 -0
  318. package/src/lib/mezzanine-messages.ts +26 -0
  319. package/src/lib/mezzanine-selection.test.ts +207 -0
  320. package/src/lib/mezzanine-stairs.ts +46 -0
  321. package/src/lib/model-export.ts +3 -1
  322. package/src/lib/node-action-movement.ts +17 -6
  323. package/src/lib/node-display-label.ts +37 -0
  324. package/src/lib/orbit-floor-clearance.test.ts +165 -0
  325. package/src/lib/orbit-floor-clearance.ts +106 -0
  326. package/src/lib/paint-commit-route.test.ts +37 -0
  327. package/src/lib/paint-commit-route.ts +17 -0
  328. package/src/lib/paint-eyedropper.test.tsx +165 -0
  329. package/src/lib/paint-eyedropper.ts +99 -0
  330. package/src/lib/paint-pass-through.test.ts +111 -0
  331. package/src/lib/paint-pass-through.ts +76 -0
  332. package/src/lib/paint-region-hover.ts +25 -0
  333. package/src/lib/paint-region-mode.ts +154 -0
  334. package/src/lib/paint-regions.test.ts +166 -0
  335. package/src/lib/paint-regions.ts +192 -0
  336. package/src/lib/paint-scope.test.ts +317 -35
  337. package/src/lib/paint-scope.ts +266 -25
  338. package/src/lib/panel-rows.ts +21 -0
  339. package/src/lib/parametric-node-update.ts +1 -1
  340. package/src/lib/plate-paint-affected.test.ts +300 -0
  341. package/src/lib/plate-paint-affected.ts +177 -0
  342. package/src/lib/plugin-chat.ts +50 -0
  343. package/src/lib/plugin-panels.test.ts +25 -0
  344. package/src/lib/plugin-panels.ts +94 -0
  345. package/src/lib/print-shell-compiler.ts +1 -0
  346. package/src/lib/registered-draft-snap.ts +12 -0
  347. package/src/lib/roof-duplication.ts +10 -2
  348. package/src/lib/room-assembly-overlay.test.ts +275 -0
  349. package/src/lib/room-assembly-overlay.ts +266 -0
  350. package/src/lib/room-built-on.test.ts +379 -0
  351. package/src/lib/room-built-on.ts +138 -0
  352. package/src/lib/room-construction-commands.ts +712 -0
  353. package/src/lib/room-construction.test.ts +746 -0
  354. package/src/lib/room-construction.ts +385 -0
  355. package/src/lib/room-controls-phase6.test.ts +630 -0
  356. package/src/lib/room-divide-session.ts +523 -0
  357. package/src/lib/room-handle-drag.ts +1068 -0
  358. package/src/lib/room-name-catalog.test.ts +90 -0
  359. package/src/lib/room-name-catalog.ts +168 -0
  360. package/src/lib/room-push-dimensions.test.ts +311 -0
  361. package/src/lib/room-push-dimensions.ts +251 -0
  362. package/src/lib/room-selection-commands.ts +62 -0
  363. package/src/lib/room-selection.test.ts +973 -0
  364. package/src/lib/room-selection.ts +417 -0
  365. package/src/lib/room-structure-commands.ts +94 -0
  366. package/src/lib/room-structure.test.ts +921 -0
  367. package/src/lib/room-transform-session.ts +570 -0
  368. package/src/lib/room-zone-routing.test.ts +294 -0
  369. package/src/lib/room-zone-routing.ts +197 -0
  370. package/src/lib/scene-clipboard.test.ts +364 -0
  371. package/src/lib/scene-clipboard.ts +229 -48
  372. package/src/lib/scene-material-refs.test.ts +79 -0
  373. package/src/lib/scene-material-refs.ts +79 -0
  374. package/src/lib/scene.test.ts +24 -36
  375. package/src/lib/scene.ts +33 -57
  376. package/src/lib/selection-routing.test.ts +129 -45
  377. package/src/lib/selection-routing.ts +53 -74
  378. package/src/lib/session-writes.test.ts +120 -0
  379. package/src/lib/session-writes.ts +205 -0
  380. package/src/lib/sidebar-panel.ts +62 -0
  381. package/src/lib/site-boundary.test.ts +4 -6
  382. package/src/lib/site-boundary.ts +1 -1
  383. package/src/lib/snapping-mode.test.ts +4 -0
  384. package/src/lib/snapping-mode.ts +8 -1
  385. package/src/lib/terrace-draft.test.ts +145 -0
  386. package/src/lib/terrace-draft.ts +213 -0
  387. package/src/lib/tool-cursor-icon.test.ts +16 -0
  388. package/src/lib/tool-cursor-icon.ts +11 -0
  389. package/src/lib/typing-target.ts +9 -0
  390. package/src/lib/units.ts +77 -39
  391. package/src/lib/vector-edges.test.ts +58 -0
  392. package/src/lib/vector-edges.ts +400 -0
  393. package/src/lib/viewer-selection.test.ts +577 -0
  394. package/src/lib/viewer-selection.ts +569 -0
  395. package/src/lib/wall-draw-variant.test.ts +71 -0
  396. package/src/lib/wall-draw-variant.ts +91 -0
  397. package/src/lib/wall-paint-region-session.ts +246 -0
  398. package/src/lib/wall-paint-region.test.ts +373 -0
  399. package/src/lib/wall-polygon-draft.test.ts +262 -0
  400. package/src/lib/wall-polygon-draft.ts +286 -0
  401. package/src/lib/wall-push.test.ts +453 -0
  402. package/src/lib/wall-region-face.ts +352 -0
  403. package/src/lib/wall-region-handles.test.ts +304 -0
  404. package/src/lib/wall-region-handles.ts +368 -0
  405. package/src/lib/wall-region-list.test.ts +119 -0
  406. package/src/lib/wall-region-list.ts +136 -0
  407. package/src/lib/wall-region-snap.ts +110 -0
  408. package/src/lib/window-interaction.ts +14 -0
  409. package/src/lib/zone-content.ts +4 -1
  410. package/src/lib/zone-name.test.ts +17 -0
  411. package/src/lib/zone-name.ts +17 -0
  412. package/src/store/opens-in-select-mode.test.ts +223 -0
  413. package/src/store/paint-mode.test.ts +188 -0
  414. package/src/store/terrain-sculpt-mode.test.ts +19 -21
  415. package/src/store/tool-mode.test.ts +137 -6
  416. package/src/store/use-delete-confirmation.ts +28 -1
  417. package/src/store/use-drawing-view.test.ts +24 -3
  418. package/src/store/use-drawing-view.ts +29 -1
  419. package/src/store/use-editor.tsx +432 -321
  420. package/src/store/use-floorplan-draft-preview.ts +13 -0
  421. package/src/store/use-floorplan-marquee.ts +12 -2
  422. package/src/store/use-quick-measurement-hud.ts +3 -3
  423. package/src/store/use-stair-build-preview.ts +13 -5
  424. package/src/store/use-wall-move-ghosts.ts +4 -2
  425. package/src/store/use-wall-region-handles-selection.test.ts +222 -0
  426. package/src/store/use-wall-region-handles-selection.ts +139 -0
  427. package/src/store/view-layout.test.ts +175 -0
  428. package/src/store/view-layout.ts +196 -0
  429. package/src/test-utils/immediate-animation-frames.ts +16 -0
  430. package/src/test-utils/live-gesture-round-trip.ts +224 -0
  431. package/src/test-utils/selection-harness.ts +82 -0
  432. package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +0 -499
  433. package/src/components/systems/zone/zone-label-editor-system.tsx +0 -333
  434. package/src/components/tools/fence/fence-drafting.test.ts +0 -100
  435. package/src/components/tools/fence/fence-drafting.ts +0 -266
  436. package/src/components/ui/sidebar/panels/plugins-panel.tsx +0 -218
  437. package/src/components/viewer/viewer-units-panel.tsx +0 -116
  438. package/src/lib/floorplan/stairs.ts +0 -489
  439. package/src/lib/level-duplication.test.ts +0 -144
  440. package/src/lib/level-duplication.ts +0 -195
@@ -0,0 +1,42 @@
1
+ import {
2
+ type AnyNode,
3
+ type AnyNodeId,
4
+ type LiveTransformLike,
5
+ nodeRegistry,
6
+ type PlacementNotice,
7
+ useLiveTransforms,
8
+ useScene,
9
+ } from '@pascal-app/core'
10
+ import { useMemo } from 'react'
11
+
12
+ /** The notice `nodeId`'s kind gives for where it stands (`placementNotice`), if it declares one. */
13
+ export function placementNoticeOf(
14
+ nodes: Readonly<Record<string, AnyNode>>,
15
+ nodeId: string,
16
+ live?: LiveTransformLike,
17
+ ): PlacementNotice | null {
18
+ const node = nodes[nodeId as AnyNodeId]
19
+ const notice = node ? nodeRegistry.get(node.type)?.placementNotice : undefined
20
+ if (!(node && notice)) return null
21
+ return notice(node as never, live ? { nodes, live } : { nodes })
22
+ }
23
+
24
+ /**
25
+ * What the node in hand, or the selected node, says about where it stands, read at its live pose
26
+ * while it is placed or moved. Subscribes to the scene only while a node is given, so an
27
+ * always-mounted caller doesn't re-render on every write.
28
+ */
29
+ export function usePlacementNotice(nodeId: string | null | undefined): PlacementNotice | null {
30
+ const nodes = useScene((state) => (nodeId ? state.nodes : null))
31
+ const live = useLiveTransforms((state) => (nodeId ? state.get(nodeId) : undefined))
32
+ return useMemo(
33
+ () => (nodeId && nodes ? placementNoticeOf(nodes, nodeId, live) : null),
34
+ [nodes, live, nodeId],
35
+ )
36
+ }
37
+
38
+ /** The node a construction tool is placing: its transient draft. */
39
+ export const transientDraftId = (nodes: Readonly<Record<string, AnyNode>>) =>
40
+ Object.values(nodes).find(
41
+ (node) => !!(node.metadata as { isTransient?: boolean } | null)?.isTransient,
42
+ )?.id ?? null
@@ -0,0 +1,143 @@
1
+ 'use client'
2
+
3
+ import { type AnyNode, type AnyNodeId, useScene } from '@pascal-app/core'
4
+ import { useViewer } from '@pascal-app/viewer'
5
+ import { useCallback, useSyncExternalStore } from 'react'
6
+ import { selectionEnabled } from '../lib/interaction/scope'
7
+ import {
8
+ type RoomKey,
9
+ RoomSelectionIndex,
10
+ type RoomSelectionRecord,
11
+ resolveRoomHit,
12
+ } from '../lib/room-selection'
13
+ import { shouldInterceptRoom } from '../lib/room-selection-commands'
14
+ import { type SelectionModifierKeys, selectionModifiersFromEvent } from '../lib/selection-routing'
15
+ import useEditor from '../store/use-editor'
16
+ import useInteractionScope from '../store/use-interaction-scope'
17
+
18
+ const indexes = new Map<string, RoomSelectionIndex>()
19
+ const subscriptions = new Map<string, { listeners: Set<() => void>; dispose: () => void }>()
20
+ const EMPTY: RoomSelectionRecord[] = []
21
+
22
+ export function getRoomSelectionIndex(levelId: string) {
23
+ let index = indexes.get(levelId)
24
+ if (!index) {
25
+ index = new RoomSelectionIndex(levelId)
26
+ indexes.set(levelId, index)
27
+ }
28
+ index.update(useScene.getState().nodes)
29
+ return index
30
+ }
31
+
32
+ function subscribeLevel(levelId: string | null, listener: () => void) {
33
+ if (!levelId) return () => {}
34
+ let subscription = subscriptions.get(levelId)
35
+ if (!subscription) {
36
+ const listeners = new Set<() => void>()
37
+ const dispose = useScene.subscribe((state, previous) => {
38
+ if (state.nodes === previous.nodes) return
39
+ const rooms = getRoomSelectionIndex(levelId).update(state.nodes)
40
+ const editor = useEditor.getState()
41
+ if (
42
+ editor.room?.levelId === levelId &&
43
+ !rooms.some((room) => room.key.zoneId === editor.room?.zoneId)
44
+ )
45
+ editor.clearRoom()
46
+ for (const notify of listeners) notify()
47
+ })
48
+ subscription = { listeners, dispose }
49
+ subscriptions.set(levelId, subscription)
50
+ }
51
+ subscription.listeners.add(listener)
52
+ return () => {
53
+ subscription.listeners.delete(listener)
54
+ if (!subscription.listeners.size) {
55
+ subscription.dispose()
56
+ subscriptions.delete(levelId)
57
+ indexes.delete(levelId)
58
+ }
59
+ }
60
+ }
61
+
62
+ export function useRoomRecords(levelId: string | null) {
63
+ const subscribe = useCallback((notify: () => void) => subscribeLevel(levelId, notify), [levelId])
64
+ const snapshot = useCallback(
65
+ () => (levelId ? getRoomSelectionIndex(levelId).update(useScene.getState().nodes) : EMPTY),
66
+ [levelId],
67
+ )
68
+ return useSyncExternalStore(subscribe, snapshot, snapshot)
69
+ }
70
+
71
+ export function useSelectedRoom() {
72
+ const key = useEditor((state) => state.room)
73
+ const rooms = useRoomRecords(key?.levelId ?? null)
74
+ return rooms.find((room) => room.key.zoneId === key?.zoneId) ?? null
75
+ }
76
+
77
+ /**
78
+ * The room a selected zone is, for the room panel: its record when the room
79
+ * index knows it, `{ record: null }` for a room the walls do not close, null
80
+ * for anything that is not a room.
81
+ */
82
+ export function useZoneRoom(zoneId: string | null): { record: RoomSelectionRecord | null } | null {
83
+ const levelId = useScene((state) => {
84
+ const zone = zoneId ? state.nodes[zoneId as AnyNodeId] : undefined
85
+ return zone?.type === 'zone' && zone.spaceRole === 'room' ? (zone.parentId ?? null) : null
86
+ })
87
+ const rooms = useRoomRecords(levelId)
88
+ if (!(zoneId && levelId)) return null
89
+ return { record: rooms.find((room) => room.key.zoneId === zoneId) ?? null }
90
+ }
91
+
92
+ export function useHighlightedRoom() {
93
+ const key = useEditor((state) => state.hoveredRoom ?? state.room)
94
+ const rooms = useRoomRecords(key?.levelId ?? null)
95
+ return rooms.find((room) => room.key.zoneId === key?.zoneId) ?? null
96
+ }
97
+
98
+ const hitPoint: [number, number] = [0, 0]
99
+
100
+ export function resolveEditorRoomHit(
101
+ node: AnyNode | null,
102
+ levelId: string,
103
+ point: readonly [number, number],
104
+ view: '2d' | '3d',
105
+ ) {
106
+ if (node && node.type !== 'wall' && node.type !== 'slab' && node.type !== 'ceiling') return null
107
+ const index = getRoomSelectionIndex(levelId)
108
+ hitPoint[0] = point[0]
109
+ hitPoint[1] = point[1]
110
+ const room = resolveRoomHit(index, levelId, node, hitPoint, view)
111
+ return room?.key ?? null
112
+ }
113
+
114
+ /** Rooms pick inside the building; from site a click picks the whole building. */
115
+ export function roomPickingEnabled() {
116
+ const editor = useEditor.getState()
117
+ return (
118
+ editor.phase !== 'site' &&
119
+ editor.mode === 'select' &&
120
+ !useViewer.getState().focusedUnitId &&
121
+ selectionEnabled(useInteractionScope.getState().scope)
122
+ )
123
+ }
124
+
125
+ export function hoverRoomFromHit(
126
+ hit: RoomKey | null,
127
+ modifiers: SelectionModifierKeys,
128
+ nodeId: string | null,
129
+ ) {
130
+ const editor = useEditor.getState()
131
+ const room = shouldInterceptRoom(hit, modifiers, nodeId) ? hit : null
132
+ editor.setHoveredRoom(room)
133
+ if (room) useViewer.getState().setHoveredId(null)
134
+ return !!room
135
+ }
136
+
137
+ export function resolvePlanRoomHit(nodeId: string | null, point: readonly [number, number]) {
138
+ const node = nodeId ? useScene.getState().nodes[nodeId as AnyNodeId] : null
139
+ const levelId = node?.parentId ?? useViewer.getState().selection.levelId
140
+ return levelId ? resolveEditorRoomHit(node ?? null, levelId, point, '2d') : null
141
+ }
142
+
143
+ export { selectionModifiersFromEvent }
package/src/index.tsx CHANGED
@@ -20,13 +20,15 @@ export {
20
20
  export { useViewer } from '@pascal-app/viewer'
21
21
  export type { EditorProps } from './components/editor'
22
22
  export { default as Editor } from './components/editor'
23
+ export { ActionMenuButton } from './components/editor/action-menu-button'
23
24
  // Headless component aliases: the implementation files keep their
24
25
  // internal names (`ParametricInspector`, `FloatingActionMenu`) because
25
26
  // they're referenced throughout the editor's own internals; the public
26
27
  // surface uses the shorter, shell-friendly names from the unified
27
28
  // preset-system spec.
28
29
  export { BakeExporter } from './components/editor/bake-exporter'
29
- export { BakeThumbnail } from './components/editor/bake-thumbnail'
30
+ export { BakeThumbnail, prepareBakeThumbnailLook } from './components/editor/bake-thumbnail'
31
+ export { copyCollectionIds, duplicateNodeAndPickUp } from './components/editor/duplicate-node'
30
32
  export { FirstPersonControls } from './components/editor/first-person-controls'
31
33
  export { FloatingActionMenu as FloatingMenu } from './components/editor/floating-action-menu'
32
34
  // Embed surface — the editor's real in-canvas affordances, so a host can mount
@@ -88,9 +90,9 @@ export { WallMoveSideHandles } from './components/editor/wall-move-side-handles'
88
90
  export { useFloorplanRender } from './components/editor-2d/floorplan-render-context'
89
91
  export { FloorplanDimensionRenderer } from './components/editor-2d/renderers/floorplan-dimension-renderer'
90
92
  export {
91
- type DraftWallMeasurement,
92
- FloorplanDraftWallMeasurement,
93
- } from './components/editor-2d/renderers/floorplan-draft-wall-measurement'
93
+ type DraftMeasurement,
94
+ FloorplanDraftMeasurement,
95
+ } from './components/editor-2d/renderers/floorplan-draft-measurement'
94
96
  export { FloorplanGeometryRenderer } from './components/editor-2d/renderers/floorplan-geometry-renderer'
95
97
  export {
96
98
  FloorplanNodePreview,
@@ -110,16 +112,7 @@ export type {
110
112
  SelectionAffordanceInteractionApi,
111
113
  SelectionAffordanceProps,
112
114
  } from './components/systems/selection-affordance-services'
113
- // Phase 5 Stage D transitional exports — pure drafting / angle helpers
114
- // consumed by kind-owned drag actions in @pascal-app/nodes. Stage F
115
- // cleanup moves these into @pascal-app/nodes (fence/drafting.ts +
116
- // shared/segment-angle.ts) once every Stage D port is in.
117
- export {
118
- createFenceOnCurrentLevel,
119
- createSplineFenceOnCurrentLevel,
120
- type FencePlanPoint,
121
- snapFenceDraftPoint,
122
- } from './components/tools/fence/fence-drafting'
115
+ export { StairEditSystem } from './components/systems/stair/stair-edit-system'
123
116
  export { MoveTool } from './components/tools/item/move-tool'
124
117
  // Placement-math helpers — shared by kind-owned placement tools in
125
118
  // `@pascal-app/nodes` (wall curve sagitta snap, door / window placement,
@@ -194,11 +187,8 @@ export {
194
187
  DEFAULT_SPIRAL_TOP_LANDING_MODE,
195
188
  DEFAULT_STAIR_ATTACHMENT_SIDE,
196
189
  DEFAULT_STAIR_FILL_TO_FLOOR,
197
- DEFAULT_STAIR_HEIGHT,
198
- DEFAULT_STAIR_LENGTH,
199
190
  DEFAULT_STAIR_RAILING_HEIGHT,
200
191
  DEFAULT_STAIR_RAILING_MODE,
201
- DEFAULT_STAIR_STEP_COUNT,
202
192
  DEFAULT_STAIR_THICKNESS,
203
193
  DEFAULT_STAIR_TYPE,
204
194
  DEFAULT_STAIR_WIDTH,
@@ -207,6 +197,7 @@ export { preloadRegistryToolModules, ToolManager } from './components/tools/tool
207
197
  export {
208
198
  chainEndJoinsExistingWall,
209
199
  createWallOnCurrentLevel,
200
+ findWallSnapTarget,
210
201
  getSegmentGridStep,
211
202
  isSegmentLongEnough,
212
203
  resolveEndpointWallSplit,
@@ -222,11 +213,8 @@ export {
222
213
  type WallPlanPoint,
223
214
  type WallSnapRadii,
224
215
  } from './components/tools/wall/wall-drafting'
225
- // `ToolbarLeft` / `ToolbarRight` are the headless-spec aliases for the
226
- // existing `ViewerToolbarLeft` / `ViewerToolbarRight` exports — the
227
- // underlying components are the same; the alias just matches the names
228
- // used in `pascalorg/private-editor:plans/community-preset-system.md`
229
- // so consumer code stays close to the spec vocabulary.
216
+ // `ToolbarLeft` / `ToolbarRight` alias `ViewerToolbarLeft` / `ViewerToolbarRight`
217
+ // (same components) under the names headless hosts compose their toolbars with.
230
218
  export {
231
219
  CameraActions as ToolbarRight,
232
220
  CameraActions as ViewerToolbarRight,
@@ -236,6 +224,14 @@ export {
236
224
  ViewToggles as ToolbarLeft,
237
225
  ViewToggles as ViewerToolbarLeft,
238
226
  } from './components/ui/action-menu/view-toggles'
227
+ // The Build panel's grouped layout, shared by the community and standalone tabs.
228
+ export {
229
+ BuildPanelAdvancedSection,
230
+ BuildPanelRoomsSection,
231
+ BuildPanelSection,
232
+ BuildToolGrid,
233
+ BuildToolTile,
234
+ } from './components/ui/build-panel/build-panel'
239
235
  export { useCommandPalette } from './components/ui/command-palette'
240
236
  export { ActionButton, ActionGroup } from './components/ui/controls/action-button'
241
237
  export {
@@ -250,14 +246,16 @@ export {
250
246
  export { MetricControl } from './components/ui/controls/metric-control'
251
247
  export { PanelSection } from './components/ui/controls/panel-section'
252
248
  export { SegmentedControl } from './components/ui/controls/segmented-control'
249
+ export { SelectControl } from './components/ui/controls/select-control'
253
250
  export { SliderControl } from './components/ui/controls/slider-control'
254
251
  export { TerrainSculptPanel } from './components/ui/controls/terrain-sculpt-panel'
255
252
  export { ToggleControl } from './components/ui/controls/toggle-control'
256
253
  export { ToolOptionsPanel } from './components/ui/controls/tool-options-panel'
257
254
  export { FloatingLevelSelector } from './components/ui/floating-level-selector'
258
255
  export { CATALOG_ITEMS } from './components/ui/item-catalog/catalog-items'
259
- // Item collections UI — used by the kind-owned ItemPanel in nodes/.
260
- export { CollectionsPopover } from './components/ui/panels/collections/collections-popover'
256
+ // A base plate's panel (one connected footprint's floor and foundation); the
257
+ // slab kind's panel hands base plates to it.
258
+ export { FloorFoundationPanel } from './components/ui/panels/floor-foundation-panel'
261
259
  export {
262
260
  resolveHomogeneousSelection,
263
261
  resolveUniqueSelectionIds,
@@ -276,6 +274,8 @@ export { applyMultiHeightMode } from './components/ui/panels/multi-height-mode'
276
274
  // a kind-owned panel and need PanelWrapper for the chrome.
277
275
  export { PanelWrapper } from './components/ui/panels/panel-wrapper'
278
276
  export { ParametricInspector as Inspector } from './components/ui/panels/parametric-inspector'
277
+ export { ShapeChoice } from './components/ui/panels/shape-choice'
278
+ export { WallPaintRegionList } from './components/ui/panels/wall-region-list'
279
279
  export { PALETTE_COLORS } from './components/ui/primitives/color-dot'
280
280
  export {
281
281
  DropdownMenu,
@@ -326,10 +326,13 @@ export {
326
326
  ViewerControlsBar,
327
327
  type ViewerControlsBarProps,
328
328
  } from './components/viewer/viewer-controls-bar'
329
+ export { ViewerHoverLabel } from './components/viewer/viewer-hover-label'
330
+ export { ParametricViewerRooms, ViewerRooms } from './components/viewer/viewer-rooms'
329
331
  export {
330
332
  ViewerSceneHeader,
331
333
  type ViewerSceneHeaderProps,
332
334
  } from './components/viewer/viewer-scene-header'
335
+ export { ViewerSelectionManager } from './components/viewer/viewer-selection-manager'
333
336
  export { ViewerStage, type ViewerStageProps } from './components/viewer/viewer-stage'
334
337
  export {
335
338
  normalizeViewerStageModes,
@@ -343,7 +346,6 @@ export {
343
346
  ViewerStageSwitcher,
344
347
  type ViewerStageSwitcherProps,
345
348
  } from './components/viewer/viewer-stage-switcher'
346
- export { ViewerUnitsPanel } from './components/viewer/viewer-units-panel'
347
349
  export {
348
350
  WalkthroughHud,
349
351
  type WalkthroughHudProps,
@@ -356,7 +358,9 @@ export type { SaveStatus } from './hooks/use-auto-save'
356
358
  export { type UseDragActionArgs, useDragAction } from './hooks/use-drag-action'
357
359
  // Phase 5 Stage D — extras for kind-owned placement tools (FenceTool etc.).
358
360
  export { cancelActiveTool, markToolCancelConsumed } from './hooks/use-keyboard'
361
+ export { usePlacementNotice } from './hooks/use-placement-notice'
359
362
  export { useReducedMotion } from './hooks/use-reduced-motion'
363
+ export { useSelectedRoom } from './hooks/use-selected-room'
360
364
  export { type Selection, useSelection } from './hooks/use-selection'
361
365
  export {
362
366
  clearPlacementSurface,
@@ -369,6 +373,16 @@ export {
369
373
  filterCatalogItems,
370
374
  isCatalogItemSelected,
371
375
  } from './lib/catalog-panel-model'
376
+ export {
377
+ type CeilingEditSession,
378
+ endCeilingEdit,
379
+ exitCeilingEditToRoom,
380
+ getCeilingEditSession,
381
+ setCeilingHoles,
382
+ startCeilingEdit,
383
+ useCeilingEditCeilingId,
384
+ useCeilingEditSession,
385
+ } from './lib/ceiling-edit-session'
372
386
  export {
373
387
  CEILING_ALIGNMENT_THRESHOLD_M,
374
388
  type CeilingPlanSnapInput,
@@ -392,7 +406,18 @@ export {
392
406
  nextContinuation,
393
407
  } from './lib/continuation'
394
408
  export { canDirectMoveNode } from './lib/direct-manipulation'
409
+ export {
410
+ closeDoorOpenState,
411
+ getDisplayedDoorValue,
412
+ openDoorOpenState,
413
+ } from './lib/door-interaction'
395
414
  export { createEditorApi } from './lib/editor-api'
415
+ export {
416
+ type EditorHostView,
417
+ editorHostViewRegistry,
418
+ openEditorView,
419
+ registerEditorHostView,
420
+ } from './lib/editor-views'
396
421
  export {
397
422
  clearStructuralElevationGuide,
398
423
  collectElevationSnapTargets,
@@ -413,30 +438,36 @@ export {
413
438
  } from './lib/elevator-support'
414
439
  export type { ExportTextureUtils } from './lib/export-texture-utils'
415
440
  export { getFloatingMenuScale } from './lib/floating-menu-scale'
416
- // Floor-plan stair helpers — the cumulative-transform walk
417
- // (`computeFloorplanStairSegmentTransforms`) and the rich segment-entry
418
- // builder (`buildFloorplanStairEntry`) used by the kind-owned stair
419
- // floor-plan emitter in `@pascal-app/nodes/src/stair/floorplan.ts`.
420
- // Each flight's transform depends on every prior sibling's length /
421
- // height / `attachmentSide`, so individual stair-segments can't compute
422
- // their own polygon in isolation — the stair (parent) owns the
423
- // computation and emits the whole stack as one registry entry.
441
+ export { startOpeningDraft } from './lib/floor-opening-draft'
424
442
  export {
425
443
  alignFloorplanDraftPoint,
426
444
  applyFloorplanAlignment,
427
- buildFloorplanStairEntry,
445
+ clampPlanValue,
428
446
  FLOORPLAN_ALIGNMENT_THRESHOLD_M,
429
447
  FLOORPLAN_DRAFT_ALIGN_ID,
430
448
  type FloorplanAlignmentResult,
431
- type FloorplanStairArrowEntry,
432
- type FloorplanStairEntry,
433
- type FloorplanStairSegmentEntry,
434
449
  getFloorplanWallThickness,
450
+ getPlanPointDistance,
451
+ getThickPlanLinePolygon,
452
+ interpolatePlanPoint,
453
+ movePlanPointTowards,
454
+ rotatePlanVector,
435
455
  } from './lib/floorplan'
436
456
  export type {
437
457
  FloorplanAnnotationCategory,
438
458
  FloorplanAnnotationVisibility,
439
459
  } from './lib/floorplan/annotation-visibility'
460
+ // Annotations (WS3) — deterministic door/window marks, driving dimensions,
461
+ // and construction-document schedule data.
462
+ export {
463
+ type DimensionDrivePlan,
464
+ type DimensionDriveResolution,
465
+ type DimensionDriveTarget,
466
+ type DimensionPlanPoint,
467
+ parseDimensionInput,
468
+ planDimensionDrive,
469
+ resolveDimensionDrive,
470
+ } from './lib/floorplan/dimension-drive'
440
471
  export {
441
472
  exportFloorplanPdf,
442
473
  type FloorplanExportScope,
@@ -466,11 +497,86 @@ export {
466
497
  type FloorplanMode,
467
498
  isFloorplanToolAvailableInMode,
468
499
  } from './lib/floorplan/floorplan-mode'
500
+ export {
501
+ type MarkResolution,
502
+ type OpeningMarkKind,
503
+ orderedOpenings,
504
+ persistResolvedMarks,
505
+ resolveMarkDetail,
506
+ resolveMarks,
507
+ } from './lib/floorplan/marks'
469
508
  export { clientToPlan } from './lib/floorplan/plan-coords'
509
+ export {
510
+ doorSchedule,
511
+ floorplanSchedules,
512
+ formatScheduleLength,
513
+ type OpeningScheduleRow,
514
+ type RoomScheduleRow,
515
+ roomSchedule,
516
+ type ScheduleResult,
517
+ type ScheduleUnit,
518
+ windowSchedule,
519
+ } from './lib/floorplan/schedules'
520
+ // Sheets — headless floor-plan geometry collection + the multi-sheet vector
521
+ // PDF writer.
522
+ export {
523
+ collectFloorplanSchedules,
524
+ collectSheetGeometry,
525
+ exportSheetsToPdf,
526
+ POINTS_PER_INCH,
527
+ resolveSheetRotationDeg,
528
+ type SheetGeometryEntry,
529
+ type SheetGeometryOptions,
530
+ type SheetPdfPage,
531
+ type SheetPdfWindow,
532
+ } from './lib/floorplan/sheet-export'
533
+ // ── Site plan (WS1) ──────────────────────────────────────────────────
534
+ export {
535
+ boundsInsidePolygon,
536
+ buildingRecentreOffset,
537
+ buildSitePlanDrawing,
538
+ castYardDimensions,
539
+ classifyEdges,
540
+ computeSiteCoverage,
541
+ describeSiteEdges,
542
+ detectFrontEdgeFromRoads,
543
+ FloorplanDrawingTypeSwitch,
544
+ FloorplanSitePlanLayer,
545
+ type FrontEdgeMatch,
546
+ flatworkKindOf,
547
+ formatCoveragePercent,
548
+ formatFeetInches,
549
+ formatSqFt,
550
+ formatStreetName,
551
+ type ImperviousRow,
552
+ type OutdoorPart,
553
+ type RoadCenterline,
554
+ registerSitePlanContributor,
555
+ type SiteCoverage,
556
+ type SitePlanContributor,
557
+ type SitePlanDrawing,
558
+ type SitePlanEdge,
559
+ type SitePlanServicePoint,
560
+ type SitePlanServiceRole,
561
+ type SitePlanServices,
562
+ serviceEntranceOf,
563
+ setbackEnvelope,
564
+ streetCore,
565
+ streetEdgeNames,
566
+ type YardDimension,
567
+ } from './lib/floorplan/site-plan'
470
568
  export {
471
569
  commitFreshPlacementSubtree,
472
570
  createFreshPlacementSubtree,
473
571
  } from './lib/fresh-planar-placement'
572
+ export {
573
+ type BlenderScriptBuilder,
574
+ compileAndStoreGeometryScript,
575
+ configureBlenderScriptBuilder,
576
+ rebuildAuthoredObject,
577
+ storedScript,
578
+ } from './lib/geometry-script/author'
579
+ export { compileGeometryScriptInWorker } from './lib/geometry-script/client'
474
580
  export { exportSceneToGlb, type GlbExportOptions } from './lib/glb-export'
475
581
  export {
476
582
  type EditorGridEvent,
@@ -507,6 +613,30 @@ export {
507
613
  scopeNodeId,
508
614
  } from './lib/interaction/scope'
509
615
  export { isEditableKeyboardTarget } from './lib/keyboard-pan'
616
+ // Lot drop-in — address → parcel → streets → front edge → setbacks, on the
617
+ // site node, through the parcel provider the host sets.
618
+ export {
619
+ DEFAULT_SETBACKS_FT,
620
+ DEFAULT_SETBACKS_M,
621
+ DEFAULT_SETBACKS_SOURCE,
622
+ type DropInInput,
623
+ type DropInOptions,
624
+ describeFrontEdge,
625
+ describeLotSummary,
626
+ dropInLot,
627
+ findSiteNode,
628
+ getParcelProvider,
629
+ type LotDropInResult,
630
+ type LotRoad,
631
+ type LotSummary,
632
+ type ParcelEndpoint,
633
+ type ParcelProvider,
634
+ type ParcelResolveData,
635
+ STREET_CLASSES,
636
+ setParcelProvider,
637
+ sitePatchFromParcel,
638
+ useParcelProvider,
639
+ } from './lib/lot'
510
640
  export { useMaterialCatalogModel } from './lib/material-catalog-model'
511
641
  export {
512
642
  type ActivePaintMaterial,
@@ -564,6 +694,7 @@ export type {
564
694
  ModelExportFormat,
565
695
  ModelExportOptions,
566
696
  } from './lib/model-export'
697
+ export { eyedropperMaterial } from './lib/paint-eyedropper'
567
698
  export {
568
699
  cyclePaintScope,
569
700
  type PaintHoverInfo,
@@ -591,11 +722,22 @@ export {
591
722
  type PlanarPoint,
592
723
  resolvePlanarCursorPosition,
593
724
  } from './lib/planar-cursor-placement'
725
+ export type {
726
+ ChatToolCardProps,
727
+ ChatToolOutput,
728
+ PluginChatExtension,
729
+ } from './lib/plugin-chat'
594
730
  export {
595
731
  type EditorHostPanel,
596
732
  type EditorHostPanelWorkspace,
597
733
  editorHostPanelRegistry,
734
+ type PluginAccess,
735
+ type PluginDirectoryContext,
736
+ type PluginInstallLock,
737
+ pluginInstallLocks,
598
738
  registerEditorHostPanel,
739
+ setPluginDirectoryContext,
740
+ setPluginInstallLocks,
599
741
  } from './lib/plugin-panels'
600
742
  export { configureManifoldRuntime } from './lib/print-shell-compiler-manifold-worker'
601
743
  export type { ManifoldRuntimeOptions } from './lib/print-shell-compiler-protocol'
@@ -604,16 +746,35 @@ export {
604
746
  quickMeasurementContext,
605
747
  resolveQuickMeasurementReport,
606
748
  } from './lib/quick-measurement'
749
+ export {
750
+ REGISTERED_DRAFT_SNAP_EXTENSION,
751
+ snapRegisteredDraftPoint,
752
+ } from './lib/registered-draft-snap'
607
753
  export { clearRoofDuplicateMetadata, duplicateRoofSubtree } from './lib/roof-duplication'
608
754
  // Roof wall-face hit resolution + overlap guard — shared by the
609
755
  // kind-owned door / window tools in `@pascal-app/nodes` and the item
610
756
  // placement coordinator's roof-wall strategy.
611
757
  export { hasRoofFaceChildOverlap, type RoofWallHit, resolveRoofWallHit } from './lib/roof-wall-hit'
758
+ export { WALL_PUSH_AFFORDANCE, type WallPushArrowPayload } from './lib/room-handle-drag'
759
+ export type { RoomKey, RoomSelectionRecord } from './lib/room-selection'
760
+ export { popRoomSelection, selectRoom } from './lib/room-selection-commands'
761
+ export {
762
+ captureElementActionOrigin,
763
+ completeElementAction,
764
+ type ElementActionOrigin,
765
+ } from './lib/room-zone-routing'
612
766
  export type { SceneGraph } from './lib/scene'
613
- export { applySceneGraphToEditor } from './lib/scene'
767
+ export { applySceneGraphToEditor, getSavedSceneDocument } from './lib/scene'
768
+ export {
769
+ forEachSceneMaterialRef,
770
+ referencedSceneMaterialIds,
771
+ remapSceneMaterialRefs,
772
+ sceneMaterialUsageCounts,
773
+ } from './lib/scene-material-refs'
614
774
  export { movementSfxStepKey } from './lib/sfx/movement-tick'
615
775
  export { emitDeleteSFX, triggerSFX } from './lib/sfx-bus'
616
776
  export { playSFX, type SFXName, type SFXPlaybackOptions } from './lib/sfx-player'
777
+ export { showSidebarPanel } from './lib/sidebar-panel'
617
778
  export {
618
779
  clearSlabSnapFeedback,
619
780
  resolveSlabEdgeBandSnap,
@@ -650,6 +811,12 @@ export {
650
811
  type SurfacePlanSnapInput,
651
812
  type SurfacePlanSnapResult,
652
813
  } from './lib/surface-plan-snap'
814
+ // The Build panel's Outdoor → Terrace tool (an outdoor room: no walls, no ceiling).
815
+ export {
816
+ cancelTerraceDraft,
817
+ startTerraceDraft,
818
+ useTerraceDraft,
819
+ } from './lib/terrace-draft'
653
820
  export { useTerrainPanelRows } from './lib/terrain-panel-model'
654
821
  export {
655
822
  brushRadiusRange,
@@ -668,6 +835,34 @@ export { useLinearDisplay } from './lib/use-linear-display'
668
835
  // nodes` so they don't need their own copy / their own tailwind-merge
669
836
  // dependency.
670
837
  export { cn } from './lib/utils'
838
+ export {
839
+ applyViewerClick,
840
+ applyViewerHover,
841
+ framedLookAt,
842
+ frameViewerCamera,
843
+ useViewerFloorDisplay,
844
+ type ViewerPick,
845
+ type ViewerSource,
846
+ } from './lib/viewer-selection'
847
+ export {
848
+ getWallDrawVariant,
849
+ selectWallDrawVariant,
850
+ useWallDrawVariant,
851
+ type WallDrawVariant,
852
+ } from './lib/wall-draw-variant'
853
+ export {
854
+ addWallPolygonDraftCorner,
855
+ commitWallPolygonDraft,
856
+ discardWallPolygonDraft,
857
+ startWallPolygonDraft,
858
+ wallPolygonDraftWalls,
859
+ } from './lib/wall-polygon-draft'
860
+ export {
861
+ closeWindowOpenState,
862
+ getDisplayedWindowValue,
863
+ isOperableWindowType,
864
+ openWindowOpenState,
865
+ } from './lib/window-interaction'
671
866
  export {
672
867
  getActiveBuildingPose,
673
868
  projectAlignmentGuidesWorldToActiveBuildingLocal,
@@ -684,6 +879,8 @@ export { type CommandAction, useCommandRegistry } from './store/use-command-regi
684
879
  export {
685
880
  DRAWING_TYPE_OPTIONS,
686
881
  default as useDrawingView,
882
+ EDITOR_DRAWING_TYPE_OPTIONS,
883
+ type EditorDrawingType,
687
884
  } from './store/use-drawing-view'
688
885
  export type {
689
886
  CaptureMode,
@@ -691,7 +888,6 @@ export type {
691
888
  Mode,
692
889
  SnapshotCropMode,
693
890
  SnapshotStandardAspect,
694
- SplitOrientation,
695
891
  StructureTool,
696
892
  Tool,
697
893
  ToolDefaults,
@@ -788,3 +984,14 @@ export {
788
984
  type WallSnapKind,
789
985
  type WallSnapPoint,
790
986
  } from './store/use-wall-snap-indicator'
987
+ export {
988
+ activeViewLayout,
989
+ isViewVisible,
990
+ sceneLayout,
991
+ VIEW_2D,
992
+ VIEW_3D,
993
+ type ViewLayout,
994
+ type ViewPaneIndex,
995
+ type VisibleScene,
996
+ visibleScene,
997
+ } from './store/view-layout'