@pascal-app/editor 0.6.0 → 0.7.0

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 (122) hide show
  1. package/package.json +9 -5
  2. package/src/components/editor/bottom-sheet.tsx +149 -0
  3. package/src/components/editor/custom-camera-controls.tsx +75 -7
  4. package/src/components/editor/editor-layout-mobile.tsx +264 -0
  5. package/src/components/editor/editor-layout-v2.tsx +20 -0
  6. package/src/components/editor/first-person/build-collider-world.ts +365 -0
  7. package/src/components/editor/first-person/bvh-ecctrl.tsx +795 -0
  8. package/src/components/editor/first-person-controls.tsx +496 -143
  9. package/src/components/editor/floating-action-menu.tsx +32 -55
  10. package/src/components/editor/floorplan-background-selection.ts +113 -0
  11. package/src/components/editor/floorplan-panel.tsx +9855 -3298
  12. package/src/components/editor/index.tsx +269 -21
  13. package/src/components/editor/selection-manager.tsx +575 -13
  14. package/src/components/editor/thumbnail-generator.tsx +38 -7
  15. package/src/components/editor/use-floorplan-background-placement.ts +257 -0
  16. package/src/components/editor/use-floorplan-hit-testing.ts +171 -0
  17. package/src/components/editor/use-floorplan-scene-data.ts +189 -0
  18. package/src/components/editor/wall-measurement-label.tsx +267 -36
  19. package/src/components/editor-2d/floorplan-action-menu-layer.tsx +95 -0
  20. package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +160 -0
  21. package/src/components/editor-2d/floorplan-hotkey-handlers.tsx +92 -0
  22. package/src/components/editor-2d/renderers/floorplan-draft-layer.tsx +119 -0
  23. package/src/components/editor-2d/renderers/floorplan-marquee-layer.tsx +58 -0
  24. package/src/components/editor-2d/renderers/floorplan-measurements-layer.tsx +197 -0
  25. package/src/components/editor-2d/renderers/floorplan-roof-layer.tsx +113 -0
  26. package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +474 -0
  27. package/src/components/editor-2d/svg-paths.ts +119 -0
  28. package/src/components/tools/ceiling/ceiling-boundary-editor.tsx +1 -0
  29. package/src/components/tools/ceiling/ceiling-hole-editor.tsx +1 -0
  30. package/src/components/tools/ceiling/ceiling-tool.tsx +5 -5
  31. package/src/components/tools/column/column-tool.tsx +97 -0
  32. package/src/components/tools/column/move-column-tool.tsx +105 -0
  33. package/src/components/tools/door/door-tool.tsx +7 -0
  34. package/src/components/tools/door/move-door-tool.tsx +28 -8
  35. package/src/components/tools/fence/fence-drafting.ts +10 -3
  36. package/src/components/tools/fence/fence-tool.tsx +159 -3
  37. package/src/components/tools/fence/move-fence-endpoint-tool.tsx +129 -18
  38. package/src/components/tools/fence/move-fence-tool.tsx +101 -34
  39. package/src/components/tools/item/move-tool.tsx +10 -1
  40. package/src/components/tools/item/placement-math.ts +30 -1
  41. package/src/components/tools/item/placement-strategies.ts +109 -31
  42. package/src/components/tools/item/placement-types.ts +7 -0
  43. package/src/components/tools/item/use-draft-node.ts +2 -0
  44. package/src/components/tools/item/use-placement-coordinator.tsx +660 -52
  45. package/src/components/tools/roof/move-roof-tool.tsx +22 -15
  46. package/src/components/tools/shared/polygon-editor.tsx +153 -28
  47. package/src/components/tools/shared/segment-angle.ts +156 -0
  48. package/src/components/tools/slab/slab-boundary-editor.tsx +1 -0
  49. package/src/components/tools/slab/slab-hole-editor.tsx +1 -0
  50. package/src/components/tools/spawn/move-spawn-tool.tsx +101 -0
  51. package/src/components/tools/spawn/spawn-tool.tsx +130 -0
  52. package/src/components/tools/tool-manager.tsx +18 -3
  53. package/src/components/tools/wall/move-wall-endpoint-tool.tsx +121 -20
  54. package/src/components/tools/wall/wall-drafting.ts +18 -9
  55. package/src/components/tools/wall/wall-tool.tsx +134 -2
  56. package/src/components/tools/window/move-window-tool.tsx +18 -0
  57. package/src/components/tools/window/window-tool.tsx +5 -0
  58. package/src/components/ui/action-menu/camera-actions.tsx +37 -33
  59. package/src/components/ui/action-menu/control-modes.tsx +28 -1
  60. package/src/components/ui/action-menu/index.tsx +91 -1
  61. package/src/components/ui/action-menu/structure-tools.tsx +2 -0
  62. package/src/components/ui/action-menu/view-toggles.tsx +424 -35
  63. package/src/components/ui/command-palette/editor-commands.tsx +18 -1
  64. package/src/components/ui/controls/material-picker.tsx +152 -165
  65. package/src/components/ui/controls/slider-control.tsx +66 -18
  66. package/src/components/ui/floating-level-selector.tsx +286 -55
  67. package/src/components/ui/helpers/helper-manager.tsx +5 -0
  68. package/src/components/ui/item-catalog/catalog-items.tsx +1116 -1219
  69. package/src/components/ui/item-catalog/item-catalog.tsx +42 -175
  70. package/src/components/ui/level-duplicate-dialog.tsx +115 -0
  71. package/src/components/ui/panels/ceiling-panel.tsx +1 -25
  72. package/src/components/ui/panels/column-panel.tsx +715 -0
  73. package/src/components/ui/panels/door-panel.tsx +981 -289
  74. package/src/components/ui/panels/fence-panel.tsx +3 -45
  75. package/src/components/ui/panels/mobile-panel-sheet.tsx +108 -0
  76. package/src/components/ui/panels/mobile-selection-bar.tsx +100 -0
  77. package/src/components/ui/panels/node-display.ts +39 -0
  78. package/src/components/ui/panels/paint-panel.tsx +138 -0
  79. package/src/components/ui/panels/panel-manager.tsx +210 -1
  80. package/src/components/ui/panels/panel-wrapper.tsx +48 -39
  81. package/src/components/ui/panels/reference-panel.tsx +238 -5
  82. package/src/components/ui/panels/roof-panel.tsx +4 -105
  83. package/src/components/ui/panels/roof-segment-panel.tsx +0 -25
  84. package/src/components/ui/panels/slab-panel.tsx +4 -30
  85. package/src/components/ui/panels/spawn-panel.tsx +155 -0
  86. package/src/components/ui/panels/stair-panel.tsx +11 -117
  87. package/src/components/ui/panels/stair-segment-panel.tsx +0 -25
  88. package/src/components/ui/panels/wall-panel.tsx +1 -95
  89. package/src/components/ui/panels/window-panel.tsx +660 -139
  90. package/src/components/ui/sidebar/mobile-tab-bar.tsx +46 -0
  91. package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +2 -2
  92. package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +2 -2
  93. package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +77 -0
  94. package/src/components/ui/sidebar/panels/site-panel/index.tsx +109 -24
  95. package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +2 -2
  96. package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +82 -0
  97. package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +9 -3
  98. package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +8 -5
  99. package/src/components/ui/sidebar/tab-bar.tsx +3 -0
  100. package/src/components/ui/viewer-toolbar.tsx +42 -1
  101. package/src/hooks/use-auto-frame.ts +45 -0
  102. package/src/hooks/use-keyboard.ts +64 -7
  103. package/src/hooks/use-mobile.ts +12 -12
  104. package/src/lib/door-interaction.ts +88 -0
  105. package/src/lib/floorplan/geometry.ts +263 -0
  106. package/src/lib/floorplan/index.ts +38 -0
  107. package/src/lib/floorplan/items.ts +179 -0
  108. package/src/lib/floorplan/selection-tool.ts +231 -0
  109. package/src/lib/floorplan/stairs.ts +478 -0
  110. package/src/lib/floorplan/types.ts +57 -0
  111. package/src/lib/floorplan/walls.ts +23 -0
  112. package/src/lib/guide-events.ts +10 -0
  113. package/src/lib/level-duplication.test.ts +72 -0
  114. package/src/lib/level-duplication.ts +153 -0
  115. package/src/lib/local-guide-image.ts +42 -0
  116. package/src/lib/material-paint.ts +284 -0
  117. package/src/lib/roof-duplication.ts +214 -0
  118. package/src/lib/scene-bounds.test.ts +183 -0
  119. package/src/lib/scene-bounds.ts +169 -0
  120. package/src/lib/stair-duplication.ts +126 -0
  121. package/src/lib/window-interaction.ts +86 -0
  122. package/src/store/use-editor.tsx +164 -8
@@ -4,7 +4,6 @@ import {
4
4
  type AnyNode,
5
5
  type AnyNodeId,
6
6
  type AttachmentSide,
7
- type MaterialSchema,
8
7
  type StairSegmentNode,
9
8
  StairSegmentNode as StairSegmentNodeSchema,
10
9
  type StairSegmentType,
@@ -16,7 +15,6 @@ import { useCallback } from 'react'
16
15
  import { sfxEmitter } from '../../../lib/sfx-bus'
17
16
  import useEditor from '../../../store/use-editor'
18
17
  import { ActionButton, ActionGroup } from '../controls/action-button'
19
- import { MaterialPicker } from '../controls/material-picker'
20
18
  import { PanelSection } from '../controls/panel-section'
21
19
  import { SegmentedControl } from '../controls/segmented-control'
22
20
  import { SliderControl } from '../controls/slider-control'
@@ -61,20 +59,6 @@ export function StairSegmentPanel() {
61
59
  [selectedId, updateNode],
62
60
  )
63
61
 
64
- const handleMaterialChange = useCallback(
65
- (material: MaterialSchema) => {
66
- handleUpdate({ material, materialPreset: undefined })
67
- },
68
- [handleUpdate],
69
- )
70
-
71
- const handleMaterialPresetChange = useCallback(
72
- (materialPreset: string) => {
73
- handleUpdate({ materialPreset, material: undefined })
74
- },
75
- [handleUpdate],
76
- )
77
-
78
62
  const handleClose = useCallback(() => {
79
63
  setSelection({ selectedIds: [] })
80
64
  }, [setSelection])
@@ -336,15 +320,6 @@ export function StairSegmentPanel() {
336
320
  />
337
321
  </ActionGroup>
338
322
  </PanelSection>
339
- <PanelSection title="Material">
340
- <MaterialPicker
341
- nodeType="stair-segment"
342
- onChange={handleMaterialChange}
343
- onSelectMaterialPreset={handleMaterialPresetChange}
344
- selectedMaterialPreset={node.materialPreset}
345
- value={node.material}
346
- />
347
- </PanelSection>
348
323
  </PanelWrapper>
349
324
  )
350
325
  }
@@ -3,61 +3,29 @@
3
3
  import {
4
4
  type AnyNode,
5
5
  type AnyNodeId,
6
- getEffectiveWallSurfaceMaterial,
7
6
  getClampedWallCurveOffset,
8
7
  getMaxWallCurveOffset,
9
8
  getWallCurveLength,
10
- getWallSurfaceMaterialSignature,
11
9
  normalizeWallCurveOffset,
12
- type MaterialSchema,
13
10
  useScene,
14
- type WallSurfaceSide,
15
11
  type WallNode,
16
12
  } from '@pascal-app/core'
17
13
  import { useViewer } from '@pascal-app/viewer'
18
14
  import { Move, Spline } from 'lucide-react'
19
- import { useCallback, useMemo } from 'react'
15
+ import { useCallback } from 'react'
20
16
  import { sfxEmitter } from '../../../lib/sfx-bus'
21
17
  import useEditor from '../../../store/use-editor'
22
18
  import { ActionButton, ActionGroup } from '../controls/action-button'
23
- import { MaterialPicker } from '../controls/material-picker'
24
19
  import { PanelSection } from '../controls/panel-section'
25
20
  import { SliderControl } from '../controls/slider-control'
26
21
  import { PanelWrapper } from './panel-wrapper'
27
22
 
28
- function buildWallSurfaceMaterialPatch(
29
- node: WallNode,
30
- targetSide: WallSurfaceSide | null,
31
- material: MaterialSchema | undefined,
32
- materialPreset: string | undefined,
33
- ): Partial<WallNode> {
34
- const nextSurfaceMaterial = { material, materialPreset }
35
- const nextInterior =
36
- targetSide === null || targetSide === 'interior'
37
- ? nextSurfaceMaterial
38
- : getEffectiveWallSurfaceMaterial(node, 'interior')
39
- const nextExterior =
40
- targetSide === null || targetSide === 'exterior'
41
- ? nextSurfaceMaterial
42
- : getEffectiveWallSurfaceMaterial(node, 'exterior')
43
-
44
- return {
45
- interiorMaterial: nextInterior.material,
46
- interiorMaterialPreset: nextInterior.materialPreset,
47
- exteriorMaterial: nextExterior.material,
48
- exteriorMaterialPreset: nextExterior.materialPreset,
49
- material: undefined,
50
- materialPreset: undefined,
51
- }
52
- }
53
-
54
23
  export function WallPanel() {
55
24
  const selectedId = useViewer((s) => s.selection.selectedIds[0])
56
25
  const setSelection = useViewer((s) => s.setSelection)
57
26
  const updateNode = useScene((s) => s.updateNode)
58
27
  const setMovingNode = useEditor((s) => s.setMovingNode)
59
28
  const setCurvingWall = useEditor((s) => s.setCurvingWall)
60
- const selectedMaterialTarget = useEditor((s) => s.selectedMaterialTarget)
61
29
 
62
30
  const node = useScene((s) =>
63
31
  selectedId ? (s.nodes[selectedId as AnyNode['id']] as WallNode | undefined) : undefined,
@@ -88,35 +56,6 @@ export function WallPanel() {
88
56
  [selectedId, updateNode],
89
57
  )
90
58
 
91
- const effectiveInteriorMaterial = useMemo(
92
- () => (node ? getEffectiveWallSurfaceMaterial(node, 'interior') : {}),
93
- [node],
94
- )
95
- const effectiveExteriorMaterial = useMemo(
96
- () => (node ? getEffectiveWallSurfaceMaterial(node, 'exterior') : {}),
97
- [node],
98
- )
99
- const surfaceMaterialsMatch = useMemo(
100
- () =>
101
- getWallSurfaceMaterialSignature(effectiveInteriorMaterial) ===
102
- getWallSurfaceMaterialSignature(effectiveExteriorMaterial),
103
- [effectiveExteriorMaterial, effectiveInteriorMaterial],
104
- )
105
- const materialTargetSide =
106
- selectedMaterialTarget &&
107
- selectedMaterialTarget.nodeId === node?.id &&
108
- (selectedMaterialTarget.role === 'interior' || selectedMaterialTarget.role === 'exterior')
109
- ? selectedMaterialTarget.role
110
- : null
111
- const materialPickerValue =
112
- materialTargetSide === 'interior'
113
- ? effectiveInteriorMaterial
114
- : materialTargetSide === 'exterior'
115
- ? effectiveExteriorMaterial
116
- : surfaceMaterialsMatch
117
- ? effectiveInteriorMaterial
118
- : {}
119
-
120
59
  const handleUpdateLength = useCallback(
121
60
  (newLength: number) => {
122
61
  if (!node || newLength <= 0) return
@@ -140,22 +79,6 @@ export function WallPanel() {
140
79
  [node, handleUpdate],
141
80
  )
142
81
 
143
- const handleMaterialPresetChange = useCallback(
144
- (materialPreset: string) => {
145
- if (!node || !materialTargetSide) return
146
- handleUpdate(buildWallSurfaceMaterialPatch(node, materialTargetSide, undefined, materialPreset))
147
- },
148
- [handleUpdate, materialTargetSide, node],
149
- )
150
-
151
- const handleCustomMaterialChange = useCallback(
152
- (material: MaterialSchema) => {
153
- if (!node || !materialTargetSide) return
154
- handleUpdate(buildWallSurfaceMaterialPatch(node, materialTargetSide, material, undefined))
155
- },
156
- [handleUpdate, materialTargetSide, node],
157
- )
158
-
159
82
  const handleClose = useCallback(() => {
160
83
  setSelection({ selectedIds: [] })
161
84
  }, [setSelection])
@@ -237,23 +160,6 @@ export function WallPanel() {
237
160
  )}
238
161
  </PanelSection>
239
162
 
240
- <PanelSection title="Material">
241
- {!materialTargetSide ? (
242
- <div className="mb-3 rounded-lg border border-border/50 bg-[#2C2C2E] px-3 py-2 text-[11px] text-muted-foreground">
243
- Click the wall face you want to edit. Materials now apply to one side at a time.
244
- </div>
245
- ) : null}
246
- <MaterialPicker
247
- disabled={!materialTargetSide}
248
- hideSideControl
249
- nodeType="wall"
250
- onChange={handleCustomMaterialChange}
251
- onSelectMaterialPreset={handleMaterialPresetChange}
252
- selectedMaterialPreset={materialPickerValue.materialPreset}
253
- value={materialPickerValue.material}
254
- />
255
- </PanelSection>
256
-
257
163
  <PanelSection title="Actions">
258
164
  <ActionGroup>
259
165
  <ActionButton icon={<Move className="h-3.5 w-3.5" />} label="Move" onClick={handleMove} />