@pascal-app/core 0.1.12 → 0.2.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 (85) hide show
  1. package/dist/events/bus.d.ts +22 -2
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/scene-registry.d.ts +6 -1
  4. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  5. package/dist/hooks/scene-registry/scene-registry.js +11 -1
  6. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +17 -12
  7. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  8. package/dist/hooks/spatial-grid/spatial-grid-manager.js +135 -38
  9. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +1 -1
  10. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  11. package/dist/hooks/spatial-grid/spatial-grid-sync.js +16 -8
  12. package/dist/hooks/spatial-grid/spatial-grid.d.ts +3 -3
  13. package/dist/hooks/spatial-grid/spatial-grid.d.ts.map +1 -1
  14. package/dist/hooks/spatial-grid/spatial-grid.js +2 -2
  15. package/dist/hooks/spatial-grid/use-spatial-query.d.ts +5 -0
  16. package/dist/hooks/spatial-grid/use-spatial-query.d.ts.map +1 -1
  17. package/dist/hooks/spatial-grid/wall-spatial-grid.d.ts +6 -3
  18. package/dist/hooks/spatial-grid/wall-spatial-grid.d.ts.map +1 -1
  19. package/dist/hooks/spatial-grid/wall-spatial-grid.js +35 -10
  20. package/dist/index.d.ts +8 -5
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +9 -6
  23. package/dist/lib/space-detection.d.ts.map +1 -1
  24. package/dist/lib/space-detection.js +1 -1
  25. package/dist/schema/collections.d.ts +11 -0
  26. package/dist/schema/collections.d.ts.map +1 -0
  27. package/dist/schema/collections.js +2 -0
  28. package/dist/schema/index.d.ts +11 -7
  29. package/dist/schema/index.d.ts.map +1 -1
  30. package/dist/schema/index.js +11 -6
  31. package/dist/schema/nodes/ceiling.d.ts +1 -0
  32. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  33. package/dist/schema/nodes/ceiling.js +2 -0
  34. package/dist/schema/nodes/door.d.ts +78 -0
  35. package/dist/schema/nodes/door.d.ts.map +1 -0
  36. package/dist/schema/nodes/door.js +67 -0
  37. package/dist/schema/nodes/item.d.ts +245 -2
  38. package/dist/schema/nodes/item.d.ts.map +1 -1
  39. package/dist/schema/nodes/item.js +72 -0
  40. package/dist/schema/nodes/level.d.ts.map +1 -1
  41. package/dist/schema/nodes/level.js +11 -1
  42. package/dist/schema/nodes/roof-segment.d.ts +51 -0
  43. package/dist/schema/nodes/roof-segment.d.ts.map +1 -0
  44. package/dist/schema/nodes/roof-segment.js +36 -0
  45. package/dist/schema/nodes/roof.d.ts +1 -4
  46. package/dist/schema/nodes/roof.d.ts.map +1 -1
  47. package/dist/schema/nodes/roof.js +9 -16
  48. package/dist/schema/nodes/site.d.ts +52 -1
  49. package/dist/schema/nodes/site.d.ts.map +1 -1
  50. package/dist/schema/nodes/slab.d.ts +1 -0
  51. package/dist/schema/nodes/slab.d.ts.map +1 -1
  52. package/dist/schema/nodes/slab.js +1 -0
  53. package/dist/schema/nodes/window.d.ts +40 -0
  54. package/dist/schema/nodes/window.d.ts.map +1 -0
  55. package/dist/schema/nodes/window.js +38 -0
  56. package/dist/schema/types.d.ts +241 -6
  57. package/dist/schema/types.d.ts.map +1 -1
  58. package/dist/schema/types.js +6 -0
  59. package/dist/store/actions/node-actions.d.ts.map +1 -1
  60. package/dist/store/actions/node-actions.js +23 -4
  61. package/dist/store/use-interactive.d.ts +18 -0
  62. package/dist/store/use-interactive.d.ts.map +1 -0
  63. package/dist/store/use-interactive.js +50 -0
  64. package/dist/store/use-scene.d.ts +10 -1
  65. package/dist/store/use-scene.d.ts.map +1 -1
  66. package/dist/store/use-scene.js +180 -57
  67. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  68. package/dist/systems/ceiling/ceiling-system.js +20 -0
  69. package/dist/systems/door/door-system.d.ts +2 -0
  70. package/dist/systems/door/door-system.d.ts.map +1 -0
  71. package/dist/systems/door/door-system.js +211 -0
  72. package/dist/systems/item/item-system.d.ts.map +1 -1
  73. package/dist/systems/item/item-system.js +10 -5
  74. package/dist/systems/roof/roof-system.d.ts +11 -3
  75. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  76. package/dist/systems/roof/roof-system.js +705 -210
  77. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  78. package/dist/systems/slab/slab-system.js +18 -3
  79. package/dist/systems/wall/wall-mitering.js +2 -2
  80. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  81. package/dist/systems/wall/wall-system.js +11 -13
  82. package/dist/systems/window/window-system.d.ts +2 -0
  83. package/dist/systems/window/window-system.d.ts.map +1 -0
  84. package/dist/systems/window/window-system.js +147 -0
  85. package/package.json +10 -8
@@ -7,6 +7,11 @@ export declare function useSpatialQuery(): {
7
7
  canPlaceOnWall: (levelId: LevelNode["id"], wallId: WallNode["id"], localX: number, localY: number, dimensions: [number, number, number], attachType?: "wall" | "wall-side", side?: "front" | "back", ignoreIds?: string[]) => {
8
8
  valid: boolean;
9
9
  conflictIds: string[];
10
+ adjustedY: number;
11
+ wasAdjusted: boolean;
12
+ } | {
13
+ valid: boolean;
14
+ conflictIds: never[];
10
15
  };
11
16
  canPlaceOnCeiling: (ceilingId: CeilingNode["id"], position: [number, number, number], dimensions: [number, number, number], rotation: [number, number, number], ignoreIds?: string[]) => {
12
17
  valid: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"use-spatial-query.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/use-spatial-query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGpE,wBAAgB,eAAe;+BAGhB,SAAS,CAAC,IAAI,CAAC,YACd,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,YAC1B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,MAAM,EAAE;;;;8BASX,SAAS,CAAC,IAAI,CAAC,UAChB,QAAQ,CAAC,IAAI,CAAC,UACd,MAAM,UACN,MAAM,cACF,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,eACxB,MAAM,GAAG,WAAW,SACzB,OAAO,GAAG,MAAM,cACX,MAAM,EAAE;;;;mCAkBT,WAAW,CAAC,IAAI,CAAC,YAClB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,YAC1B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,MAAM,EAAE;;;;EAQzB"}
1
+ {"version":3,"file":"use-spatial-query.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/use-spatial-query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGpE,wBAAgB,eAAe;+BAGhB,SAAS,CAAC,IAAI,CAAC,YACd,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,YAC1B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,MAAM,EAAE;;;;8BASX,SAAS,CAAC,IAAI,CAAC,UAChB,QAAQ,CAAC,IAAI,CAAC,UACd,MAAM,UACN,MAAM,cACF,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,eACxB,MAAM,GAAG,WAAW,SACzB,OAAO,GAAG,MAAM,cACX,MAAM,EAAE;;;;;;;;;mCAkBT,WAAW,CAAC,IAAI,CAAC,YAClB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,YAC1B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,cACtB,MAAM,EAAE;;;;EAczB"}
@@ -11,10 +11,10 @@ interface WallItemPlacement {
11
11
  side?: WallSide;
12
12
  }
13
13
  export declare class WallSpatialGrid {
14
- private wallItems;
15
- private itemToWall;
14
+ private readonly wallItems;
15
+ private readonly itemToWall;
16
16
  /**
17
- * Check if an item can be placed on a wall
17
+ * Check if an item can be placed on a wall with auto-adjustment for vertical position
18
18
  * @param wallId - The wall to place on
19
19
  * @param wallLength - Length of the wall
20
20
  * @param wallHeight - Height of the wall
@@ -25,10 +25,13 @@ export declare class WallSpatialGrid {
25
25
  * @param attachType - 'wall' (blocks both sides) or 'wall-side' (blocks one side)
26
26
  * @param side - Which side for 'wall-side' items
27
27
  * @param ignoreIds - Item IDs to ignore in conflict check
28
+ * @returns Validation result with auto-adjusted Y position if needed
28
29
  */
29
30
  canPlaceOnWall(wallId: string, wallLength: number, wallHeight: number, tCenter: number, itemWidth: number, yBottom: number, itemHeight: number, attachType?: AttachType, side?: WallSide, ignoreIds?: string[]): {
30
31
  valid: boolean;
31
32
  conflictIds: string[];
33
+ adjustedY: number;
34
+ wasAdjusted: boolean;
32
35
  };
33
36
  /**
34
37
  * Check if two items conflict based on their attach types and sides
@@ -1 +1 @@
1
- {"version":3,"file":"wall-spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/wall-spatial-grid.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;AAChC,KAAK,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;AAKtC,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,UAAU,CAA4B;IAE9C;;;;;;;;;;;;OAYG;IACH,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,UAAmB,EAC/B,IAAI,CAAC,EAAE,QAAQ,EACf,SAAS,GAAE,MAAM,EAAO,GACvB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IAoC5C;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IA0BzB,MAAM,CAAC,SAAS,EAAE,iBAAiB;IAUnC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IASrC,cAAc,CAAC,MAAM,EAAE,MAAM;IAQ7B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAapC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIlD,KAAK;CAIN"}
1
+ {"version":3,"file":"wall-spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/wall-spatial-grid.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAA;AAChC,KAAK,UAAU,GAAG,MAAM,GAAG,WAAW,CAAA;AAQtC,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,IAAI,CAAC,EAAE,QAAQ,CAAA;CAChB;AAgCD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4B;IAEvD;;;;;;;;;;;;;OAaG;IACH,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,UAAmB,EAC/B,IAAI,CAAC,EAAE,QAAQ,EACf,SAAS,GAAE,MAAM,EAAO,GACvB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE;IAsCrF;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IA0BzB,MAAM,CAAC,SAAS,EAAE,iBAAiB;IAUnC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IASrC,cAAc,CAAC,MAAM,EAAE,MAAM;IAQ7B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAapC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIlD,KAAK;CAIN"}
@@ -1,10 +1,33 @@
1
1
  // Small tolerance for floating point comparison to allow adjacent items
2
2
  const EPSILON = 0.001;
3
+ // Margin from ceiling/floor when auto-snapping items
4
+ const AUTO_SNAP_MARGIN = 0.05;
5
+ /**
6
+ * Auto-adjust Y position to fit item within wall bounds
7
+ * Returns the adjusted Y position (bottom of item)
8
+ */
9
+ function autoAdjustYPosition(yBottom, itemHeight, wallHeight) {
10
+ const yTop = yBottom + itemHeight;
11
+ // If fits perfectly, no adjustment needed
12
+ if (yBottom >= 0 && yTop <= wallHeight) {
13
+ return { adjustedY: yBottom, wasAdjusted: false };
14
+ }
15
+ // If too high (top exceeds wall height), snap down from ceiling
16
+ if (yTop > wallHeight) {
17
+ const adjustedY = wallHeight - itemHeight - AUTO_SNAP_MARGIN;
18
+ return { adjustedY: Math.max(0, adjustedY), wasAdjusted: true };
19
+ }
20
+ // If too low (bottom below floor), snap up from floor
21
+ if (yBottom < 0) {
22
+ return { adjustedY: AUTO_SNAP_MARGIN, wasAdjusted: true };
23
+ }
24
+ return { adjustedY: yBottom, wasAdjusted: false };
25
+ }
3
26
  export class WallSpatialGrid {
4
27
  wallItems = new Map(); // wallId -> placements
5
28
  itemToWall = new Map(); // itemId -> wallId (reverse lookup)
6
29
  /**
7
- * Check if an item can be placed on a wall
30
+ * Check if an item can be placed on a wall with auto-adjustment for vertical position
8
31
  * @param wallId - The wall to place on
9
32
  * @param wallLength - Length of the wall
10
33
  * @param wallHeight - Height of the wall
@@ -15,18 +38,20 @@ export class WallSpatialGrid {
15
38
  * @param attachType - 'wall' (blocks both sides) or 'wall-side' (blocks one side)
16
39
  * @param side - Which side for 'wall-side' items
17
40
  * @param ignoreIds - Item IDs to ignore in conflict check
41
+ * @returns Validation result with auto-adjusted Y position if needed
18
42
  */
19
43
  canPlaceOnWall(wallId, wallLength, wallHeight, tCenter, itemWidth, yBottom, itemHeight, attachType = 'wall', side, ignoreIds = []) {
20
44
  const halfW = itemWidth / wallLength / 2;
21
45
  const tStart = tCenter - halfW;
22
46
  const tEnd = tCenter + halfW;
23
- // yBottom is the bottom of the item, so yEnd = yBottom + itemHeight
24
- const yStart = yBottom;
25
- const yEnd = yBottom + itemHeight;
26
- // Check wall boundaries
27
- if (tStart < 0 || tEnd > 1 || yStart < 0 || yEnd > wallHeight) {
28
- return { valid: false, conflictIds: [] };
47
+ // Check horizontal boundaries (still reject if item exceeds wall width)
48
+ if (tStart < 0 || tEnd > 1) {
49
+ return { valid: false, conflictIds: [], adjustedY: yBottom, wasAdjusted: false };
29
50
  }
51
+ // Auto-adjust vertical position to fit within wall bounds
52
+ const { adjustedY, wasAdjusted } = autoAdjustYPosition(yBottom, itemHeight, wallHeight);
53
+ const yStart = adjustedY;
54
+ const yEnd = adjustedY + itemHeight;
30
55
  const existing = this.wallItems.get(wallId) ?? [];
31
56
  const ignoreSet = new Set(ignoreIds);
32
57
  const conflicts = [];
@@ -44,7 +69,7 @@ export class WallSpatialGrid {
44
69
  }
45
70
  }
46
71
  }
47
- return { valid: conflicts.length === 0, conflictIds: conflicts };
72
+ return { valid: conflicts.length === 0, conflictIds: conflicts, adjustedY, wasAdjusted };
48
73
  }
49
74
  /**
50
75
  * Check if two items conflict based on their attach types and sides
@@ -64,7 +89,7 @@ export class WallSpatialGrid {
64
89
  }
65
90
  // Both are 'wall-side' - only conflict if they're on the same side
66
91
  // If either side is undefined, be conservative and assume conflict
67
- if (!newSide || !existing.side) {
92
+ if (!(newSide && existing.side)) {
68
93
  return true;
69
94
  }
70
95
  return newSide === existing.side;
@@ -74,7 +99,7 @@ export class WallSpatialGrid {
74
99
  if (!this.wallItems.has(wallId)) {
75
100
  this.wallItems.set(wallId, []);
76
101
  }
77
- this.wallItems.get(wallId).push(placement);
102
+ this.wallItems.get(wallId)?.push(placement);
78
103
  this.itemToWall.set(itemId, wallId);
79
104
  }
80
105
  remove(wallId, itemId) {
package/dist/index.d.ts CHANGED
@@ -1,17 +1,20 @@
1
- export type { BuildingEvent, CameraControlEvent, EventSuffix, GridEvent, ItemEvent, LevelEvent, NodeEvent, SiteEvent, SlabEvent, WallEvent, ZoneEvent, CeilingEvent, RoofEvent, } from './events/bus';
1
+ export type { BuildingEvent, CameraControlEvent, CeilingEvent, DoorEvent, EventSuffix, GridEvent, ItemEvent, LevelEvent, NodeEvent, RoofEvent, RoofSegmentEvent, SiteEvent, SlabEvent, WallEvent, WindowEvent, ZoneEvent, } from './events/bus';
2
2
  export { emitter, eventSuffixes } from './events/bus';
3
3
  export { sceneRegistry, useRegistry, } from './hooks/scene-registry/scene-registry';
4
+ export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
4
5
  export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
5
6
  export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
6
- export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
7
+ export { loadAssetUrl, saveAsset } from './lib/asset-storage';
8
+ export { detectSpacesForLevel, initSpaceDetectionSync, type Space, wallTouchesOthers, } from './lib/space-detection';
7
9
  export * from './schema';
8
- export { default as useScene } from './store/use-scene';
10
+ export { type ControlValue, type ItemInteractiveState, useInteractive, } from './store/use-interactive';
11
+ export { clearSceneHistory, default as useScene } from './store/use-scene';
9
12
  export { CeilingSystem } from './systems/ceiling/ceiling-system';
13
+ export { DoorSystem } from './systems/door/door-system';
10
14
  export { ItemSystem } from './systems/item/item-system';
11
15
  export { RoofSystem } from './systems/roof/roof-system';
12
16
  export { SlabSystem } from './systems/slab/slab-system';
13
17
  export { WallSystem } from './systems/wall/wall-system';
18
+ export { WindowSystem } from './systems/window/window-system';
14
19
  export { isObject } from './utils/types';
15
- export { saveAsset, loadAssetUrl } from './lib/asset-storage';
16
- export { detectSpacesForLevel, wallTouchesOthers, initSpaceDetectionSync, type Space } from './lib/space-detection';
17
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAY,EACZ,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAErD,OAAO,EACL,aAAa,EACb,WAAW,GACZ,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAE9F,cAAc,UAAU,CAAA;AACxB,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAErD,OAAO,EACL,aAAa,EACb,WAAW,GACZ,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAC9F,OAAO,EACL,mBAAmB,EACnB,cAAc,GACf,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wCAAwC,CAAA;AAExE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,KAAK,EACV,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAE9B,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,iBAAiB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAA;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
package/dist/index.js CHANGED
@@ -3,20 +3,23 @@
3
3
  export { emitter, eventSuffixes } from './events/bus';
4
4
  // Hooks
5
5
  export { sceneRegistry, useRegistry, } from './hooks/scene-registry/scene-registry';
6
+ export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
6
7
  export { initSpatialGridSync, resolveLevelId, } from './hooks/spatial-grid/spatial-grid-sync';
7
8
  export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
8
- export { pointInPolygon, spatialGridManager } from './hooks/spatial-grid/spatial-grid-manager';
9
+ // Asset storage
10
+ export { loadAssetUrl, saveAsset } from './lib/asset-storage';
11
+ // Space detection
12
+ export { detectSpacesForLevel, initSpaceDetectionSync, wallTouchesOthers, } from './lib/space-detection';
9
13
  // Schema
10
14
  export * from './schema';
11
- export { default as useScene } from './store/use-scene';
15
+ export { useInteractive, } from './store/use-interactive';
16
+ export { clearSceneHistory, default as useScene } from './store/use-scene';
12
17
  // Systems
13
18
  export { CeilingSystem } from './systems/ceiling/ceiling-system';
19
+ export { DoorSystem } from './systems/door/door-system';
14
20
  export { ItemSystem } from './systems/item/item-system';
15
21
  export { RoofSystem } from './systems/roof/roof-system';
16
22
  export { SlabSystem } from './systems/slab/slab-system';
17
23
  export { WallSystem } from './systems/wall/wall-system';
24
+ export { WindowSystem } from './systems/window/window-system';
18
25
  export { isObject } from './utils/types';
19
- // Asset storage
20
- export { saveAsset, loadAssetUrl } from './lib/asset-storage';
21
- // Space detection
22
- export { detectSpacesForLevel, wallTouchesOthers, initSpaceDetectionSync } from './lib/space-detection';
@@ -1 +1 @@
1
- {"version":3,"file":"space-detection.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAMzC,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,GAAG,EAAE,iBAAiB;AAClC,WAAW,EAAE,GAAG,GACf,MAAM,IAAI,CAgGZ;AA+DD,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;IAC9C,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;CAC9C,CAAA;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,QAAQ,EAAE,EACjB,cAAc,GAAE,MAAY,GAC3B;IACD,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,MAAM,EAAE,KAAK,EAAE,CAAA;CAChB,CAqBA;AAsWD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAkBjF"}
1
+ {"version":3,"file":"space-detection.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAMzC,MAAM,MAAM,KAAK,GAAG;IAClB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChC,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,GAAG,EAAE,iBAAiB;AAClC,WAAW,EAAE,GAAG,GACf,MAAM,IAAI,CAgGZ;AA+DD,KAAK,cAAc,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;IAC9C,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAA;CAC9C,CAAA;AAMD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,QAAQ,EAAE,EACjB,cAAc,SAAM,GACnB;IACD,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,MAAM,EAAE,KAAK,EAAE,CAAA;CAChB,CAqBA;AAsWD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAkBjF"}
@@ -23,7 +23,7 @@ editorStore) {
23
23
  if (!currentWallsByLevel.has(levelId)) {
24
24
  currentWallsByLevel.set(levelId, new Set());
25
25
  }
26
- currentWallsByLevel.get(levelId).add(node.id);
26
+ currentWallsByLevel.get(levelId)?.add(node.id);
27
27
  }
28
28
  }
29
29
  // Check each level for changes
@@ -0,0 +1,11 @@
1
+ import type { AnyNodeId } from './types';
2
+ export type CollectionId = `collection_${string}`;
3
+ export type Collection = {
4
+ id: CollectionId;
5
+ name: string;
6
+ color?: string;
7
+ nodeIds: AnyNodeId[];
8
+ controlNodeId?: AnyNodeId;
9
+ };
10
+ export declare const generateCollectionId: () => CollectionId;
11
+ //# sourceMappingURL=collections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/schema/collections.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG,cAAc,MAAM,EAAE,CAAA;AAEjD,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,YAAY,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,aAAa,CAAC,EAAE,SAAS,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,oBAAoB,QAAO,YAAwC,CAAA"}
@@ -0,0 +1,2 @@
1
+ import { generateId } from './base';
2
+ export const generateCollectionId = () => generateId('collection');
@@ -1,17 +1,21 @@
1
1
  export { BaseNode, generateId, Material, nodeType, objectId } from './base';
2
2
  export { CameraSchema } from './camera';
3
- export type { AssetInput } from './nodes/item';
4
- export { ItemNode } from './nodes/item';
3
+ export { type Collection, type CollectionId, generateCollectionId } from './collections';
4
+ export { BuildingNode } from './nodes/building';
5
+ export { CeilingNode } from './nodes/ceiling';
6
+ export { DoorNode, DoorSegment } from './nodes/door';
7
+ export { GuideNode } from './nodes/guide';
8
+ export type { AnimationEffect, Asset, AssetInput, Control, Effect, Interactive, LightEffect, SliderControl, TemperatureControl, ToggleControl, } from './nodes/item';
9
+ export { getScaledDimensions, ItemNode } from './nodes/item';
5
10
  export { LevelNode } from './nodes/level';
11
+ export { RoofNode } from './nodes/roof';
12
+ export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
13
+ export { ScanNode } from './nodes/scan';
6
14
  export { SiteNode } from './nodes/site';
7
15
  export { SlabNode } from './nodes/slab';
8
16
  export { WallNode } from './nodes/wall';
9
- export { BuildingNode } from './nodes/building';
10
- export { CeilingNode } from './nodes/ceiling';
17
+ export { WindowNode } from './nodes/window';
11
18
  export { ZoneNode } from './nodes/zone';
12
- export { RoofNode } from './nodes/roof';
13
- export { ScanNode } from './nodes/scan';
14
- export { GuideNode } from './nodes/guide';
15
19
  export type { AnyNodeId, AnyNodeType } from './types';
16
20
  export { AnyNode } from './types';
17
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvC,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AACxF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,YAAY,EACV,eAAe,EACf,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,aAAa,GACd,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AACvC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA"}
@@ -2,17 +2,22 @@
2
2
  export { BaseNode, generateId, Material, nodeType, objectId } from './base';
3
3
  // Camera
4
4
  export { CameraSchema } from './camera';
5
- export { ItemNode } from './nodes/item';
5
+ // Collections
6
+ export { generateCollectionId } from './collections';
7
+ export { BuildingNode } from './nodes/building';
8
+ export { CeilingNode } from './nodes/ceiling';
9
+ export { DoorNode, DoorSegment } from './nodes/door';
10
+ export { GuideNode } from './nodes/guide';
11
+ export { getScaledDimensions, ItemNode } from './nodes/item';
6
12
  export { LevelNode } from './nodes/level';
13
+ export { RoofNode } from './nodes/roof';
14
+ export { RoofSegmentNode, RoofType } from './nodes/roof-segment';
15
+ export { ScanNode } from './nodes/scan';
7
16
  // Nodes
8
17
  export { SiteNode } from './nodes/site';
9
18
  export { SlabNode } from './nodes/slab';
10
19
  export { WallNode } from './nodes/wall';
11
- export { BuildingNode } from './nodes/building';
12
- export { CeilingNode } from './nodes/ceiling';
20
+ export { WindowNode } from './nodes/window';
13
21
  export { ZoneNode } from './nodes/zone';
14
- export { RoofNode } from './nodes/roof';
15
- export { ScanNode } from './nodes/scan';
16
- export { GuideNode } from './nodes/guide';
17
22
  // Union types
18
23
  export { AnyNode } from './types';
@@ -19,6 +19,7 @@ export declare const CeilingNode: z.ZodObject<{
19
19
  type: z.ZodDefault<z.ZodLiteral<"ceiling">>;
20
20
  children: z.ZodDefault<z.ZodArray<z.ZodDefault<z.ZodTemplateLiteral<`item_${string}`>>>>;
21
21
  polygon: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
22
+ holes: z.ZodDefault<z.ZodArray<z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>>>;
22
23
  height: z.ZodDefault<z.ZodNumber>;
23
24
  }, z.core.$strip>;
24
25
  export type CeilingNode = z.infer<typeof CeilingNode>;
@@ -1 +1 @@
1
- {"version":3,"file":"ceiling.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/ceiling.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;iBAavB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA"}
1
+ {"version":3,"file":"ceiling.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/ceiling.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;iBAevB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA"}
@@ -9,8 +9,10 @@ export const CeilingNode = BaseNode.extend({
9
9
  // Specific props
10
10
  // Polygon boundary - array of [x, z] coordinates defining the ceiling
11
11
  polygon: z.array(z.tuple([z.number(), z.number()])),
12
+ holes: z.array(z.array(z.tuple([z.number(), z.number()]))).default([]),
12
13
  height: z.number().default(2.5), // Height in meters
13
14
  }).describe(dedent `
14
15
  Ceiling node - used to represent a ceiling in the building
15
16
  - polygon: array of [x, z] points defining the ceiling boundary
17
+ - holes: array of polygons representing holes in the ceiling
16
18
  `);
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ export declare const DoorSegment: z.ZodObject<{
3
+ type: z.ZodEnum<{
4
+ panel: "panel";
5
+ glass: "glass";
6
+ empty: "empty";
7
+ }>;
8
+ heightRatio: z.ZodNumber;
9
+ columnRatios: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
10
+ dividerThickness: z.ZodDefault<z.ZodNumber>;
11
+ panelDepth: z.ZodDefault<z.ZodNumber>;
12
+ panelInset: z.ZodDefault<z.ZodNumber>;
13
+ }, z.core.$strip>;
14
+ export type DoorSegment = z.infer<typeof DoorSegment>;
15
+ export declare const DoorNode: z.ZodObject<{
16
+ object: z.ZodDefault<z.ZodLiteral<"node">>;
17
+ name: z.ZodOptional<z.ZodString>;
18
+ parentId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
19
+ visible: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
20
+ camera: z.ZodOptional<z.ZodObject<{
21
+ position: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
22
+ target: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
23
+ mode: z.ZodDefault<z.ZodEnum<{
24
+ perspective: "perspective";
25
+ orthographic: "orthographic";
26
+ }>>;
27
+ fov: z.ZodOptional<z.ZodNumber>;
28
+ zoom: z.ZodOptional<z.ZodNumber>;
29
+ }, z.core.$strip>>;
30
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
31
+ id: z.ZodDefault<z.ZodTemplateLiteral<`door_${string}`>>;
32
+ type: z.ZodDefault<z.ZodLiteral<"door">>;
33
+ position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
34
+ rotation: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
35
+ side: z.ZodOptional<z.ZodEnum<{
36
+ front: "front";
37
+ back: "back";
38
+ }>>;
39
+ wallId: z.ZodOptional<z.ZodString>;
40
+ width: z.ZodDefault<z.ZodNumber>;
41
+ height: z.ZodDefault<z.ZodNumber>;
42
+ frameThickness: z.ZodDefault<z.ZodNumber>;
43
+ frameDepth: z.ZodDefault<z.ZodNumber>;
44
+ threshold: z.ZodDefault<z.ZodBoolean>;
45
+ thresholdHeight: z.ZodDefault<z.ZodNumber>;
46
+ hingesSide: z.ZodDefault<z.ZodEnum<{
47
+ left: "left";
48
+ right: "right";
49
+ }>>;
50
+ swingDirection: z.ZodDefault<z.ZodEnum<{
51
+ inward: "inward";
52
+ outward: "outward";
53
+ }>>;
54
+ segments: z.ZodDefault<z.ZodArray<z.ZodObject<{
55
+ type: z.ZodEnum<{
56
+ panel: "panel";
57
+ glass: "glass";
58
+ empty: "empty";
59
+ }>;
60
+ heightRatio: z.ZodNumber;
61
+ columnRatios: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
62
+ dividerThickness: z.ZodDefault<z.ZodNumber>;
63
+ panelDepth: z.ZodDefault<z.ZodNumber>;
64
+ panelInset: z.ZodDefault<z.ZodNumber>;
65
+ }, z.core.$strip>>>;
66
+ handle: z.ZodDefault<z.ZodBoolean>;
67
+ handleHeight: z.ZodDefault<z.ZodNumber>;
68
+ handleSide: z.ZodDefault<z.ZodEnum<{
69
+ left: "left";
70
+ right: "right";
71
+ }>>;
72
+ contentPadding: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
73
+ doorCloser: z.ZodDefault<z.ZodBoolean>;
74
+ panicBar: z.ZodDefault<z.ZodBoolean>;
75
+ panicBarHeight: z.ZodDefault<z.ZodNumber>;
76
+ }, z.core.$strip>;
77
+ export type DoorNode = z.infer<typeof DoorNode>;
78
+ //# sourceMappingURL=door.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"door.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/door.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,WAAW;;;;;;;;;;;iBAWtB,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AAErD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6DnB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA"}
@@ -0,0 +1,67 @@
1
+ import dedent from 'dedent';
2
+ import { z } from 'zod';
3
+ import { BaseNode, nodeType, objectId } from '../base';
4
+ export const DoorSegment = z.object({
5
+ type: z.enum(['panel', 'glass', 'empty']),
6
+ heightRatio: z.number(),
7
+ // Each segment controls its own column split
8
+ columnRatios: z.array(z.number()).default([1]),
9
+ dividerThickness: z.number().default(0.03),
10
+ // panel-specific
11
+ panelDepth: z.number().default(0.01), // + raised, - recessed
12
+ panelInset: z.number().default(0.04),
13
+ });
14
+ export const DoorNode = BaseNode.extend({
15
+ id: objectId('door'),
16
+ type: nodeType('door'),
17
+ position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
18
+ rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
19
+ side: z.enum(['front', 'back']).optional(),
20
+ wallId: z.string().optional(),
21
+ // Overall dimensions
22
+ width: z.number().default(0.9),
23
+ height: z.number().default(2.1),
24
+ // Frame
25
+ frameThickness: z.number().default(0.05),
26
+ frameDepth: z.number().default(0.07),
27
+ threshold: z.boolean().default(true),
28
+ thresholdHeight: z.number().default(0.02),
29
+ // Swing
30
+ hingesSide: z.enum(['left', 'right']).default('left'),
31
+ swingDirection: z.enum(['inward', 'outward']).default('inward'),
32
+ // Leaf segments — stacked top to bottom, each with its own column split
33
+ segments: z.array(DoorSegment).default([
34
+ {
35
+ type: 'panel',
36
+ heightRatio: 0.4,
37
+ columnRatios: [1],
38
+ dividerThickness: 0.03,
39
+ panelDepth: 0.01,
40
+ panelInset: 0.04,
41
+ },
42
+ {
43
+ type: 'panel',
44
+ heightRatio: 0.6,
45
+ columnRatios: [1],
46
+ dividerThickness: 0.03,
47
+ panelDepth: 0.01,
48
+ panelInset: 0.04,
49
+ },
50
+ ]),
51
+ // Handle
52
+ handle: z.boolean().default(true),
53
+ handleHeight: z.number().default(1.05),
54
+ handleSide: z.enum(['left', 'right']).default('right'),
55
+ // Leaf inner margin — space between leaf edge and segment content area [x, y]
56
+ contentPadding: z.tuple([z.number(), z.number()]).default([0.04, 0.04]),
57
+ // Emergency / commercial hardware
58
+ doorCloser: z.boolean().default(false),
59
+ panicBar: z.boolean().default(false),
60
+ panicBarHeight: z.number().default(1.0),
61
+ }).describe(dedent `Door node - a parametric door placed on a wall
62
+ - position: center of the door in wall-local coordinate system (Y = height/2, always at floor)
63
+ - segments: rows stacked top to bottom, each defining its own columnRatios
64
+ - type 'empty' = flush flat fill, 'panel' = raised/recessed panel, 'glass' = glazed
65
+ - hingesSide/swingDirection: which way the door opens
66
+ - doorCloser/panicBar: commercial and emergency hardware options
67
+ `);