@pascal-app/core 0.5.1 → 0.6.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 (91) hide show
  1. package/dist/events/bus.d.ts +37 -3
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/events/bus.js +1 -1
  4. package/dist/hooks/spatial-grid/spatial-grid.d.ts +2 -0
  5. package/dist/hooks/spatial-grid/spatial-grid.d.ts.map +1 -1
  6. package/dist/hooks/spatial-grid/spatial-grid.js +43 -20
  7. package/dist/index.d.ts +4 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -1
  10. package/dist/lib/polygon-geometry.d.ts +3 -0
  11. package/dist/lib/polygon-geometry.d.ts.map +1 -0
  12. package/dist/lib/polygon-geometry.js +90 -0
  13. package/dist/lib/space-detection.d.ts +10 -17
  14. package/dist/lib/space-detection.d.ts.map +1 -1
  15. package/dist/lib/space-detection.js +666 -453
  16. package/dist/material-library.d.ts +18 -0
  17. package/dist/material-library.d.ts.map +1 -0
  18. package/dist/material-library.js +603 -0
  19. package/dist/schema/index.d.ts +9 -4
  20. package/dist/schema/index.d.ts.map +1 -1
  21. package/dist/schema/index.js +5 -4
  22. package/dist/schema/material.d.ts +109 -0
  23. package/dist/schema/material.d.ts.map +1 -1
  24. package/dist/schema/material.js +52 -0
  25. package/dist/schema/nodes/ceiling.d.ts +10 -0
  26. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  27. package/dist/schema/nodes/ceiling.js +6 -0
  28. package/dist/schema/nodes/door.d.ts +1 -0
  29. package/dist/schema/nodes/door.d.ts.map +1 -1
  30. package/dist/schema/nodes/fence.d.ts +34 -0
  31. package/dist/schema/nodes/fence.d.ts.map +1 -1
  32. package/dist/schema/nodes/fence.js +5 -0
  33. package/dist/schema/nodes/item.d.ts +2 -2
  34. package/dist/schema/nodes/roof-segment.d.ts +2 -0
  35. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  36. package/dist/schema/nodes/roof-segment.js +1 -0
  37. package/dist/schema/nodes/roof.d.ts +108 -0
  38. package/dist/schema/nodes/roof.d.ts.map +1 -1
  39. package/dist/schema/nodes/roof.js +58 -2
  40. package/dist/schema/nodes/site.d.ts +1 -1
  41. package/dist/schema/nodes/slab.d.ts +10 -0
  42. package/dist/schema/nodes/slab.d.ts.map +1 -1
  43. package/dist/schema/nodes/slab.js +7 -0
  44. package/dist/schema/nodes/stair-segment.d.ts +2 -0
  45. package/dist/schema/nodes/stair-segment.d.ts.map +1 -1
  46. package/dist/schema/nodes/stair-segment.js +1 -0
  47. package/dist/schema/nodes/stair.d.ts +122 -2
  48. package/dist/schema/nodes/stair.d.ts.map +1 -1
  49. package/dist/schema/nodes/stair.js +72 -2
  50. package/dist/schema/nodes/surface-hole-metadata.d.ts +10 -0
  51. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -0
  52. package/dist/schema/nodes/surface-hole-metadata.js +5 -0
  53. package/dist/schema/nodes/wall.d.ts +87 -1
  54. package/dist/schema/nodes/wall.d.ts.map +1 -1
  55. package/dist/schema/nodes/wall.js +45 -4
  56. package/dist/schema/nodes/window.d.ts +1 -0
  57. package/dist/schema/nodes/window.d.ts.map +1 -1
  58. package/dist/schema/types.d.ts +343 -5
  59. package/dist/schema/types.d.ts.map +1 -1
  60. package/dist/store/actions/node-actions.d.ts +1 -1
  61. package/dist/store/actions/node-actions.d.ts.map +1 -1
  62. package/dist/store/actions/node-actions.js +175 -0
  63. package/dist/store/history-control.d.ts +14 -0
  64. package/dist/store/history-control.d.ts.map +1 -0
  65. package/dist/store/history-control.js +22 -0
  66. package/dist/store/use-scene.d.ts.map +1 -1
  67. package/dist/store/use-scene.js +248 -2
  68. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  69. package/dist/systems/ceiling/ceiling-system.js +7 -0
  70. package/dist/systems/fence/fence-system.d.ts.map +1 -1
  71. package/dist/systems/fence/fence-system.js +106 -39
  72. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  73. package/dist/systems/roof/roof-system.js +31 -1
  74. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  75. package/dist/systems/slab/slab-system.js +45 -8
  76. package/dist/systems/stair/stair-opening-sync.d.ts +6 -0
  77. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -0
  78. package/dist/systems/stair/stair-opening-sync.js +515 -0
  79. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  80. package/dist/systems/stair/stair-system.js +119 -2
  81. package/dist/systems/wall/wall-curve.d.ts +43 -0
  82. package/dist/systems/wall/wall-curve.d.ts.map +1 -0
  83. package/dist/systems/wall/wall-curve.js +176 -0
  84. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  85. package/dist/systems/wall/wall-footprint.js +16 -2
  86. package/dist/systems/wall/wall-mitering.d.ts +7 -0
  87. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  88. package/dist/systems/wall/wall-mitering.js +76 -3
  89. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  90. package/dist/systems/wall/wall-system.js +202 -2
  91. package/package.json +3 -3
@@ -1,13 +1,15 @@
1
1
  import type { ThreeEvent } from '@react-three/fiber';
2
+ import type { Object3D } from 'three';
2
3
  import type { BuildingNode, CeilingNode, DoorNode, FenceNode, ItemNode, LevelNode, RoofNode, RoofSegmentNode, SiteNode, SlabNode, StairNode, StairSegmentNode, WallNode, WindowNode, ZoneNode } from '../schema';
3
4
  import type { AnyNode } from '../schema/types';
4
5
  export interface GridEvent {
5
6
  /** World-space intersection point on the grid plane. */
6
7
  position: [number, number, number];
7
8
  /**
8
- * Building-local intersection point relative to the currently selected building.
9
+ * Building-local intersection point, relative to the currently selected building.
9
10
  * Equals `position` when no building is selected.
10
- * Use this for placing/committing anything that lives inside a building (walls, slabs, items, etc.).
11
+ * Use this for placing or committing anything that lives inside a building
12
+ * (walls, slabs, items, etc.).
11
13
  */
12
14
  localPosition: [number, number, number];
13
15
  nativeEvent: ThreeEvent<PointerEvent>;
@@ -17,6 +19,8 @@ export interface NodeEvent<T extends AnyNode = AnyNode> {
17
19
  position: [number, number, number];
18
20
  localPosition: [number, number, number];
19
21
  normal?: [number, number, number];
22
+ faceIndex?: number;
23
+ object: Object3D;
20
24
  stopPropagation: () => void;
21
25
  nativeEvent: ThreeEvent<PointerEvent>;
22
26
  }
@@ -48,6 +52,20 @@ export interface CameraControlEvent {
48
52
  }
49
53
  export interface ThumbnailGenerateEvent {
50
54
  projectId: string;
55
+ captureMode?: 'standard' | 'viewport' | 'area';
56
+ cropRegion?: {
57
+ x: number;
58
+ y: number;
59
+ width: number;
60
+ height: number;
61
+ };
62
+ /**
63
+ * When true, snap levels to their true positions before capturing (for a
64
+ * consistent auto-thumbnail angle) and defer the capture if the tab is
65
+ * hidden, the background auto-save path. Omit for user-driven captures
66
+ * that should fire immediately from the current camera pose.
67
+ */
68
+ snapLevels?: boolean;
51
69
  }
52
70
  type CameraControlEvents = {
53
71
  'camera-controls:view': CameraControlEvent;
@@ -75,7 +93,23 @@ type ThumbnailEvents = {
75
93
  'thumbnail:before-capture': undefined;
76
94
  'thumbnail:after-capture': undefined;
77
95
  };
78
- type EditorEvents = GridEvents & NodeEvents<'wall', WallEvent> & NodeEvents<'fence', FenceEvent> & NodeEvents<'item', ItemEvent> & NodeEvents<'site', SiteEvent> & NodeEvents<'building', BuildingEvent> & NodeEvents<'level', LevelEvent> & NodeEvents<'zone', ZoneEvent> & NodeEvents<'slab', SlabEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & CameraControlEvents & ToolEvents & PresetEvents & ThumbnailEvents;
96
+ type SnapshotEvents = {
97
+ 'snapshot:saved': undefined;
98
+ 'camera:go-to-position': {
99
+ position: [number, number, number];
100
+ target: [number, number, number];
101
+ };
102
+ };
103
+ type AIChatEvents = {
104
+ 'ai-chat:attach-images': {
105
+ images: {
106
+ url: string;
107
+ name: string;
108
+ kind: 'snapshot' | 'render';
109
+ }[];
110
+ };
111
+ };
112
+ type EditorEvents = GridEvents & NodeEvents<'wall', WallEvent> & NodeEvents<'fence', FenceEvent> & NodeEvents<'item', ItemEvent> & NodeEvents<'site', SiteEvent> & NodeEvents<'building', BuildingEvent> & NodeEvents<'level', LevelEvent> & NodeEvents<'zone', ZoneEvent> & NodeEvents<'slab', SlabEvent> & NodeEvents<'ceiling', CeilingEvent> & NodeEvents<'roof', RoofEvent> & NodeEvents<'roof-segment', RoofSegmentEvent> & NodeEvents<'stair', StairEvent> & NodeEvents<'stair-segment', StairSegmentEvent> & NodeEvents<'window', WindowEvent> & NodeEvents<'door', DoorEvent> & CameraControlEvents & ToolEvents & PresetEvents & ThumbnailEvents & SnapshotEvents & AIChatEvents;
79
113
  export declare const emitter: import("mitt").Emitter<EditorEvents>;
80
114
  export {};
81
115
  //# sourceMappingURL=bus.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,UAAU,EACV,QAAQ,EACT,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAG9C,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC;;;;OAIG;IACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,WAAW,EAAE,UAAU,CAAC,YAAY,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO;IACpD,IAAI,EAAE,CAAC,CAAA;IACP,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACjC,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,WAAW,EAAE,UAAU,CAAC,YAAY,CAAC,CAAA;CACtC;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;AAC7C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,YAAY,CAAC,CAAA;AACnD,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;AAC7C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,WAAW,CAAC,CAAA;AACjD,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAC3C,MAAM,MAAM,gBAAgB,GAAG,SAAS,CAAC,eAAe,CAAC,CAAA;AACzD,MAAM,MAAM,UAAU,GAAG,SAAS,CAAC,SAAS,CAAC,CAAA;AAC7C,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAA;AAC3D,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,UAAU,CAAC,CAAA;AAC/C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;AAG3C,eAAO,MAAM,aAAa,0GAShB,CAAA;AAEV,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAA;AAExD,KAAK,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI;KACpC,CAAC,IAAI,GAAG,CAAC,IAAI,WAAW,EAAE,GAAG,CAAC;CAChC,CAAA;AAED,KAAK,UAAU,GAAG;KACf,CAAC,IAAI,QAAQ,WAAW,EAAE,GAAG,SAAS;CACxC,CAAA;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,KAAK,mBAAmB,GAAG;IACzB,sBAAsB,EAAE,kBAAkB,CAAA;IAC1C,uBAAuB,EAAE,kBAAkB,CAAA;IAC3C,yBAAyB,EAAE,kBAAkB,CAAA;IAC7C,0BAA0B,EAAE,SAAS,CAAA;IACrC,0BAA0B,EAAE,SAAS,CAAA;IACrC,2BAA2B,EAAE,SAAS,CAAA;IACtC,oCAAoC,EAAE,sBAAsB,CAAA;CAC7D,CAAA;AAED,KAAK,UAAU,GAAG;IAChB,aAAa,EAAE,SAAS,CAAA;CACzB,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,2BAA2B,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IACjE,0BAA0B,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;CACvE,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,0BAA0B,EAAE,SAAS,CAAA;IACrC,yBAAyB,EAAE,SAAS,CAAA;CACrC,CAAA;AAED,KAAK,YAAY,GAAG,UAAU,GAC5B,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,GAC/B,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,UAAU,EAAE,aAAa,CAAC,GACrC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,GAC/B,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,SAAS,EAAE,YAAY,CAAC,GACnC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,UAAU,CAAC,cAAc,EAAE,gBAAgB,CAAC,GAC5C,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,GAC/B,UAAU,CAAC,eAAe,EAAE,iBAAiB,CAAC,GAC9C,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,GACjC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,GAC7B,mBAAmB,GACnB,UAAU,GACV,YAAY,GACZ,eAAe,CAAA;AAEjB,eAAO,MAAM,OAAO,sCAAuB,CAAA"}
1
+ {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/events/bus.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import mitt from 'mitt';
2
- // Event suffixes - exported for use in hooks
2
+ // Event suffixes, exported for use in hooks
3
3
  export const eventSuffixes = [
4
4
  'click',
5
5
  'move',
@@ -4,10 +4,12 @@ interface SpatialGridConfig {
4
4
  export declare class SpatialGrid {
5
5
  private readonly cells;
6
6
  private readonly itemCells;
7
+ private readonly itemBounds;
7
8
  private readonly config;
8
9
  constructor(config: SpatialGridConfig);
9
10
  private posToCell;
10
11
  private cellKey;
12
+ private getAABB;
11
13
  private getItemCells;
12
14
  insert(itemId: string, position: [number, number, number], dimensions: [number, number, number], rotation: [number, number, number]): void;
13
15
  remove(itemId: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid.ts"],"names":[],"mappings":"AAMA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAE5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAE9B,MAAM,EAAE,iBAAiB;IAIrC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,YAAY;IAsCpB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAepC,MAAM,CAAC,MAAM,EAAE,MAAM;IAiBrB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAOpC,QAAQ,CACN,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,GAAE,MAAM,EAAO,GACvB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IAuB5C,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAkB3D,YAAY,IAAI,MAAM;CAGvB"}
1
+ {"version":3,"file":"spatial-grid.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid.ts"],"names":[],"mappings":"AAaA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;gBAE9B,MAAM,EAAE,iBAAiB;IAIrC,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,OAAO;IAuBf,OAAO,CAAC,YAAY;IAgBpB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAiBpC,MAAM,CAAC,MAAM,EAAE,MAAM;IAkBrB,MAAM,CACJ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IASpC,QAAQ,CACN,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAClC,SAAS,GAAE,MAAM,EAAO,GACvB;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE;IA0C5C,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAkB3D,YAAY,IAAI,MAAM;CAGvB"}
@@ -1,6 +1,7 @@
1
1
  export class SpatialGrid {
2
2
  cells = new Map();
3
3
  itemCells = new Map(); // reverse lookup
4
+ itemBounds = new Map(); // actual AABB for narrow-phase
4
5
  config;
5
6
  constructor(config) {
6
7
  this.config = config;
@@ -11,27 +12,27 @@ export class SpatialGrid {
11
12
  cellKey(cx, cz) {
12
13
  return `${cx},${cz}`;
13
14
  }
14
- // Get all cells an item occupies based on its AABB
15
- getItemCells(position, dimensions, rotation) {
16
- // Simplified: axis-aligned bounding box
17
- // For full rotation support, compute rotated corners
15
+ // Compute the axis-aligned bounding box for a rotated item
16
+ getAABB(position, dimensions, rotation) {
18
17
  const [x, , z] = position;
19
18
  const [w, , d] = dimensions;
20
- const yRot = rotation[1]; // Y-axis rotation
21
- // Compute rotated footprint (simplified for 90° increments)
19
+ const yRot = rotation[1];
22
20
  const cos = Math.abs(Math.cos(yRot));
23
21
  const sin = Math.abs(Math.sin(yRot));
24
22
  const rotatedW = w * cos + d * sin;
25
23
  const rotatedD = w * sin + d * cos;
26
- const minX = x - rotatedW / 2;
27
- const maxX = x + rotatedW / 2;
28
- const minZ = z - rotatedD / 2;
29
- const maxZ = z + rotatedD / 2;
24
+ return {
25
+ minX: x - rotatedW / 2,
26
+ maxX: x + rotatedW / 2,
27
+ minZ: z - rotatedD / 2,
28
+ maxZ: z + rotatedD / 2,
29
+ };
30
+ }
31
+ // Get all cells an item occupies based on its AABB
32
+ getItemCells(bounds) {
33
+ const { minX, maxX, minZ, maxZ } = bounds;
30
34
  const [minCx, minCz] = this.posToCell(minX, minZ);
31
- // Use exclusive upper bound: subtract epsilon so exact boundaries don't overlap
32
- // This allows adjacent items (touching but not overlapping) to not conflict
33
- const epsilon = 1e-6;
34
- const [maxCx, maxCz] = this.posToCell(maxX - epsilon, maxZ - epsilon);
35
+ const [maxCx, maxCz] = this.posToCell(maxX, maxZ);
35
36
  const keys = [];
36
37
  for (let cx = minCx; cx <= maxCx; cx++) {
37
38
  for (let cz = minCz; cz <= maxCz; cz++) {
@@ -42,8 +43,10 @@ export class SpatialGrid {
42
43
  }
43
44
  // Register an item
44
45
  insert(itemId, position, dimensions, rotation) {
45
- const cellKeys = this.getItemCells(position, dimensions, rotation);
46
+ const bounds = this.getAABB(position, dimensions, rotation);
47
+ const cellKeys = this.getItemCells(bounds);
46
48
  this.itemCells.set(itemId, new Set(cellKeys));
49
+ this.itemBounds.set(itemId, bounds);
47
50
  for (const key of cellKeys) {
48
51
  if (!this.cells.has(key)) {
49
52
  this.cells.set(key, { itemIds: new Set() });
@@ -66,6 +69,7 @@ export class SpatialGrid {
66
69
  }
67
70
  }
68
71
  this.itemCells.delete(itemId);
72
+ this.itemBounds.delete(itemId);
69
73
  }
70
74
  // Update = remove + insert
71
75
  update(itemId, position, dimensions, rotation) {
@@ -73,23 +77,42 @@ export class SpatialGrid {
73
77
  this.insert(itemId, position, dimensions, rotation);
74
78
  }
75
79
  // Query: is this placement valid?
80
+ // Uses cells as broad-phase, then checks actual AABB overlap (narrow-phase)
81
+ // to avoid false positives when adjacent items share a cell but don't overlap.
76
82
  canPlace(position, dimensions, rotation, ignoreIds = []) {
77
- const cellKeys = this.getItemCells(position, dimensions, rotation);
83
+ const bounds = this.getAABB(position, dimensions, rotation);
84
+ const cellKeys = this.getItemCells(bounds);
78
85
  const ignoreSet = new Set(ignoreIds);
79
- const conflicts = new Set();
86
+ // Broad phase: collect candidate items from overlapping cells
87
+ const candidates = new Set();
80
88
  for (const key of cellKeys) {
81
89
  const cell = this.cells.get(key);
82
90
  if (cell) {
83
91
  for (const id of cell.itemIds) {
84
92
  if (!ignoreSet.has(id)) {
85
- conflicts.add(id);
93
+ candidates.add(id);
86
94
  }
87
95
  }
88
96
  }
89
97
  }
98
+ // Narrow phase: check actual AABB overlap
99
+ // Items that merely touch (share an edge) are allowed; only true overlap conflicts.
100
+ const EPSILON = 1e-4; // tolerance to allow touching
101
+ const conflicts = [];
102
+ for (const id of candidates) {
103
+ const other = this.itemBounds.get(id);
104
+ if (!other)
105
+ continue;
106
+ if (bounds.minX < other.maxX - EPSILON &&
107
+ bounds.maxX > other.minX + EPSILON &&
108
+ bounds.minZ < other.maxZ - EPSILON &&
109
+ bounds.maxZ > other.minZ + EPSILON) {
110
+ conflicts.push(id);
111
+ }
112
+ }
90
113
  return {
91
- valid: conflicts.size === 0,
92
- conflictIds: [...conflicts],
114
+ valid: conflicts.length === 0,
115
+ conflictIds: conflicts,
93
116
  };
94
117
  }
95
118
  // Query: get all items near a point (for snapping, selection, etc.)
package/dist/index.d.ts CHANGED
@@ -7,8 +7,10 @@ export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
7
7
  export { loadAssetUrl, saveAsset } from './lib/asset-storage';
8
8
  export { detectSpacesForLevel, initSpaceDetectionSync, type Space, wallTouchesOthers, } from './lib/space-detection';
9
9
  export { baseMaterial, glassMaterial } from './materials';
10
+ export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, type MaterialCatalogItem, toLibraryMaterialRef, } from './material-library';
10
11
  export * from './schema';
11
12
  export { type ControlValue, type ItemInteractiveState, useInteractive, } from './store/use-interactive';
13
+ export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
12
14
  export { default as useLiveTransforms, type LiveTransform } from './store/use-live-transforms';
13
15
  export { FenceSystem } from './systems/fence/fence-system';
14
16
  export { clearSceneHistory, default as useScene } from './store/use-scene';
@@ -19,7 +21,8 @@ export { RoofSystem } from './systems/roof/roof-system';
19
21
  export { SlabSystem } from './systems/slab/slab-system';
20
22
  export { StairSystem } from './systems/stair/stair-system';
21
23
  export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
22
- export { calculateLevelMiters, type Point2D, pointToKey, type WallMiterData, } from './systems/wall/wall-mitering';
24
+ export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
25
+ export { calculateLevelMiters, getWallMiterBoundaryPoints, type Point2D, type WallMiterBoundaryPoints, pointToKey, type WallMiterData, } from './systems/wall/wall-mitering';
23
26
  export { WallSystem } from './systems/wall/wall-system';
24
27
  export { WindowSystem } from './systems/window/window-system';
25
28
  export type { SceneGraph } from './utils/clone-scene-graph';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrD,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;AACxE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,KAAK,EACV,iBAAiB,GAClB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACzD,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,cAAc,GACf,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC9F,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC1E,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,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC1D,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EACL,oBAAoB,EACpB,KAAK,OAAO,EACZ,UAAU,EACV,KAAK,aAAa,GACnB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC9F,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,8 +6,10 @@ export { useSpatialQuery } from './hooks/spatial-grid/use-spatial-query';
6
6
  export { loadAssetUrl, saveAsset } from './lib/asset-storage';
7
7
  export { detectSpacesForLevel, initSpaceDetectionSync, wallTouchesOthers, } from './lib/space-detection';
8
8
  export { baseMaterial, glassMaterial } from './materials';
9
+ export { getCatalogMaterialById, getLibraryMaterialIdFromRef, getMaterialPresetByRef, getMaterialsForTarget, LIBRARY_MATERIAL_REF_PREFIX, MATERIAL_CATALOG, toLibraryMaterialRef, } from './material-library';
9
10
  export * from './schema';
10
11
  export { useInteractive, } from './store/use-interactive';
12
+ export { getSceneHistoryPauseDepth, pauseSceneHistory, resetSceneHistoryPauseDepth, resumeSceneHistory, } from './store/history-control';
11
13
  export { default as useLiveTransforms } from './store/use-live-transforms';
12
14
  export { FenceSystem } from './systems/fence/fence-system';
13
15
  export { clearSceneHistory, default as useScene } from './store/use-scene';
@@ -18,7 +20,8 @@ export { RoofSystem } from './systems/roof/roof-system';
18
20
  export { SlabSystem } from './systems/slab/slab-system';
19
21
  export { StairSystem } from './systems/stair/stair-system';
20
22
  export { DEFAULT_WALL_HEIGHT, DEFAULT_WALL_THICKNESS, getWallPlanFootprint, getWallThickness, } from './systems/wall/wall-footprint';
21
- export { calculateLevelMiters, pointToKey, } from './systems/wall/wall-mitering';
23
+ export { getClampedWallCurveOffset, getMaxWallCurveOffset, getWallChordFrame, getWallCurveFrameAt, getWallCurveLength, getWallMidpointHandlePoint, getWallStraightSnapOffset, getWallSurfacePolygon, isCurvedWall, normalizeWallCurveOffset, sampleWallCenterline, } from './systems/wall/wall-curve';
24
+ export { calculateLevelMiters, getWallMiterBoundaryPoints, pointToKey, } from './systems/wall/wall-mitering';
22
25
  export { WallSystem } from './systems/wall/wall-system';
23
26
  export { WindowSystem } from './systems/window/window-system';
24
27
  export { cloneLevelSubtree, cloneSceneGraph, forkSceneGraph } from './utils/clone-scene-graph';
@@ -0,0 +1,3 @@
1
+ export declare function insetPolygonFromCentroid(polygon: Array<[number, number]>, inset: number): Array<[number, number]>;
2
+ export declare function simplifyClosedPolygon(polygon: Array<[number, number]>, tolerance: number): Array<[number, number]>;
3
+ //# sourceMappingURL=polygon-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon-geometry.d.ts","sourceRoot":"","sources":["../../src/lib/polygon-geometry.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,GACZ,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAuBzB;AAuED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAChC,SAAS,EAAE,MAAM,GAChB,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiCzB"}
@@ -0,0 +1,90 @@
1
+ export function insetPolygonFromCentroid(polygon, inset) {
2
+ if (inset <= 0) {
3
+ return polygon.map(([x, z]) => [x, z]);
4
+ }
5
+ const centroid = polygon.reduce((acc, [x, z]) => ({ x: acc.x + x, z: acc.z + z }), { x: 0, z: 0 });
6
+ centroid.x /= Math.max(polygon.length, 1);
7
+ centroid.z /= Math.max(polygon.length, 1);
8
+ return polygon.map(([x, z]) => {
9
+ const dx = x - centroid.x;
10
+ const dz = z - centroid.z;
11
+ const length = Math.hypot(dx, dz);
12
+ if (length <= inset + 1e-6) {
13
+ return [x, z];
14
+ }
15
+ const scale = (length - inset) / length;
16
+ return [centroid.x + dx * scale, centroid.z + dz * scale];
17
+ });
18
+ }
19
+ function pointLineDistance(point, start, end) {
20
+ const dx = end[0] - start[0];
21
+ const dz = end[1] - start[1];
22
+ const lengthSquared = dx * dx + dz * dz;
23
+ if (lengthSquared < 1e-9) {
24
+ return Math.hypot(point[0] - start[0], point[1] - start[1]);
25
+ }
26
+ const cross = (point[0] - start[0]) * dz - (point[1] - start[1]) * dx;
27
+ return Math.abs(cross) / Math.sqrt(lengthSquared);
28
+ }
29
+ function dedupePolygonPoints(polygon, tolerance = 1e-6) {
30
+ const deduped = [];
31
+ for (const point of polygon) {
32
+ const previous = deduped[deduped.length - 1];
33
+ if (previous && Math.hypot(point[0] - previous[0], point[1] - previous[1]) <= tolerance) {
34
+ continue;
35
+ }
36
+ deduped.push(point);
37
+ }
38
+ if (deduped.length > 2 &&
39
+ Math.hypot(deduped[0][0] - deduped[deduped.length - 1][0], deduped[0][1] - deduped[deduped.length - 1][1]) <= tolerance) {
40
+ deduped.pop();
41
+ }
42
+ return deduped;
43
+ }
44
+ function simplifyPolyline(points, tolerance) {
45
+ if (points.length <= 2) {
46
+ return points.map(([x, z]) => [x, z]);
47
+ }
48
+ let maxDistance = -1;
49
+ let splitIndex = -1;
50
+ for (let index = 1; index < points.length - 1; index += 1) {
51
+ const distance = pointLineDistance(points[index], points[0], points[points.length - 1]);
52
+ if (distance > maxDistance) {
53
+ maxDistance = distance;
54
+ splitIndex = index;
55
+ }
56
+ }
57
+ if (maxDistance <= tolerance || splitIndex === -1) {
58
+ return [points[0], points[points.length - 1]];
59
+ }
60
+ const left = simplifyPolyline(points.slice(0, splitIndex + 1), tolerance);
61
+ const right = simplifyPolyline(points.slice(splitIndex), tolerance);
62
+ return [...left.slice(0, -1), ...right];
63
+ }
64
+ export function simplifyClosedPolygon(polygon, tolerance) {
65
+ const cleanPolygon = dedupePolygonPoints(polygon);
66
+ if (cleanPolygon.length <= 3 || tolerance <= 0) {
67
+ return cleanPolygon;
68
+ }
69
+ let anchorA = 0;
70
+ let anchorB = Math.floor(cleanPolygon.length / 2);
71
+ let maxDistanceSquared = -1;
72
+ for (let i = 0; i < cleanPolygon.length; i += 1) {
73
+ for (let j = i + 1; j < cleanPolygon.length; j += 1) {
74
+ const dx = cleanPolygon[j][0] - cleanPolygon[i][0];
75
+ const dz = cleanPolygon[j][1] - cleanPolygon[i][1];
76
+ const distanceSquared = dx * dx + dz * dz;
77
+ if (distanceSquared > maxDistanceSquared) {
78
+ maxDistanceSquared = distanceSquared;
79
+ anchorA = i;
80
+ anchorB = j;
81
+ }
82
+ }
83
+ }
84
+ const forward = cleanPolygon.slice(anchorA, anchorB + 1);
85
+ const wrapped = [...cleanPolygon.slice(anchorB), ...cleanPolygon.slice(0, anchorA + 1)];
86
+ const simplifiedForward = simplifyPolyline(forward, tolerance);
87
+ const simplifiedWrapped = simplifyPolyline(wrapped, tolerance);
88
+ const simplified = dedupePolygonPoints([...simplifiedForward.slice(0, -1), ...simplifiedWrapped.slice(0, -1)], tolerance * 0.25);
89
+ return simplified.length >= 3 ? simplified : cleanPolygon;
90
+ }
@@ -1,4 +1,8 @@
1
- import type { WallNode } from '../schema';
1
+ import { type WallNode } from '../schema';
2
+ type Point2D = {
3
+ x: number;
4
+ y: number;
5
+ };
2
6
  export type Space = {
3
7
  id: string;
4
8
  levelId: string;
@@ -6,29 +10,18 @@ export type Space = {
6
10
  wallIds: string[];
7
11
  isExterior: boolean;
8
12
  };
9
- /**
10
- * Initializes space detection sync with scene and editor stores
11
- * Call this once during app initialization
12
- */
13
- export declare function initSpaceDetectionSync(sceneStore: any, // useScene store
14
- editorStore: any): () => void;
15
13
  type WallSideUpdate = {
16
14
  wallId: string;
17
15
  frontSide: 'interior' | 'exterior' | 'unknown';
18
16
  backSide: 'interior' | 'exterior' | 'unknown';
19
17
  };
20
- /**
21
- * Detects spaces for a level by flood-filling a grid from the edges
22
- * Returns wall side updates and detected spaces
23
- */
24
- export declare function detectSpacesForLevel(levelId: string, walls: WallNode[], gridResolution?: number): {
25
- wallUpdates: WallSideUpdate[];
18
+ export declare function resolveWallSurfaceSides(wall: Pick<WallNode, 'start' | 'end' | 'thickness' | 'frontSide' | 'backSide'>, roomPolygons: Point2D[][]): Pick<WallSideUpdate, 'frontSide' | 'backSide'>;
19
+ export declare function detectSpacesForLevel(levelId: string, walls: WallNode[]): {
20
+ roomPolygons: Point2D[][];
26
21
  spaces: Space[];
22
+ wallUpdates: WallSideUpdate[];
27
23
  };
28
- /**
29
- * Checks if a wall touches any other walls
30
- * Used to determine if space detection should run
31
- */
24
+ export declare function initSpaceDetectionSync(sceneStore: any, editorStore: any): () => void;
32
25
  export declare function wallTouchesOthers(wall: WallNode, otherWalls: WallNode[]): boolean;
33
26
  export {};
34
27
  //# sourceMappingURL=space-detection.d.ts.map
@@ -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,CAkGZ;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"}
1
+ {"version":3,"file":"space-detection.d.ts","sourceRoot":"","sources":["../../src/lib/space-detection.ts"],"names":[],"mappings":"AAKA,OAAO,EAA6F,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAA;AAQpI,KAAK,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvC,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;AAED,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;AA4VD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC,EAC9E,YAAY,EAAE,OAAO,EAAE,EAAE,GACxB,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,UAAU,CAAC,CA4ChD;AA0WD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE;;;;EAEtE;AAsED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,GAAG,MAAM,IAAI,CAuDpF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,OAAO,CAiBjF"}