@pascal-app/editor 1.0.7 → 1.1.1

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 (336) hide show
  1. package/package.json +9 -15
  2. package/src/components/editor/action-menu-button.tsx +1 -1
  3. package/src/components/editor/alignment-3d-guide-layer.tsx +1 -1
  4. package/src/components/editor/custom-camera-controls.tsx +101 -45
  5. package/src/components/editor/duplicate-node.ts +2 -1
  6. package/src/components/editor/editor-layout-v2.tsx +1 -1
  7. package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
  8. package/src/components/editor/first-person-controls.tsx +20 -1983
  9. package/src/components/editor/fit-scene-framing.test.ts +318 -0
  10. package/src/components/editor/fit-scene-framing.ts +142 -0
  11. package/src/components/editor/floating-action-menu.tsx +5 -3
  12. package/src/components/editor/floating-building-action-menu.tsx +1 -1
  13. package/src/components/editor/floor-openings-overlay.tsx +1 -1
  14. package/src/components/editor/floor-region-controls.tsx +8 -4
  15. package/src/components/editor/floorplan-navigation-presentation.test.ts +0 -40
  16. package/src/components/editor/floorplan-navigation-presentation.ts +0 -66
  17. package/src/components/editor/floorplan-panel.tsx +199 -30
  18. package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
  19. package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
  20. package/src/components/editor/follow-pascal.test.tsx +1 -2
  21. package/src/components/editor/follow-pascal.tsx +1 -1
  22. package/src/components/editor/footprint-height-handle.tsx +2 -2
  23. package/src/components/editor/group-actions.ts +1 -2
  24. package/src/components/editor/group-floating-action-menu.tsx +1 -1
  25. package/src/components/editor/group-move-3d.ts +1 -2
  26. package/src/components/editor/group-rotate-handle.tsx +1 -2
  27. package/src/components/editor/group-transform-shared.ts +3 -1
  28. package/src/components/editor/handles/use-handle-drag.ts +1 -2
  29. package/src/components/editor/index.tsx +43 -13
  30. package/src/components/editor/inspector-extension-actions.tsx +1 -1
  31. package/src/components/editor/measurement-pill.tsx +1 -1
  32. package/src/components/editor/node-arrow-handles.tsx +2 -2
  33. package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
  34. package/src/components/editor/open-wall-ends-hint.tsx +1 -1
  35. package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
  36. package/src/components/editor/quick-measurement-card.tsx +1 -1
  37. package/src/components/editor/room-controls.tsx +10 -6
  38. package/src/components/editor/room-handles-2d.tsx +3 -3
  39. package/src/components/editor/room-handles.tsx +4 -5
  40. package/src/components/editor/room-highlight.tsx +6 -105
  41. package/src/components/editor/room-labels.test.ts +8 -822
  42. package/src/components/editor/room-labels.tsx +41 -1670
  43. package/src/components/editor/room-webgpu-materials.test.ts +1 -1
  44. package/src/components/editor/selection-manager.tsx +5 -3
  45. package/src/components/editor/site-edge-labels.tsx +7 -3
  46. package/src/components/editor/snapshot-capture-overlay.tsx +2 -5
  47. package/src/components/editor/use-floorplan-background-placement.ts +2 -1
  48. package/src/components/editor/views/plugins-view.tsx +1 -1
  49. package/src/components/editor/views/view-bar.tsx +9 -9
  50. package/src/components/editor/wall-measurement-label.tsx +31 -15
  51. package/src/components/editor/wall-move-side-handles.tsx +11 -7
  52. package/src/components/editor/wall-pull-grip.tsx +2 -2
  53. package/src/components/editor/wall-region-handles.tsx +2 -2
  54. package/src/components/editor/wall-snap-beacon-layer.tsx +53 -32
  55. package/src/components/editor-2d/floorplan-group-move.tsx +3 -4
  56. package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +13 -13
  57. package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +2 -3
  58. package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
  59. package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +23 -6
  60. package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +0 -37
  61. package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +0 -30
  62. package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +13 -3
  63. package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
  64. package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +14 -3
  65. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
  66. package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
  67. package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +30 -10
  68. package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +39 -35
  69. package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
  70. package/src/components/systems/roof/roof-edit-system.tsx +33 -21
  71. package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
  72. package/src/components/tools/distribution/distribution-run-tool.tsx +151 -33
  73. package/src/components/tools/item/move-tool.tsx +1 -6
  74. package/src/components/tools/item/placement-history.test.tsx +1 -1
  75. package/src/components/tools/item/use-placement-coordinator.tsx +3 -4
  76. package/src/components/tools/paint-region/wall-paint-region-tool.tsx +7 -3
  77. package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
  78. package/src/components/tools/registry/move-registry-node-tool.tsx +39 -16
  79. package/src/components/tools/shared/cursor-sphere.tsx +1 -1
  80. package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
  81. package/src/components/tools/shared/placement-box.tsx +2 -6
  82. package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
  83. package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
  84. package/src/components/tools/shared/segment-angle.ts +0 -4
  85. package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
  86. package/src/components/tools/tool-manager.tsx +1 -24
  87. package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
  88. package/src/components/tools/wall/wall-typed-entry.ts +70 -0
  89. package/src/components/ui/action-menu/camera-actions.tsx +2 -2
  90. package/src/components/ui/action-menu/control-modes.tsx +1 -1
  91. package/src/components/ui/action-menu/follow-pascal-pill.tsx +1 -1
  92. package/src/components/ui/action-menu/index.tsx +3 -3
  93. package/src/components/ui/action-menu/measurement-control.tsx +3 -3
  94. package/src/components/ui/action-menu/placement.ts +0 -18
  95. package/src/components/ui/action-menu/point-ask-button.tsx +1 -1
  96. package/src/components/ui/action-menu/view-toggles.tsx +5 -5
  97. package/src/components/ui/controls/finish-swatch.tsx +1 -1
  98. package/src/components/ui/controls/material-paint-panel.tsx +2 -2
  99. package/src/components/ui/controls/scene-material-list.tsx +2 -2
  100. package/src/components/ui/controls/select-control.tsx +1 -1
  101. package/src/components/ui/controls/slider-control.tsx +18 -6
  102. package/src/components/ui/controls/terrain-sculpt-panel.tsx +1 -1
  103. package/src/components/ui/controls/tool-options-panel.tsx +74 -44
  104. package/src/components/ui/floating-level-selector.tsx +3 -3
  105. package/src/components/ui/helpers/contextual-helper-panel.tsx +1 -1
  106. package/src/components/ui/helpers/helper-manager.test.tsx +54 -1
  107. package/src/components/ui/helpers/helper-manager.tsx +55 -1
  108. package/src/components/ui/level-duplicate-dialog.tsx +1 -1
  109. package/src/components/ui/panels/collections/collections-popover.tsx +2 -2
  110. package/src/components/ui/panels/floor-foundation-panel.tsx +3 -3
  111. package/src/components/ui/panels/floor-opening-panel.tsx +5 -5
  112. package/src/components/ui/panels/mobile-selection-bar.tsx +28 -24
  113. package/src/components/ui/panels/multi-height-mode.tsx +3 -3
  114. package/src/components/ui/panels/multi-selection-panel.tsx +1 -1
  115. package/src/components/ui/panels/node-display.ts +1 -1
  116. package/src/components/ui/panels/panel-manager.tsx +5 -3
  117. package/src/components/ui/panels/panel-wrapper.tsx +42 -19
  118. package/src/components/ui/panels/parametric-inspector.tsx +1 -1
  119. package/src/components/ui/panels/room-construction-rows.tsx +7 -7
  120. package/src/components/ui/panels/room-name-options.ts +1 -5
  121. package/src/components/ui/panels/room-openings-field.tsx +1 -1
  122. package/src/components/ui/panels/room-panel.tsx +7 -9
  123. package/src/components/ui/primitives/color-dot.tsx +2 -2
  124. package/src/components/ui/primitives/opacity-control.tsx +2 -2
  125. package/src/components/ui/primitives/sidebar.tsx +3 -3
  126. package/src/components/ui/right-stack.test.ts +13 -6
  127. package/src/components/ui/right-stack.tsx +22 -11
  128. package/src/components/ui/sidebar/icon-rail.tsx +1 -1
  129. package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
  130. package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +2 -2
  131. package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +1 -1
  132. package/src/components/ui/sidebar/panels/settings-panel/index.tsx +2 -2
  133. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +1 -1
  134. package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +2 -6
  135. package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +1 -1
  136. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +1 -1
  137. package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +1 -1
  138. package/src/components/ui/sidebar/panels/site-panel/index.tsx +3 -10
  139. package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +1 -1
  140. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
  141. package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +46 -7
  142. package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +1 -1
  143. package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +1 -1
  144. package/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx +14 -5
  145. package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -2
  146. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +1 -1
  147. package/src/components/ui/sidebar/panels/zone-panel/index.tsx +3 -3
  148. package/src/components/ui/sidebar/tab-bar.tsx +1 -1
  149. package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +2 -2
  150. package/src/components/ui/wall-type/wall-type-menu.tsx +1 -1
  151. package/src/components/viewer-overlay.tsx +1 -2
  152. package/src/hooks/use-auto-frame.ts +1 -2
  153. package/src/hooks/use-keyboard.ts +1 -2
  154. package/src/hooks/use-selected-room.ts +5 -7
  155. package/src/i18n/floor-footprint-name.ts +1 -1
  156. package/src/i18n/locales/en/messages.po +1036 -306
  157. package/src/i18n/locales/en/messages.ts +1 -1
  158. package/src/i18n/locales/en-XA/messages.ts +1 -1
  159. package/src/i18n/locales/es/messages.po +2267 -439
  160. package/src/i18n/locales/fr/messages.po +2267 -439
  161. package/src/i18n/locales/ja/messages.po +2267 -439
  162. package/src/i18n/locales/zh-CN/messages.po +2267 -439
  163. package/src/i18n/locales.test.ts +1 -1
  164. package/src/index.tsx +183 -178
  165. package/src/lib/below-grade.test.tsx +4 -4
  166. package/src/lib/camera-facing.test.ts +1 -1
  167. package/src/lib/camera-facing.ts +2 -3
  168. package/src/lib/contextual-help.ts +6 -0
  169. package/src/lib/editor-level-display.ts +1 -1
  170. package/src/lib/elevation-guides.ts +21 -6
  171. package/src/lib/elevator-support.ts +1 -72
  172. package/src/lib/floor-footprints.test.ts +3 -3
  173. package/src/lib/floor-footprints.ts +1 -9
  174. package/src/lib/floor-foundation-support.test.ts +8 -3
  175. package/src/lib/floor-opening-draft.ts +2 -2
  176. package/src/lib/floor-region-session.ts +1 -1
  177. package/src/lib/floorplan/annotation-visibility.test.ts +1 -1
  178. package/src/lib/floorplan/annotation-visibility.ts +1 -1
  179. package/src/lib/floorplan/floorplan-export.test.ts +1 -1
  180. package/src/lib/floorplan/floorplan-export.tsx +8 -11
  181. package/src/lib/floorplan/floorplan-extension.ts +4 -157
  182. package/src/lib/floorplan/floorplan-mode.ts +2 -1
  183. package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +1 -1
  184. package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +8 -6
  185. package/src/lib/floorplan/floorplan-plugin-install.test.tsx +3 -4
  186. package/src/lib/floorplan/geometry.ts +2 -112
  187. package/src/lib/floorplan/index.ts +0 -9
  188. package/src/lib/floorplan/items.ts +2 -1
  189. package/src/lib/floorplan/open-wall-ends.ts +2 -1
  190. package/src/lib/floorplan/schedules.ts +6 -3
  191. package/src/lib/floorplan/sheet-export.ts +7 -3
  192. package/src/lib/floorplan/site-plan/site-parts.ts +7 -1
  193. package/src/lib/floorplan/site-plan/site-plan-layer.tsx +1 -1
  194. package/src/lib/follow-pascal-presentation.ts +1 -1
  195. package/src/lib/gesture-lifecycle.ts +3 -1
  196. package/src/lib/glb-export.ts +1 -1
  197. package/src/lib/interaction/scope.ts +1 -0
  198. package/src/lib/layer-thickness.ts +1 -1
  199. package/src/lib/level-selection.test.ts +18 -2
  200. package/src/lib/level-selection.ts +31 -8
  201. package/src/lib/linear-display.ts +1 -1
  202. package/src/lib/live-gesture-round-trip.test.ts +1 -1
  203. package/src/lib/material-paint.ts +1 -1
  204. package/src/lib/measurement-label.test.ts +1 -1
  205. package/src/lib/measurements.test.ts +7 -5
  206. package/src/lib/mezzanine-selection.test.ts +1 -1
  207. package/src/lib/node-action-movement.test.tsx +115 -0
  208. package/src/lib/node-action-movement.ts +2 -0
  209. package/src/lib/paint-region-mode.ts +1 -1
  210. package/src/lib/placement-metadata.ts +4 -0
  211. package/src/lib/point-ask/describe-target.ts +6 -8
  212. package/src/lib/point-ask/region.ts +1 -1
  213. package/src/lib/point-ask/session.ts +1 -2
  214. package/src/lib/print-shell-compiler.ts +12 -1
  215. package/src/lib/print-wall-solids.test.ts +11 -0
  216. package/src/lib/print-wall-solids.ts +9 -0
  217. package/src/lib/roof-duplication.test.ts +100 -0
  218. package/src/lib/roof-duplication.ts +30 -5
  219. package/src/lib/room-built-on.test.ts +2 -5
  220. package/src/lib/room-built-on.ts +1 -15
  221. package/src/lib/room-construction-commands.ts +3 -2
  222. package/src/lib/room-controls-phase6.test.ts +1 -1
  223. package/src/lib/room-handle-drag.ts +8 -37
  224. package/src/lib/room-name-catalog.test.ts +2 -1
  225. package/src/lib/room-name-messages.test.ts +2 -1
  226. package/src/lib/room-name-messages.ts +1 -118
  227. package/src/lib/room-name-storage.test.ts +2 -1
  228. package/src/lib/room-push-dimensions.test.ts +1 -1
  229. package/src/lib/room-selection-commands.ts +2 -2
  230. package/src/lib/room-selection.test.ts +6 -6
  231. package/src/lib/room-transform-session.ts +1 -2
  232. package/src/lib/room-zone-routing.ts +2 -2
  233. package/src/lib/scene-clipboard.ts +2 -1
  234. package/src/lib/selection-routing.test.ts +0 -28
  235. package/src/lib/selection-routing.ts +1 -40
  236. package/src/lib/sfx-bus.ts +8 -32
  237. package/src/lib/sfx-player.test.ts +72 -1
  238. package/src/lib/sfx-player.ts +49 -337
  239. package/src/lib/snapping-mode.test.ts +23 -1
  240. package/src/lib/viewer-selection.test.ts +38 -10
  241. package/src/lib/wall-pull.test.ts +1 -1
  242. package/src/lib/wall-pull.ts +1 -27
  243. package/src/lib/wall-region-list.ts +3 -1
  244. package/src/lib/window-interaction.test.ts +4 -2
  245. package/src/store/use-editor.tsx +22 -26
  246. package/src/store/use-floorplan-annotation-visibility.ts +5 -5
  247. package/src/store/use-placement-typing.test.ts +165 -0
  248. package/src/store/use-placement-typing.ts +186 -0
  249. package/src/store/use-wall-region-handles-selection.ts +1 -2
  250. package/src/components/editor/__bench__/room-label-placement.bench.ts +0 -108
  251. package/src/components/editor/first-person/build-collider-world.test.ts +0 -596
  252. package/src/components/editor/first-person/build-collider-world.ts +0 -549
  253. package/src/components/editor/first-person/ground-holes.test.ts +0 -128
  254. package/src/components/editor/first-person/ground-holes.ts +0 -130
  255. package/src/components/editor/first-person/mechanism-targets.test.ts +0 -162
  256. package/src/components/editor/first-person/mechanism-targets.ts +0 -88
  257. package/src/components/editor/first-person/terrain-collider.test.ts +0 -132
  258. package/src/components/editor/first-person/terrain-collider.ts +0 -212
  259. package/src/components/editor/floorplan-camera-sync.test.ts +0 -249
  260. package/src/components/editor/floorplan-camera-sync.ts +0 -213
  261. package/src/components/editor/localized-html.tsx +0 -22
  262. package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +0 -236
  263. package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +0 -708
  264. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +0 -385
  265. package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +0 -670
  266. package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +0 -89
  267. package/src/components/editor-2d/renderers/floorplan-label-angle.ts +0 -106
  268. package/src/components/editor-2d/svg-paths.ts +0 -124
  269. package/src/components/tools/elevator/elevator-defaults.ts +0 -8
  270. package/src/components/tools/elevator/elevator-tool.tsx +0 -372
  271. package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
  272. package/src/components/ui/action-menu/action-button.tsx +0 -89
  273. package/src/components/ui/action-menu/follow-pascal-toggle.tsx +0 -42
  274. package/src/components/ui/primitives/button.tsx +0 -69
  275. package/src/components/ui/primitives/dropdown-menu.tsx +0 -232
  276. package/src/components/ui/primitives/popover.tsx +0 -42
  277. package/src/components/ui/primitives/switch.tsx +0 -29
  278. package/src/components/ui/primitives/tooltip.tsx +0 -57
  279. package/src/components/ui/scene-loader.tsx +0 -73
  280. package/src/components/viewer/floorplan-compass-button.tsx +0 -67
  281. package/src/components/viewer/floorplan-preview-geometry.test.ts +0 -107
  282. package/src/components/viewer/floorplan-preview-geometry.ts +0 -281
  283. package/src/components/viewer/floorplan-preview-navigation.test.ts +0 -43
  284. package/src/components/viewer/floorplan-preview-navigation.ts +0 -62
  285. package/src/components/viewer/floorplan-preview-visibility.test.ts +0 -35
  286. package/src/components/viewer/floorplan-preview-visibility.ts +0 -19
  287. package/src/components/viewer/floorplan-preview.tsx +0 -1065
  288. package/src/components/viewer/render-settings-menu.tsx +0 -294
  289. package/src/components/viewer/sky-control.tsx +0 -710
  290. package/src/components/viewer/use-viewer-camera-navigation-sync.ts +0 -140
  291. package/src/components/viewer/use-viewer-ui-sounds.test.ts +0 -15
  292. package/src/components/viewer/use-viewer-ui-sounds.ts +0 -46
  293. package/src/components/viewer/viewer-controls-bar.tsx +0 -496
  294. package/src/components/viewer/viewer-hover-label.tsx +0 -42
  295. package/src/components/viewer/viewer-rooms.tsx +0 -248
  296. package/src/components/viewer/viewer-scene-header.tsx +0 -286
  297. package/src/components/viewer/viewer-selection-manager.tsx +0 -124
  298. package/src/components/viewer/viewer-stage-modes.test.ts +0 -38
  299. package/src/components/viewer/viewer-stage-modes.ts +0 -49
  300. package/src/components/viewer/viewer-stage-switcher.tsx +0 -97
  301. package/src/components/viewer/viewer-stage.test.tsx +0 -47
  302. package/src/components/viewer/viewer-stage.tsx +0 -221
  303. package/src/components/walkthrough-hud.tsx +0 -193
  304. package/src/hooks/use-mobile.ts +0 -19
  305. package/src/i18n/level-name.ts +0 -39
  306. package/src/i18n/scene-theme-name.ts +0 -16
  307. package/src/lib/below-grade.ts +0 -133
  308. package/src/lib/camera-pose.test.ts +0 -237
  309. package/src/lib/camera-pose.ts +0 -172
  310. package/src/lib/door-interaction.ts +0 -102
  311. package/src/lib/floorplan/floorplan-extension.test.ts +0 -42
  312. package/src/lib/floorplan/floorplan-readonly.test.ts +0 -47
  313. package/src/lib/floorplan/floorplan-readonly.ts +0 -95
  314. package/src/lib/floorplan/marks.test.ts +0 -213
  315. package/src/lib/floorplan/marks.ts +0 -238
  316. package/src/lib/measurement-label.ts +0 -68
  317. package/src/lib/measurements.ts +0 -225
  318. package/src/lib/node-display-label.ts +0 -37
  319. package/src/lib/room-assembly-overlay.test.ts +0 -275
  320. package/src/lib/room-assembly-overlay.ts +0 -265
  321. package/src/lib/room-selection.ts +0 -417
  322. package/src/lib/scene-bounds.test.ts +0 -183
  323. package/src/lib/scene-bounds.ts +0 -169
  324. package/src/lib/typing-target.ts +0 -9
  325. package/src/lib/viewer-selection.ts +0 -595
  326. package/src/lib/window-interaction.ts +0 -142
  327. package/src/lib/zone-content.ts +0 -133
  328. package/src/store/camera-pose-store.test.ts +0 -29
  329. package/src/store/camera-pose-store.ts +0 -27
  330. package/src/store/navigation-sync-pose-store.test.ts +0 -34
  331. package/src/store/navigation-sync-pose-store.ts +0 -27
  332. package/src/store/use-audio.test.ts +0 -146
  333. package/src/store/use-audio.tsx +0 -169
  334. package/src/store/use-first-person-hud.ts +0 -40
  335. package/src/store/use-follow-pascal.test.ts +0 -62
  336. package/src/store/use-follow-pascal.ts +0 -53
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pascal-app/editor",
3
- "version": "1.0.7",
3
+ "version": "1.1.1",
4
4
  "description": "Pascal building editor component",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -13,18 +13,17 @@
13
13
  "./distribution": "./src/components/tools/distribution/distribution-public.ts"
14
14
  },
15
15
  "scripts": {
16
- "bench:room-labels": "bun run src/components/editor/__bench__/room-label-placement.bench.ts",
17
16
  "check-types": "tsgo --noEmit",
18
17
  "test": "bun test src"
19
18
  },
20
19
  "peerDependencies": {
21
- "@pascal-app/core": "^1.0.7",
22
- "@pascal-app/viewer": "^1.0.7",
20
+ "@pascal-app/core": "^1.1.1",
21
+ "@pascal-app/viewer": "^1.1.1",
23
22
  "@react-three/drei": "^10",
24
23
  "@react-three/fiber": "^9",
25
24
  "next": ">=15",
26
- "react": "^18 || ^19",
27
- "react-dom": "^18 || ^19",
25
+ "react": "^19",
26
+ "react-dom": "^19",
28
27
  "three": "^0.187"
29
28
  },
30
29
  "dependencies": {
@@ -34,19 +33,16 @@
34
33
  "@iconify/react": "^6.0.4",
35
34
  "@lingui/core": "6.12.0",
36
35
  "@number-flow/react": "^0.6.2",
37
- "@pascal-app/geometry-script": "^1.0.7",
38
- "@pascal-app/ifc-converter": "^1.0.7",
36
+ "@pascal-app/geometry-script": "^1.1.1",
37
+ "@pascal-app/ifc-converter": "^1.1.1",
39
38
  "@pascal-app/lingo": "^0.5.0",
40
39
  "@radix-ui/react-alert-dialog": "^1.2.1",
41
40
  "@radix-ui/react-context-menu": "^2.4.1",
42
41
  "@radix-ui/react-dialog": "^1.3.1",
43
- "@radix-ui/react-dropdown-menu": "^2.2.1",
44
- "@radix-ui/react-popover": "^1.3.1",
45
42
  "@radix-ui/react-select": "^2.4.1",
46
43
  "@radix-ui/react-separator": "^1.2.0",
47
44
  "@radix-ui/react-slider": "^1.6.1",
48
45
  "@radix-ui/react-slot": "^1.5.0",
49
- "@radix-ui/react-switch": "^1.4.1",
50
46
  "@radix-ui/react-tabs": "^1.2.1",
51
47
  "@radix-ui/react-tooltip": "^1.4.1",
52
48
  "@visual-json/react": "^0.4.0",
@@ -55,7 +51,6 @@
55
51
  "clsx": "^2.1.1",
56
52
  "cmdk": "^1.1.1",
57
53
  "fflate": "^0.8.3",
58
- "howler": "^2.2.4",
59
54
  "lucide-react": "^1.69.0",
60
55
  "manifold-3d": "3.5.4",
61
56
  "mitt": "^3.0.1",
@@ -69,13 +64,12 @@
69
64
  "zustand": "^5.0.16"
70
65
  },
71
66
  "devDependencies": {
72
- "@pascal-app/core": "^1.0.7",
73
- "@pascal-app/viewer": "^1.0.7",
67
+ "@pascal-app/core": "^1.1.1",
68
+ "@pascal-app/viewer": "^1.1.1",
74
69
  "@pascal/typescript-config": "*",
75
70
  "@react-three/test-renderer": "^9.1.1",
76
71
  "@types/blob-stream": "^0.1.33",
77
72
  "@types/bun": "^1.4.4",
78
- "@types/howler": "^2.2.13",
79
73
  "@types/pdfkit": "^0.17.7",
80
74
  "@types/react": "19.3.0",
81
75
  "@types/react-dom": "19.3.0",
@@ -1,11 +1,11 @@
1
1
  'use client'
2
2
 
3
3
  import { usePascalI18n } from '@pascal-app/core'
4
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@pascal-app/viewer/ui'
4
5
  import type { MouseEventHandler, ReactNode } from 'react'
5
6
  import { toolHintKey } from '../../i18n/node-messages'
6
7
  import { cn } from '../../lib/utils'
7
8
  import { shortcutDisplayValue } from '../ui/primitives/shortcut-token'
8
- import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/primitives/tooltip'
9
9
 
10
10
  const BUTTON =
11
11
  'rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground'
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { type AlignmentGuide, sceneRegistry } from '@pascal-app/core'
4
4
  import { useViewer } from '@pascal-app/viewer'
5
+ import { LocalizedHtml as Html } from '@pascal-app/viewer/ui'
5
6
  import { useFrame } from '@react-three/fiber'
6
7
  import { memo, useMemo, useRef } from 'react'
7
8
  import { BoxGeometry, CircleGeometry, type Group, RingGeometry, Vector3 } from 'three'
@@ -11,7 +12,6 @@ import useAlignmentGuides, {
11
12
  type DraftGuideLine,
12
13
  type DraftGuides,
13
14
  } from '../../store/use-alignment-guides'
14
- import { Html } from './localized-html'
15
15
  import { formatMeasurement } from './measurement-pill'
16
16
 
17
17
  /**
@@ -21,6 +21,17 @@ import {
21
21
  useViewer,
22
22
  ZONE_LAYER,
23
23
  } from '@pascal-app/viewer'
24
+ import {
25
+ type CameraPoseApplicationPlan,
26
+ frameViewerCamera,
27
+ normalizeCameraPose,
28
+ planCameraPoseApplication,
29
+ publishCameraPose,
30
+ publishInitialCameraPose,
31
+ releaseCameraPoseEventSuppression,
32
+ stepCameraPoseInterpolation,
33
+ withCameraPoseDistance,
34
+ } from '@pascal-app/viewer/ui'
24
35
  import { CameraControls, CameraControlsImpl } from '@react-three/drei'
25
36
  import { useFrame, useThree } from '@react-three/fiber'
26
37
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react'
@@ -29,18 +40,10 @@ import {
29
40
  type Camera,
30
41
  type OrthographicCamera,
31
42
  type PerspectiveCamera,
43
+ Sphere,
32
44
  Spherical,
33
45
  Vector3,
34
46
  } from 'three'
35
- import {
36
- type CameraPoseApplicationPlan,
37
- normalizeCameraPose,
38
- planCameraPoseApplication,
39
- publishInitialCameraPose,
40
- releaseCameraPoseEventSuppression,
41
- stepCameraPoseInterpolation,
42
- withCameraPoseDistance,
43
- } from '../../lib/camera-pose'
44
47
  import { EDITOR_LAYER } from '../../lib/constants'
45
48
  import {
46
49
  acceptsKeyboardPan,
@@ -64,8 +67,6 @@ import {
64
67
  } from '../../lib/orbit-floor-clearance'
65
68
  import { orbitNearPlane } from '../../lib/orbit-near-plane'
66
69
  import { editorOwnsOneFingerDrag } from '../../lib/touch-gesture-priority'
67
- import { frameViewerCamera } from '../../lib/viewer-selection'
68
- import { publishCameraPose } from '../../store/camera-pose-store'
69
70
  import useEditor, { takePreviewCameraRestore } from '../../store/use-editor'
70
71
  import {
71
72
  useActiveHandleDrag,
@@ -74,6 +75,13 @@ import {
74
75
  } from '../../store/use-interaction-scope'
75
76
  import { visibleScene } from '../../store/view-layout'
76
77
  import { createCameraDraggingLifecycle } from './camera-dragging-lifecycle'
78
+ import {
79
+ type FitSceneLookAt,
80
+ type PendingFitScene,
81
+ planFitSceneOnEvent,
82
+ planFitSceneOnOrbitResume,
83
+ planLevelFollow,
84
+ } from './fit-scene-framing'
77
85
  import { FloorAwareCameraControls } from './floor-aware-camera-controls'
78
86
  import { FloorSurface } from './floor-surface'
79
87
 
@@ -84,6 +92,7 @@ const tempDelta = new Vector3()
84
92
  const tempPosition = new Vector3()
85
93
  const tempSize = new Vector3()
86
94
  const tempTarget = new Vector3()
95
+ const fitSceneSphere = new Sphere()
87
96
  const transitionFreezePosition = new Vector3()
88
97
  const transitionFreezeTarget = new Vector3()
89
98
  const keyboardPanSpherical = new Spherical()
@@ -120,6 +129,23 @@ function keepEyeOverGround(x: number, eyeY: number, z: number, previousEyeY = ey
120
129
  return overviewEyeY(eyeY, previousEyeY, groundY, useViewer.getState().eyeUnderGround)
121
130
  }
122
131
 
132
+ function applyFitLookAt(control: CameraControlsImpl, lookAt: FitSceneLookAt) {
133
+ control.setLookAt(
134
+ lookAt.eyeX,
135
+ keepEyeOverGround(lookAt.eyeX, lookAt.eyeY, lookAt.eyeZ, lookAt.eyeHeight),
136
+ lookAt.eyeZ,
137
+ lookAt.targetX,
138
+ lookAt.targetY,
139
+ lookAt.targetZ,
140
+ true,
141
+ )
142
+ if (isOrthographicCamera(control.camera)) {
143
+ fitSceneSphere.center.set(...lookAt.fitSphere.center)
144
+ fitSceneSphere.radius = lookAt.fitSphere.radius
145
+ control.fitToSphere(fitSceneSphere, true)
146
+ }
147
+ }
148
+
123
149
  function levelOf(nodeId: string): string | null {
124
150
  const nodes = useScene.getState().nodes
125
151
  let node: AnyNode | undefined = nodes[nodeId as AnyNodeId]
@@ -407,6 +433,9 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
407
433
  if (selection.levelId) lastLevelId.current = selection.levelId
408
434
  const currentLevelId = lastLevelId.current
409
435
  const firstLoad = useRef(true)
436
+ // Survives first-person (orbit unmounted) so scene-ready fit still applies
437
+ // once CameraControls remount.
438
+ const pendingFitSceneRef = useRef<PendingFitScene | null>(null)
410
439
  const floorY = useScene((state) =>
411
440
  currentLevelId ? getLevelPresentationY(currentLevelId, state.nodes, levelMode) : 0,
412
441
  )
@@ -615,19 +644,32 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
615
644
  }
616
645
  }, [scene, gl, camera])
617
646
 
647
+ const previousLevelIdRef = useRef<string | null>(null)
648
+ const previousLevelModeRef = useRef(levelMode)
649
+ const previousCameraRef = useRef(camera)
618
650
  // `camera` too: drei builds a fresh controls instance (pivot at the origin)
619
651
  // when the default camera mounts or changes; it is rested on the floor too.
620
- // biome-ignore lint/correctness/useExhaustiveDependencies: camera re-runs this on a new instance
621
652
  useEffect(() => {
622
653
  if (isPreviewMode || isFirstPersonMode || isRestoringFirstPersonPose()) return
623
654
  // Analytic destination, not `sceneRegistry` mesh position: a level created
624
655
  // this frame still sits at y=0 (LevelSystem lerps it later), and a mode
625
- // switch leaves every level mid-lerp — the camera must pan to where the
656
+ // switch leaves every level mid-lerp - the camera must pan to where the
626
657
  // level will settle, in the CURRENT presentation mode.
627
658
  const targetY = orbitGroundY(currentLevelId, levelMode)
628
659
  if (!controls.current) return
629
- if (firstLoad.current) {
630
- firstLoad.current = false
660
+ const plan = planLevelFollow({
661
+ firstLoad: firstLoad.current,
662
+ sceneEmpty: Object.keys(useScene.getState().nodes).length === 0,
663
+ levelChanged: previousLevelIdRef.current !== currentLevelId,
664
+ modeChanged: previousLevelModeRef.current !== levelMode,
665
+ cameraChanged: previousCameraRef.current !== camera,
666
+ })
667
+ firstLoad.current = false
668
+ previousLevelIdRef.current = currentLevelId
669
+ previousLevelModeRef.current = levelMode
670
+ previousCameraRef.current = camera
671
+ if (plan === 'none') return
672
+ if (plan === 'default-pose') {
631
673
  controls.current.setLookAt(
632
674
  20,
633
675
  keepEyeOverGround(20, 20 + targetY, 20, 20),
@@ -637,6 +679,7 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
637
679
  0,
638
680
  true,
639
681
  )
682
+ return
640
683
  }
641
684
  controls.current.getOrbitTarget(currentTarget)
642
685
  // Idempotence guard: skip when already there — also swallows the thumbnail
@@ -692,6 +735,19 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
692
735
  controls.current.floorSurface = diveFloor === null ? floorSurface : null
693
736
  }, [camera, currentLevelId, diveFloor, floorMinY, floorSurface, isFirstPersonMode])
694
737
 
738
+ const flushPendingFitScene = useCallback(() => {
739
+ const plan = planFitSceneOnOrbitResume({
740
+ isPreviewMode,
741
+ isFirstPersonMode: useEditor.getState().isFirstPersonMode,
742
+ hasControls: !!controls.current,
743
+ pending: pendingFitSceneRef.current,
744
+ groundY: orbitGroundY(lastLevelId.current),
745
+ })
746
+ if (plan.action !== 'apply' || !controls.current) return
747
+ pendingFitSceneRef.current = null
748
+ applyFitLookAt(controls.current, plan.lookAt)
749
+ }, [isPreviewMode])
750
+
695
751
  const focusNode = useCallback(
696
752
  (nodeId: string) => {
697
753
  if (isPreviewMode || isFirstPersonMode || !controls.current) return
@@ -1388,37 +1444,22 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
1388
1444
  }
1389
1445
 
1390
1446
  const handleFitScene = ({ bounds }: CameraControlFitSceneEvent) => {
1391
- if (isFirstPersonMode || !controls.current || isPreviewMode) return
1392
- const groundY = orbitGroundY(lastLevelId.current)
1393
- if (!bounds) {
1394
- // Restore default framing pose when no bounds were computed.
1395
- controls.current.setLookAt(
1396
- 20,
1397
- keepEyeOverGround(20, 20 + groundY, 20, 20),
1398
- 20,
1399
- 0,
1400
- groundY,
1401
- 0,
1402
- true,
1403
- )
1447
+ const plan = planFitSceneOnEvent({
1448
+ isPreviewMode,
1449
+ isFirstPersonMode,
1450
+ hasControls: !!controls.current,
1451
+ bounds: bounds ?? null,
1452
+ groundY: orbitGroundY(lastLevelId.current),
1453
+ })
1454
+ if (plan.action === 'ignore') return
1455
+ if (plan.action === 'queue') {
1456
+ pendingFitSceneRef.current = plan.pending
1457
+ // Orbit path with a not-yet-attached ref: retry next frame.
1458
+ if (!isFirstPersonMode) requestAnimationFrame(flushPendingFitScene)
1404
1459
  return
1405
1460
  }
1406
- const [cx, cz] = bounds.center
1407
- const [w, d] = bounds.size
1408
- // Use the longer horizontal extent to size the orbit radius so the whole
1409
- // footprint sits in view regardless of aspect ratio.
1410
- const maxExtent = Math.max(w, d)
1411
- const distance = Math.max(maxExtent * 1.4, 15)
1412
- const height = Math.max(maxExtent * 0.8, 10)
1413
- controls.current.setLookAt(
1414
- cx + distance * 0.7,
1415
- keepEyeOverGround(cx + distance * 0.7, height + groundY, cz + distance * 0.7, height),
1416
- cz + distance * 0.7,
1417
- cx,
1418
- groundY,
1419
- cz,
1420
- true,
1421
- )
1461
+ pendingFitSceneRef.current = null
1462
+ if (controls.current) applyFitLookAt(controls.current, plan.lookAt)
1422
1463
  }
1423
1464
 
1424
1465
  emitter.on('camera-controls:capture', handleNodeCapture)
@@ -1440,7 +1481,22 @@ export const CustomCameraControls = ({ paused = false }: { paused?: boolean }) =
1440
1481
  emitter.off('camera-controls:orbit-ccw', handleOrbitCCW)
1441
1482
  emitter.off('camera-controls:fit-scene', handleFitScene)
1442
1483
  }
1443
- }, [camera, cancelPoseApplication, focusNode, isPreviewMode, isFirstPersonMode])
1484
+ }, [
1485
+ camera,
1486
+ cancelPoseApplication,
1487
+ flushPendingFitScene,
1488
+ focusNode,
1489
+ isPreviewMode,
1490
+ isFirstPersonMode,
1491
+ ])
1492
+
1493
+ // Apply a fit that arrived while first-person (orbit unmounted). Wait one
1494
+ // frame so CameraControls can remount and attach its ref.
1495
+ useEffect(() => {
1496
+ if (isFirstPersonMode || isPreviewMode || !pendingFitSceneRef.current) return
1497
+ const frame = requestAnimationFrame(flushPendingFitScene)
1498
+ return () => cancelAnimationFrame(frame)
1499
+ }, [flushPendingFitScene, isFirstPersonMode, isPreviewMode])
1444
1500
 
1445
1501
  const onTransitionStart = useCallback(() => {
1446
1502
  cameraDraggingLifecycle.begin()
@@ -9,6 +9,7 @@ import {
9
9
  FenceNode,
10
10
  generateId,
11
11
  ItemNode,
12
+ isNodeDuplicable,
12
13
  nodeRegistry,
13
14
  RoofSegmentNode,
14
15
  runSceneHistoryDraftWrite,
@@ -48,7 +49,7 @@ export function copyCollectionIds(copy: AnyNode): CollectionId[] {
48
49
  * every inspector's Duplicate. The copy is in the collections its source is in.
49
50
  */
50
51
  export function duplicateNodeAndPickUp(node: AnyNode) {
51
- if (!node.parentId) return
52
+ if (!(node.parentId && isNodeDuplicable(node))) return
52
53
  if (startZoneRoomTransform(node, 'duplicate')) return
53
54
  sfxEmitter.emit('sfx:item-pick')
54
55
  const { setMovingNode } = useEditor.getState()
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
+ import { useIsMobile } from '@pascal-app/viewer/ui'
3
4
  import { type ReactNode, useCallback, useEffect, useRef } from 'react'
4
- import { useIsMobile } from '../../hooks/use-mobile'
5
5
  import {
6
6
  openSidebarPanel,
7
7
  SIDEBAR_MIN_WIDTH,
@@ -2,13 +2,13 @@
2
2
 
3
3
  import { sceneRegistry } from '@pascal-app/core'
4
4
  import { useViewer } from '@pascal-app/viewer'
5
+ import { LocalizedHtml as Html } from '@pascal-app/viewer/ui'
5
6
  import { useFrame } from '@react-three/fiber'
6
7
  import { memo, useMemo, useRef } from 'react'
7
8
  import { BoxGeometry, CircleGeometry, type Group } from 'three'
8
9
  import { MeshBasicNodeMaterial } from 'three/webgpu'
9
10
  import { EDITOR_LAYER } from '../../lib/constants'
10
11
  import useElevationGuides from '../../store/use-elevation-guides'
11
- import { Html } from './localized-html'
12
12
  import { formatMeasurement } from './measurement-pill'
13
13
 
14
14
  const LINE_COLOR = 0x81_8c_f8