@pascal-app/core 1.1.0 → 1.1.2

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 (133) hide show
  1. package/dist/agent-operations/__fixtures__/cases.d.ts +3 -2
  2. package/dist/agent-operations/__fixtures__/cases.d.ts.map +1 -1
  3. package/dist/agent-operations/__fixtures__/place-items-cases.d.ts.map +1 -1
  4. package/dist/agent-operations/__fixtures__/place-items-cases.js +28 -0
  5. package/dist/agent-operations/__fixtures__/roof-bearing-cases.d.ts +2618 -2618
  6. package/dist/agent-operations/asset-catalog.d.ts +21 -11
  7. package/dist/agent-operations/asset-catalog.d.ts.map +1 -1
  8. package/dist/agent-operations/asset-catalog.js +28 -10
  9. package/dist/agent-operations/asset-views.d.ts +8 -3
  10. package/dist/agent-operations/asset-views.d.ts.map +1 -1
  11. package/dist/agent-operations/asset-views.js +19 -3
  12. package/dist/agent-operations/batch.d.ts +4 -2
  13. package/dist/agent-operations/batch.d.ts.map +1 -1
  14. package/dist/agent-operations/batch.js +9 -6
  15. package/dist/agent-operations/catalog-asset.d.ts +15 -0
  16. package/dist/agent-operations/catalog-asset.d.ts.map +1 -0
  17. package/dist/agent-operations/catalog-asset.js +4 -0
  18. package/dist/agent-operations/circulation-spaces.d.ts +585 -585
  19. package/dist/agent-operations/design-brief.d.ts.map +1 -1
  20. package/dist/agent-operations/design-brief.js +2 -0
  21. package/dist/agent-operations/furnish-room.d.ts.map +1 -1
  22. package/dist/agent-operations/furnish-room.js +2 -1
  23. package/dist/agent-operations/index.d.ts +5716 -7
  24. package/dist/agent-operations/index.d.ts.map +1 -1
  25. package/dist/agent-operations/index.js +17 -3
  26. package/dist/agent-operations/level-reads.d.ts.map +1 -1
  27. package/dist/agent-operations/level-reads.js +4 -1
  28. package/dist/agent-operations/place-in-room.d.ts.map +1 -1
  29. package/dist/agent-operations/place-in-room.js +2 -1
  30. package/dist/agent-operations/place-items.d.ts.map +1 -1
  31. package/dist/agent-operations/place-items.js +2 -1
  32. package/dist/agent-operations/scene-queries.d.ts +3818 -3818
  33. package/dist/agent-operations/scene-view.d.ts.map +1 -1
  34. package/dist/agent-operations/scene-view.js +38 -13
  35. package/dist/agent-operations/search-assets.d.ts.map +1 -1
  36. package/dist/agent-operations/search-assets.js +6 -0
  37. package/dist/agent-operations/types.d.ts +10 -2
  38. package/dist/agent-operations/types.d.ts.map +1 -1
  39. package/dist/agent-operations/usage-checks.js +18 -3
  40. package/dist/agent-operations/verify-scene.d.ts +7 -3
  41. package/dist/agent-operations/verify-scene.d.ts.map +1 -1
  42. package/dist/agent-operations/verify-scene.js +15 -7
  43. package/dist/agent-tools/assets.js +1 -1
  44. package/dist/building/__fixtures__/wall-opening-cases.d.ts +30 -30
  45. package/dist/building/level-duplication.d.ts +3409 -3409
  46. package/dist/building/level-duplication.d.ts.map +1 -1
  47. package/dist/building/level-duplication.js +3 -1
  48. package/dist/building/wall-openings.d.ts +75 -75
  49. package/dist/commands/structure/shared.d.ts +3407 -3407
  50. package/dist/commands/structure/zone-wall-merge.d.ts +652 -652
  51. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +3818 -3818
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +2 -0
  55. package/dist/lib/__fixtures__/mezzanine.d.ts +2003 -2003
  56. package/dist/lib/absorb-wall-separators.d.ts +1032 -1032
  57. package/dist/lib/asset-storage.d.ts.map +1 -1
  58. package/dist/lib/asset-storage.js +3 -0
  59. package/dist/lib/floor-foundation-datum.d.ts.map +1 -1
  60. package/dist/lib/floor-foundation-datum.js +5 -1
  61. package/dist/lib/floorplan/context.d.ts +95 -0
  62. package/dist/lib/floorplan/context.d.ts.map +1 -0
  63. package/dist/lib/floorplan/context.js +155 -0
  64. package/dist/lib/floorplan/index.d.ts +6 -0
  65. package/dist/lib/floorplan/index.d.ts.map +1 -0
  66. package/dist/lib/floorplan/index.js +5 -0
  67. package/dist/lib/floorplan/marks.d.ts +71 -0
  68. package/dist/lib/floorplan/marks.d.ts.map +1 -0
  69. package/dist/lib/floorplan/marks.js +157 -0
  70. package/dist/lib/floorplan/plan-math.d.ts +18 -0
  71. package/dist/lib/floorplan/plan-math.d.ts.map +1 -0
  72. package/dist/lib/floorplan/plan-math.js +82 -0
  73. package/dist/lib/floorplan/svg-paths.d.ts +17 -0
  74. package/dist/lib/floorplan/svg-paths.d.ts.map +1 -0
  75. package/dist/lib/floorplan/svg-paths.js +92 -0
  76. package/dist/lib/floorplan/wall-affordances.d.ts +31 -0
  77. package/dist/lib/floorplan/wall-affordances.d.ts.map +1 -0
  78. package/dist/lib/floorplan/wall-affordances.js +24 -0
  79. package/dist/lib/steps.d.ts +8 -0
  80. package/dist/lib/steps.d.ts.map +1 -0
  81. package/dist/lib/steps.js +7 -0
  82. package/dist/registry/__fixtures__/roof-planes.d.ts +69 -0
  83. package/dist/registry/__fixtures__/roof-planes.d.ts.map +1 -0
  84. package/dist/registry/__fixtures__/roof-planes.js +59 -0
  85. package/dist/registry/index.d.ts +2 -1
  86. package/dist/registry/index.d.ts.map +1 -1
  87. package/dist/registry/index.js +1 -0
  88. package/dist/registry/roofs.d.ts +34 -0
  89. package/dist/registry/roofs.d.ts.map +1 -0
  90. package/dist/registry/roofs.js +61 -0
  91. package/dist/registry/types.d.ts +30 -0
  92. package/dist/registry/types.d.ts.map +1 -1
  93. package/dist/registry/validate-relations.d.ts +5 -1
  94. package/dist/registry/validate-relations.d.ts.map +1 -1
  95. package/dist/registry/validate-relations.js +6 -2
  96. package/dist/schema/asset-url.d.ts +8 -0
  97. package/dist/schema/asset-url.d.ts.map +1 -1
  98. package/dist/schema/asset-url.js +17 -0
  99. package/dist/schema/nodes/roof.d.ts +1 -1
  100. package/dist/schema/nodes/roof.d.ts.map +1 -1
  101. package/dist/schema/nodes/roof.js +13 -8
  102. package/dist/schema/types.d.ts +1 -1
  103. package/dist/services/roof-level.d.ts.map +1 -1
  104. package/dist/services/roof-level.js +12 -2
  105. package/dist/services/roof-move.d.ts +4 -2
  106. package/dist/services/roof-move.d.ts.map +1 -1
  107. package/dist/services/roof-move.js +21 -9
  108. package/dist/spatial/usage-field/findings.d.ts +10 -1
  109. package/dist/spatial/usage-field/findings.d.ts.map +1 -1
  110. package/dist/spatial/usage-field/findings.js +56 -12
  111. package/dist/spatial/usage-field/measure.d.ts +3 -1
  112. package/dist/spatial/usage-field/measure.d.ts.map +1 -1
  113. package/dist/spatial/usage-field/measure.js +7 -2
  114. package/dist/spatial/usage-field/path.d.ts.map +1 -1
  115. package/dist/spatial/usage-field/path.js +28 -18
  116. package/dist/store/actions/node-actions.d.ts +2380 -2380
  117. package/dist/store/scene-annotations.d.ts +1279 -1279
  118. package/dist/systems/document-reconcile.d.ts.map +1 -1
  119. package/dist/systems/document-reconcile.js +1 -2
  120. package/dist/systems/roof/roof-elevation.d.ts +11 -6
  121. package/dist/systems/roof/roof-elevation.d.ts.map +1 -1
  122. package/dist/systems/roof/roof-elevation.js +24 -11
  123. package/dist/systems/slab/__fixtures__/floor-step.d.ts +2381 -2381
  124. package/dist/systems/slab/__fixtures__/raised-room.d.ts +3818 -3818
  125. package/dist/systems/stair/stair-opening-preview.d.ts +900 -900
  126. package/dist/utils/ensure-scene-openings.d.ts +4815 -4815
  127. package/dist/utils/floor-plate-migration.d.ts +1032 -1032
  128. package/dist/utils/owned-floor-opening-migration.d.ts +1032 -1032
  129. package/dist/utils/reconcile-structure-on-load.d.ts +2380 -2380
  130. package/dist/utils/scene-bounds.d.ts +32 -0
  131. package/dist/utils/scene-bounds.d.ts.map +1 -0
  132. package/dist/utils/scene-bounds.js +201 -0
  133. package/package.json +1 -1
@@ -0,0 +1,32 @@
1
+ import type { AnyNode } from '../schema/index.js';
2
+ export type SceneBoundsXZ = {
3
+ /** Min [x, z] in world units (meters). */
4
+ min: [number, number];
5
+ /** Max [x, z] in world units (meters). */
6
+ max: [number, number];
7
+ /** Center [x, z] = (min + max) / 2. */
8
+ center: [number, number];
9
+ /** Size [w, d] = max - min. */
10
+ size: [number, number];
11
+ };
12
+ /**
13
+ * Compute the axis-aligned XZ bounds of a scene.
14
+ *
15
+ * Walks every node and extracts 2D footprint points from the fields most
16
+ * nodes carry:
17
+ * - `start`/`end` → wall and fence endpoints in level coordinates.
18
+ * - `polygon` → zone, slab, site-boundary polygons.
19
+ * - `position` → building/item/door/window position; uses [x, z] only.
20
+ *
21
+ * Each point is in its parent's frame, so it is carried to world XZ through
22
+ * the ancestors' `position` and `rotation` yaw (a moved or turned building).
23
+ *
24
+ * Site-node polygons are intentionally excluded when they are the default
25
+ * 30×30 bootstrap polygon — otherwise a brand-new empty scene would frame
26
+ * an empty square around the origin. We still include site polygons that
27
+ * look intentional (> 4 points, or any point outside the ±15 m default).
28
+ *
29
+ * Returns `null` if no usable geometry was found.
30
+ */
31
+ export declare function computeSceneBoundsXZ(nodes: AnyNode[] | Record<string, AnyNode>): SceneBoundsXZ | null;
32
+ //# sourceMappingURL=scene-bounds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-bounds.d.ts","sourceRoot":"","sources":["../../src/utils/scene-bounds.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAExC,MAAM,MAAM,aAAa,GAAG;IAC1B,0CAA0C;IAC1C,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrB,0CAA0C;IAC1C,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrB,uCAAuC;IACvC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxB,+BAA+B;IAC/B,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACvB,CAAA;AAyBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACzC,aAAa,GAAG,IAAI,CAgGtB"}
@@ -0,0 +1,201 @@
1
+ import { turnPlanPoint, yawOf } from '../lib/building-footprint.js';
2
+ // A very small guard against degenerate bounds (e.g. a single wall of zero length).
3
+ const MIN_BOUNDS_EXTENT = 0.0001;
4
+ const WORLD_FRAME = { x: 0, z: 0, yaw: 0 };
5
+ function extendPoint(acc, frame, localX, localZ) {
6
+ if (typeof localX !== 'number' || typeof localZ !== 'number')
7
+ return;
8
+ if (!(Number.isFinite(localX) && Number.isFinite(localZ)))
9
+ return;
10
+ const [tx, tz] = frame.yaw === 0 ? [localX, localZ] : turnPlanPoint(localX, localZ, frame.yaw);
11
+ const x = frame.x + tx;
12
+ const z = frame.z + tz;
13
+ if (x < acc.minX)
14
+ acc.minX = x;
15
+ if (x > acc.maxX)
16
+ acc.maxX = x;
17
+ if (z < acc.minZ)
18
+ acc.minZ = z;
19
+ if (z > acc.maxZ)
20
+ acc.maxZ = z;
21
+ acc.hasPoint = true;
22
+ }
23
+ /**
24
+ * Compute the axis-aligned XZ bounds of a scene.
25
+ *
26
+ * Walks every node and extracts 2D footprint points from the fields most
27
+ * nodes carry:
28
+ * - `start`/`end` → wall and fence endpoints in level coordinates.
29
+ * - `polygon` → zone, slab, site-boundary polygons.
30
+ * - `position` → building/item/door/window position; uses [x, z] only.
31
+ *
32
+ * Each point is in its parent's frame, so it is carried to world XZ through
33
+ * the ancestors' `position` and `rotation` yaw (a moved or turned building).
34
+ *
35
+ * Site-node polygons are intentionally excluded when they are the default
36
+ * 30×30 bootstrap polygon — otherwise a brand-new empty scene would frame
37
+ * an empty square around the origin. We still include site polygons that
38
+ * look intentional (> 4 points, or any point outside the ±15 m default).
39
+ *
40
+ * Returns `null` if no usable geometry was found.
41
+ */
42
+ export function computeSceneBoundsXZ(nodes) {
43
+ const list = Array.isArray(nodes) ? nodes : Object.values(nodes);
44
+ if (list.length === 0)
45
+ return null;
46
+ const acc = {
47
+ minX: Number.POSITIVE_INFINITY,
48
+ minZ: Number.POSITIVE_INFINITY,
49
+ maxX: Number.NEGATIVE_INFINITY,
50
+ maxZ: Number.NEGATIVE_INFINITY,
51
+ hasPoint: false,
52
+ };
53
+ const byId = new Map();
54
+ for (const node of list) {
55
+ if (node && typeof node === 'object' && typeof node.id === 'string')
56
+ byId.set(node.id, node);
57
+ }
58
+ const frameOf = createFrameResolver(byId);
59
+ for (const node of list) {
60
+ if (!node || typeof node !== 'object')
61
+ continue;
62
+ const anyNode = node;
63
+ // A node's own fields live in its parent's frame (a building's walls are
64
+ // building-local), so every point goes through the ancestors' transforms.
65
+ const frame = frameOf(node.parentId ?? null);
66
+ // Wall / fence endpoints in level coordinates.
67
+ const start = anyNode.start;
68
+ const end = anyNode.end;
69
+ if (Array.isArray(start) && start.length >= 2)
70
+ extendPoint(acc, frame, start[0], start[1]);
71
+ if (Array.isArray(end) && end.length >= 2)
72
+ extendPoint(acc, frame, end[0], end[1]);
73
+ // Zone / slab polygons (and explicit polygon-shaped site boundaries).
74
+ const polygon = anyNode.polygon;
75
+ if (Array.isArray(polygon)) {
76
+ // Zones/slabs expose a plain array of [x,z] tuples. Site nodes nest the
77
+ // points under `polygon.points` (a discriminated PropertyLineData shape).
78
+ for (const point of polygon) {
79
+ if (Array.isArray(point) && point.length >= 2) {
80
+ extendPoint(acc, frame, point[0], point[1]);
81
+ }
82
+ }
83
+ }
84
+ else if (polygon &&
85
+ typeof polygon === 'object' &&
86
+ Array.isArray(polygon.points)) {
87
+ // Site nodes only: skip the default bootstrap square so a blank scene
88
+ // isn't auto-framed around an empty ±15 m box. Include any other site
89
+ // polygon (more than 4 points, or any coordinate beyond the default).
90
+ const points = polygon.points;
91
+ if (node.type === 'site' && isDefaultSitePolygon(points)) {
92
+ // Skip — default bootstrap polygon.
93
+ }
94
+ else {
95
+ for (const point of points) {
96
+ if (Array.isArray(point) && point.length >= 2) {
97
+ extendPoint(acc, frame, point[0], point[1]);
98
+ }
99
+ }
100
+ }
101
+ }
102
+ // Position on the XZ plane (3D position = [x, y, z]). A node hosted on a
103
+ // wall (door, window, wall item) has a wall-local position, and the
104
+ // wall's endpoints already bound it.
105
+ const position = anyNode.position;
106
+ if (Array.isArray(position) && position.length >= 3 && !isWallHosted(node, byId)) {
107
+ extendPoint(acc, frame, position[0], position[2]);
108
+ }
109
+ }
110
+ if (!acc.hasPoint)
111
+ return null;
112
+ // Ensure a minimum extent so a single-point scene still yields a box.
113
+ let minX = acc.minX;
114
+ let minZ = acc.minZ;
115
+ let maxX = acc.maxX;
116
+ let maxZ = acc.maxZ;
117
+ if (maxX - minX < MIN_BOUNDS_EXTENT) {
118
+ const cx = (minX + maxX) / 2;
119
+ minX = cx - MIN_BOUNDS_EXTENT / 2;
120
+ maxX = cx + MIN_BOUNDS_EXTENT / 2;
121
+ }
122
+ if (maxZ - minZ < MIN_BOUNDS_EXTENT) {
123
+ const cz = (minZ + maxZ) / 2;
124
+ minZ = cz - MIN_BOUNDS_EXTENT / 2;
125
+ maxZ = cz + MIN_BOUNDS_EXTENT / 2;
126
+ }
127
+ const centerX = (minX + maxX) / 2;
128
+ const centerZ = (minZ + maxZ) / 2;
129
+ return {
130
+ min: [minX, minZ],
131
+ max: [maxX, maxZ],
132
+ center: [centerX, centerZ],
133
+ size: [maxX - minX, maxZ - minZ],
134
+ };
135
+ }
136
+ /**
137
+ * World plan frame of each node, composed down the parent chain the way the
138
+ * renderers nest groups: a node with a `position` (building, item) translates
139
+ * its children and turns them by its `rotation` yaw; nodes without one (site,
140
+ * level) pass their parent's frame through.
141
+ */
142
+ function createFrameResolver(byId) {
143
+ const cache = new Map();
144
+ const resolving = new Set();
145
+ const resolve = (id) => {
146
+ if (!id)
147
+ return WORLD_FRAME;
148
+ const cached = cache.get(id);
149
+ if (cached)
150
+ return cached;
151
+ const node = byId.get(id);
152
+ if (!node || resolving.has(id))
153
+ return WORLD_FRAME;
154
+ resolving.add(id);
155
+ const parent = resolve(node.parentId ?? null);
156
+ resolving.delete(id);
157
+ const anyNode = node;
158
+ const position = anyNode.position;
159
+ let frame = parent;
160
+ if (Array.isArray(position) && position.length >= 3) {
161
+ const px = Number.isFinite(position[0]) ? position[0] : 0;
162
+ const pz = Number.isFinite(position[2]) ? position[2] : 0;
163
+ const [tx, tz] = turnPlanPoint(px, pz, parent.yaw);
164
+ frame = { x: parent.x + tx, z: parent.z + tz, yaw: parent.yaw + yawOf(anyNode.rotation) };
165
+ }
166
+ cache.set(id, frame);
167
+ return frame;
168
+ };
169
+ return resolve;
170
+ }
171
+ function isWallHosted(node, byId) {
172
+ const parent = node.parentId ? byId.get(node.parentId) : undefined;
173
+ if (!parent)
174
+ return false;
175
+ const anyParent = parent;
176
+ return Array.isArray(anyParent.start) && Array.isArray(anyParent.end);
177
+ }
178
+ /**
179
+ * Matches the `SiteNode` bootstrap polygon defined in
180
+ * `packages/core/src/schema/nodes/site.ts` (a 30×30 square at the origin).
181
+ * We ignore it so the default scene doesn't "auto-frame" onto an empty box.
182
+ */
183
+ function isDefaultSitePolygon(points) {
184
+ if (points.length !== 4)
185
+ return false;
186
+ const expected = [
187
+ [-15, -15],
188
+ [15, -15],
189
+ [15, 15],
190
+ [-15, 15],
191
+ ];
192
+ for (let i = 0; i < 4; i++) {
193
+ const p = points[i];
194
+ const e = expected[i];
195
+ if (!Array.isArray(p) || p.length < 2)
196
+ return false;
197
+ if (p[0] !== e[0] || p[1] !== e[1])
198
+ return false;
199
+ }
200
+ return true;
201
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pascal-app/core",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Core library for Pascal 3D building editor",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",