@pascal-app/core 1.0.0-beta.4 → 1.0.0-beta.5

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 (69) hide show
  1. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +12 -0
  2. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  3. package/dist/hooks/spatial-grid/spatial-grid-manager.js +39 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/lib/room-topology-index.d.ts +50 -0
  8. package/dist/lib/room-topology-index.d.ts.map +1 -0
  9. package/dist/lib/room-topology-index.js +237 -0
  10. package/dist/lib/space-detection.d.ts +29 -3
  11. package/dist/lib/space-detection.d.ts.map +1 -1
  12. package/dist/lib/space-detection.js +858 -242
  13. package/dist/registry/index.d.ts +3 -2
  14. package/dist/registry/index.d.ts.map +1 -1
  15. package/dist/registry/index.js +2 -1
  16. package/dist/registry/registry.d.ts +17 -1
  17. package/dist/registry/registry.d.ts.map +1 -1
  18. package/dist/registry/registry.js +74 -0
  19. package/dist/registry/types.d.ts +35 -0
  20. package/dist/registry/types.d.ts.map +1 -1
  21. package/dist/registry/use-registry-version.d.ts +11 -0
  22. package/dist/registry/use-registry-version.d.ts.map +1 -0
  23. package/dist/registry/use-registry-version.js +15 -0
  24. package/dist/schema/index.d.ts +1 -0
  25. package/dist/schema/index.d.ts.map +1 -1
  26. package/dist/schema/index.js +2 -0
  27. package/dist/schema/nodes/level.d.ts +3 -0
  28. package/dist/schema/nodes/level.d.ts.map +1 -1
  29. package/dist/schema/nodes/level.js +9 -0
  30. package/dist/schema/types.d.ts +1 -0
  31. package/dist/schema/types.d.ts.map +1 -1
  32. package/dist/services/index.d.ts +1 -1
  33. package/dist/services/index.d.ts.map +1 -1
  34. package/dist/services/index.js +1 -1
  35. package/dist/services/storey.d.ts +3 -10
  36. package/dist/services/storey.d.ts.map +1 -1
  37. package/dist/services/storey.js +45 -15
  38. package/dist/store/actions/node-actions.d.ts +8 -4
  39. package/dist/store/actions/node-actions.d.ts.map +1 -1
  40. package/dist/store/actions/node-actions.js +31 -4
  41. package/dist/store/history-control.d.ts +5 -0
  42. package/dist/store/history-control.d.ts.map +1 -1
  43. package/dist/store/history-control.js +68 -6
  44. package/dist/store/use-scene.d.ts.map +1 -1
  45. package/dist/store/use-scene.js +75 -163
  46. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  47. package/dist/systems/elevator/elevator-service.js +16 -11
  48. package/dist/systems/slab/slab-support.d.ts +0 -31
  49. package/dist/systems/slab/slab-support.d.ts.map +1 -1
  50. package/dist/systems/slab/slab-support.js +26 -4
  51. package/dist/systems/stair/stair-opening-preview.d.ts +1 -0
  52. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  53. package/dist/systems/stair/stair-rise.d.ts.map +1 -1
  54. package/dist/systems/stair/stair-rise.js +4 -2
  55. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  56. package/dist/systems/wall/wall-mitering.js +88 -9
  57. package/dist/systems/wall/wall-topology.d.ts +53 -0
  58. package/dist/systems/wall/wall-topology.d.ts.map +1 -0
  59. package/dist/systems/wall/wall-topology.js +414 -0
  60. package/dist/utils/clone-scene-graph.d.ts +2 -0
  61. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  62. package/dist/utils/clone-scene-graph.js +13 -2
  63. package/dist/utils/scene-migrations.d.ts +1 -0
  64. package/dist/utils/scene-migrations.d.ts.map +1 -1
  65. package/dist/utils/scene-migrations.js +1 -0
  66. package/dist/utils/vertical-scene-migration.d.ts +13 -0
  67. package/dist/utils/vertical-scene-migration.d.ts.map +1 -0
  68. package/dist/utils/vertical-scene-migration.js +179 -0
  69. package/package.json +1 -1
@@ -13,22 +13,15 @@ export declare const CEILING_CLAMP_MARGIN = 0.01;
13
13
  */
14
14
  export declare function getStoredLevelHeight(level: Pick<LevelNode, 'height'>): number;
15
15
  export type LevelElevation = {
16
- /** World Y of the level's floor: prefix sum of the storey heights below it. */
16
+ /** World Y of the level's floor: cumulative heights and level offsets through this level. */
17
17
  baseY: number;
18
18
  /** Stored storey height of this level (fallback applied). */
19
19
  height: number;
20
20
  buildingId: string | null;
21
21
  ordinal: number;
22
22
  };
23
- /**
24
- * Per-building stacked elevations from stored storey heights: levels are
25
- * sorted by ordinal ascending within each building, the lowest level's floor
26
- * sits at 0, and each next floor sits on top of the previous storey height.
27
- * Levels with no resolvable building share one legacy stack from 0.
28
- *
29
- * Pure — operates on the serialized nodes record only.
30
- */
31
23
  export declare function getLevelElevations(nodes: Record<AnyNodeId, AnyNode>): Map<string, LevelElevation>;
24
+ export declare function getLevelFloorToFloorHeight(levelId: string, nodes: Record<AnyNodeId, AnyNode>): number;
32
25
  /**
33
26
  * The id of the level directly above `levelId` in its own stack (same
34
27
  * resolved building, or the shared legacy stack for building-less levels):
@@ -55,7 +48,7 @@ export declare function getLevelBelow(levelId: string, nodes: Record<AnyNodeId,
55
48
  /**
56
49
  * Underside of the LOWEST slab from the level above that covers
57
50
  * level-local point `[x, z]`, expressed in the queried level's local Y:
58
- * `storeyHeight + (slab.elevation - slab.thickness)`. `recessed` slabs
51
+ * `floorToFloorHeight + (slab.elevation - slab.thickness)`. `recessed` slabs
59
52
  * (pools) never cover. `null` when no covering slab (or no level above).
60
53
  *
61
54
  * Coordinate spaces: levels stack in Y only (`LevelNode` carries no XZ
@@ -1 +1 @@
1
- {"version":3,"file":"storey.d.ts","sourceRoot":"","sources":["../../src/services/storey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAY,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAQzD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAExC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,MAAM,CAE7E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAkBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAgCjG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AAuFD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,GAAG,IAAI,CAIf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,aAAa,CAAC,CAAC,EAC5F,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,MAAM,CAYR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,OAAO,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,CAuBR"}
1
+ {"version":3,"file":"storey.d.ts","sourceRoot":"","sources":["../../src/services/storey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAY,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAQzD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAExC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,MAAM,CAE7E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,6FAA6F;IAC7F,KAAK,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAgCD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAqCjG;AAeD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,MAAM,CAER;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AA+FD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,GAAG,IAAI,CAIf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,aAAa,CAAC,CAAC,EAC5F,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,MAAM,CAYR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,OAAO,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,CAuBR"}
@@ -26,14 +26,22 @@ function resolveLevelBuildingId(levelId, parentId, buildings) {
26
26
  return buildings.find((building) => building.children.includes(levelId))?.id ?? null;
27
27
  }
28
28
  /**
29
- * Per-building stacked elevations from stored storey heights: levels are
30
- * sorted by ordinal ascending within each building, the lowest level's floor
31
- * sits at 0, and each next floor sits on top of the previous storey height.
32
- * Levels with no resolvable building share one legacy stack from 0.
29
+ * Per-building stacked elevations from stored storey heights and additive
30
+ * base-elevation offsets: levels are sorted by ordinal ascending within each
31
+ * building, and each offset shifts its level plus every higher level in the
32
+ * same stack. Levels with no resolvable building share one legacy stack.
33
33
  *
34
34
  * Pure — operates on the serialized nodes record only.
35
35
  */
36
+ // Identity-keyed memo. `nodes` is an immutable store slice, so a hit means the
37
+ // scene has not changed since the last call. Hot callers ask once per wall per
38
+ // frame (WallCutout), which rebuilt an identical Map 1000+ times a frame. Weakly
39
+ // keyed so a closed project's node graph is not pinned by the memo.
40
+ const elevationMemo = new WeakMap();
36
41
  export function getLevelElevations(nodes) {
42
+ const memoized = elevationMemo.get(nodes);
43
+ if (memoized)
44
+ return memoized;
37
45
  const buildings = Object.values(nodes).filter((node) => node?.type === 'building');
38
46
  const entries = [];
39
47
  for (const node of Object.values(nodes)) {
@@ -42,6 +50,7 @@ export function getLevelElevations(nodes) {
42
50
  const level = node;
43
51
  entries.push({
44
52
  levelId: level.id,
53
+ baseElevation: level.baseElevation ?? 0,
45
54
  baseY: 0,
46
55
  height: getStoredLevelHeight(level),
47
56
  buildingId: resolveLevelBuildingId(level.id, level.parentId, buildings),
@@ -51,7 +60,7 @@ export function getLevelElevations(nodes) {
51
60
  const elevations = new Map();
52
61
  const cumulativeYByBuilding = new Map();
53
62
  for (const entry of entries.sort((a, b) => a.ordinal - b.ordinal)) {
54
- const baseY = cumulativeYByBuilding.get(entry.buildingId) ?? 0;
63
+ const baseY = (cumulativeYByBuilding.get(entry.buildingId) ?? 0) + entry.baseElevation;
55
64
  elevations.set(entry.levelId, {
56
65
  baseY,
57
66
  height: entry.height,
@@ -60,8 +69,22 @@ export function getLevelElevations(nodes) {
60
69
  });
61
70
  cumulativeYByBuilding.set(entry.buildingId, baseY + entry.height);
62
71
  }
72
+ elevationMemo.set(nodes, elevations);
63
73
  return elevations;
64
74
  }
75
+ function resolveLevelFloorToFloorHeight(levelId, elevations) {
76
+ const current = elevations.get(levelId);
77
+ if (!current)
78
+ return null;
79
+ const aboveId = findLevelAboveId(levelId, elevations);
80
+ if (!aboveId)
81
+ return current.height;
82
+ const above = elevations.get(aboveId);
83
+ return above ? above.baseY - current.baseY : current.height;
84
+ }
85
+ export function getLevelFloorToFloorHeight(levelId, nodes) {
86
+ return resolveLevelFloorToFloorHeight(levelId, getLevelElevations(nodes)) ?? DEFAULT_LEVEL_HEIGHT;
87
+ }
65
88
  /**
66
89
  * The id of the level directly above `levelId` in its own stack (same
67
90
  * resolved building, or the shared legacy stack for building-less levels):
@@ -141,7 +164,10 @@ function resolveCoveringSlabContext(levelId, nodes) {
141
164
  const level = nodes[levelId];
142
165
  if (level?.type !== 'level')
143
166
  return null;
144
- const above = getLevelAbove(levelId, nodes);
167
+ const elevations = getLevelElevations(nodes);
168
+ const aboveId = findLevelAboveId(levelId, elevations);
169
+ const aboveNode = aboveId ? nodes[aboveId] : null;
170
+ const above = aboveNode?.type === 'level' ? aboveNode : null;
145
171
  const slabs = [];
146
172
  for (const childId of above?.children ?? []) {
147
173
  const child = nodes[childId];
@@ -155,15 +181,19 @@ function resolveCoveringSlabContext(levelId, nodes) {
155
181
  continue;
156
182
  slabs.push(slab);
157
183
  }
158
- return { storeyHeight: getStoredLevelHeight(level), slabs };
184
+ return {
185
+ floorToFloorHeight: resolveLevelFloorToFloorHeight(levelId, elevations) ??
186
+ getStoredLevelHeight(level),
187
+ slabs,
188
+ };
159
189
  }
160
190
  /**
161
191
  * Underside of `slab`'s solid in the QUERIED level's local Y. The solid
162
192
  * occupies `[elevation - thickness, elevation]` in ITS level's local Y,
163
- * which sits `storeyHeight` above the queried level's floor.
193
+ * which sits `floorToFloorHeight` above the queried level's floor.
164
194
  */
165
- function coveringUndersideY(storeyHeight, slab) {
166
- return storeyHeight + ((slab.elevation ?? 0.05) - (slab.thickness ?? 0.05));
195
+ function coveringUndersideY(floorToFloorHeight, slab) {
196
+ return floorToFloorHeight + ((slab.elevation ?? 0.05) - (slab.thickness ?? 0.05));
167
197
  }
168
198
  /**
169
199
  * Whether `slab`'s stored footprint (polygon minus holes) covers `[x, z]`.
@@ -198,7 +228,7 @@ function lowestCoveringUndersideAt(context, x, z) {
198
228
  for (const slab of context.slabs) {
199
229
  if (!slabCoversPoint(slab, x, z))
200
230
  continue;
201
- const underside = coveringUndersideY(context.storeyHeight, slab);
231
+ const underside = coveringUndersideY(context.floorToFloorHeight, slab);
202
232
  if (lowest === null || underside < lowest)
203
233
  lowest = underside;
204
234
  }
@@ -207,7 +237,7 @@ function lowestCoveringUndersideAt(context, x, z) {
207
237
  /**
208
238
  * Underside of the LOWEST slab from the level above that covers
209
239
  * level-local point `[x, z]`, expressed in the queried level's local Y:
210
- * `storeyHeight + (slab.elevation - slab.thickness)`. `recessed` slabs
240
+ * `floorToFloorHeight + (slab.elevation - slab.thickness)`. `recessed` slabs
211
241
  * (pools) never cover. `null` when no covering slab (or no level above).
212
242
  *
213
243
  * Coordinate spaces: levels stack in Y only (`LevelNode` carries no XZ
@@ -245,9 +275,9 @@ export function getWallPlaneTop(wall, levelId, nodes) {
245
275
  const context = resolveCoveringSlabContext(levelId, nodes);
246
276
  if (!context)
247
277
  return DEFAULT_LEVEL_HEIGHT;
248
- let plane = context.storeyHeight;
278
+ let plane = context.floorToFloorHeight;
249
279
  for (const slab of context.slabs) {
250
- const underside = coveringUndersideY(context.storeyHeight, slab);
280
+ const underside = coveringUndersideY(context.floorToFloorHeight, slab);
251
281
  if (underside >= plane)
252
282
  continue;
253
283
  if (!wallOverlapsSlabFootprint(wall, slab.polygon, slab.holes))
@@ -274,7 +304,7 @@ export function getCeilingClampBound(levelId, nodes, polygon) {
274
304
  const context = resolveCoveringSlabContext(levelId, nodes);
275
305
  if (!context)
276
306
  return Number.POSITIVE_INFINITY;
277
- let bound = context.storeyHeight;
307
+ let bound = context.floorToFloorHeight;
278
308
  if (polygon.length > 0) {
279
309
  let cx = 0;
280
310
  let cz = 0;
@@ -9,16 +9,20 @@ type NodeUpdateOp = {
9
9
  data: Partial<AnyNode>;
10
10
  };
11
11
  type NodeDeleteOp = AnyNodeId;
12
- export declare const createNodesAction: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, ops: NodeCreateOp[]) => void;
13
- export declare const applyNodeChangesAction: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, changes: {
12
+ declare const createNodesActionImpl: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, ops: NodeCreateOp[]) => void;
13
+ declare const applyNodeChangesActionImpl: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, changes: {
14
14
  create?: NodeCreateOp[];
15
15
  update?: NodeUpdateOp[];
16
16
  delete?: NodeDeleteOp[];
17
17
  }) => void;
18
- export declare const updateNodesAction: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, updates: {
18
+ declare const updateNodesActionImpl: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, updates: {
19
19
  id: AnyNodeId;
20
20
  data: Partial<AnyNode>;
21
21
  }[]) => void;
22
- export declare const deleteNodesAction: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, ids: AnyNodeId[]) => void;
22
+ declare const deleteNodesActionImpl: (set: (fn: (state: SceneState) => Partial<SceneState>) => void, get: () => SceneState, ids: AnyNodeId[]) => void;
23
+ export declare const createNodesAction: (set: Parameters<typeof createNodesActionImpl>[0], get: Parameters<typeof createNodesActionImpl>[1], ops: NodeCreateOp[]) => void;
24
+ export declare const applyNodeChangesAction: (set: Parameters<typeof applyNodeChangesActionImpl>[0], get: Parameters<typeof applyNodeChangesActionImpl>[1], changes: Parameters<typeof applyNodeChangesActionImpl>[2]) => void;
25
+ export declare const updateNodesAction: (set: Parameters<typeof updateNodesActionImpl>[0], get: Parameters<typeof updateNodesActionImpl>[1], updates: Parameters<typeof updateNodesActionImpl>[2]) => void;
26
+ export declare const deleteNodesAction: (set: Parameters<typeof deleteNodesActionImpl>[0], get: Parameters<typeof deleteNodesActionImpl>[1], ids: AnyNodeId[]) => void;
23
27
  export {};
24
28
  //# sourceMappingURL=node-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node-actions.d.ts","sourceRoot":"","sources":["../../../src/store/actions/node-actions.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EASf,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG9C,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAA;AAC3D,KAAK,YAAY,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAC7D,KAAK,YAAY,GAAG,SAAS,CAAA;AA0vB7B,eAAO,MAAM,iBAAiB,GAC5B,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,KAAK,YAAY,EAAE,SAkDpB,CAAA;AAED,eAAO,MAAM,sBAAsB,GACjC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,SAAS;IAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE,SAyIvF,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,SAAS;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EAAE,SAoFrD,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,KAAK,SAAS,EAAE,SA8JjB,CAAA"}
1
+ {"version":3,"file":"node-actions.d.ts","sourceRoot":"","sources":["../../../src/store/actions/node-actions.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EASf,MAAM,cAAc,CAAA;AAGrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAG9C,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAA;AAC3D,KAAK,YAAY,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAC7D,KAAK,YAAY,GAAG,SAAS,CAAA;AA0vB7B,QAAA,MAAM,qBAAqB,GACzB,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,KAAK,YAAY,EAAE,SAkDpB,CAAA;AAED,QAAA,MAAM,0BAA0B,GAC9B,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,SAAS;IAAE,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE,SA2IvF,CAAA;AAED,QAAA,MAAM,qBAAqB,GACzB,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,SAAS;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EAAE,SA8FrD,CAAA;AAED,QAAA,MAAM,qBAAqB,GACzB,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,EAC7D,KAAK,MAAM,UAAU,EACrB,KAAK,SAAS,EAAE,SAgKjB,CAAA;AAED,eAAO,MAAM,iBAAiB,GAC5B,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,KAAK,YAAY,EAAE,SAQlB,CAAA;AAEH,eAAO,MAAM,sBAAsB,GACjC,KAAK,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,EACrD,KAAK,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,EACrD,SAAS,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC,CAAC,CAAC,SAYxD,CAAA;AAEH,eAAO,MAAM,iBAAiB,GAC5B,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,SAAS,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,SAKnD,CAAA;AAEH,eAAO,MAAM,iBAAiB,GAC5B,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,KAAK,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAChD,KAAK,SAAS,EAAE,SAC6D,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { nodeRegistry } from '../../registry/registry';
2
2
  import { AnyNode as AnyNodeSchema, createDefaultRidgeVentsForSegment, getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, isAutoRidgeVentEnabled, isDefaultRidgeVentNode, } from '../../schema';
3
+ import { addActiveSceneCommitNodeIds, runWithSceneCommitNodeIds } from '../history-control';
3
4
  const DEFAULT_RIDGE_VENT_REFRESH_FIELDS = new Set([
4
5
  'roofType',
5
6
  'width',
@@ -547,7 +548,7 @@ function buildWallMergePlans(nodes, idsToDelete) {
547
548
  }
548
549
  return mergePlans;
549
550
  }
550
- export const createNodesAction = (set, get, ops) => {
551
+ const createNodesActionImpl = (set, get, ops) => {
551
552
  if (get().readOnly)
552
553
  return;
553
554
  set((state) => {
@@ -595,7 +596,7 @@ export const createNodesAction = (set, get, ops) => {
595
596
  get().markDirty(node.parentId);
596
597
  });
597
598
  };
598
- export const applyNodeChangesAction = (set, get, changes) => {
599
+ const applyNodeChangesActionImpl = (set, get, changes) => {
599
600
  if (get().readOnly)
600
601
  return;
601
602
  const createOps = changes.create ?? [];
@@ -704,6 +705,7 @@ export const applyNodeChangesAction = (set, get, changes) => {
704
705
  }
705
706
  delete nextNodes[id];
706
707
  }
708
+ addActiveSceneCommitNodeIds([...allIdsToDelete, ...nodesToMarkDirty, ...parentsToMarkDirty]);
707
709
  return { nodes: nextNodes, rootNodeIds: resolvedRootIds, collections: nextCollections };
708
710
  });
709
711
  for (const id of nodesToMarkDirty) {
@@ -719,7 +721,7 @@ export const applyNodeChangesAction = (set, get, changes) => {
719
721
  }
720
722
  }
721
723
  };
722
- export const updateNodesAction = (set, get, updates) => {
724
+ const updateNodesActionImpl = (set, get, updates) => {
723
725
  if (get().readOnly)
724
726
  return;
725
727
  const parentsToUpdate = new Set();
@@ -773,10 +775,20 @@ export const updateNodesAction = (set, get, updates) => {
773
775
  }
774
776
  }
775
777
  }
778
+ addActiveSceneCommitNodeIds([
779
+ ...updates.map(({ id }) => id),
780
+ ...parentsToUpdate,
781
+ ...extraNodesToUpdate,
782
+ ]);
776
783
  return { nodes: nextNodes };
777
784
  });
778
785
  // Batch dirty-marking into a single RAF to avoid redundant callbacks during rapid updates
779
786
  for (const u of updates) {
787
+ // Visibility is applied by React before the deferred dirty callback. Mark
788
+ // it now so render systems can release collective geometry in that same
789
+ // frame, including when the host uses render-on-demand.
790
+ if (u.data.visible !== undefined)
791
+ get().markDirty(u.id);
780
792
  pendingUpdates.add(u.id);
781
793
  }
782
794
  for (const pId of parentsToUpdate) {
@@ -796,7 +808,7 @@ export const updateNodesAction = (set, get, updates) => {
796
808
  pendingRafId = null;
797
809
  });
798
810
  };
799
- export const deleteNodesAction = (set, get, ids) => {
811
+ const deleteNodesActionImpl = (set, get, ids) => {
800
812
  if (get().readOnly)
801
813
  return;
802
814
  const parentsToMarkDirty = new Set();
@@ -935,6 +947,7 @@ export const deleteNodesAction = (set, get, ids) => {
935
947
  // 4. Delete the node itself
936
948
  delete nextNodes[id];
937
949
  }
950
+ addActiveSceneCommitNodeIds([...allIds, ...parentsToMarkDirty, ...nodesToMarkDirty]);
938
951
  return { nodes: nextNodes, rootNodeIds: nextRootIds, collections: nextCollections };
939
952
  });
940
953
  // Deleted ids must leave the dirty set: every consumer skips missing
@@ -957,3 +970,17 @@ export const deleteNodesAction = (set, get, ids) => {
957
970
  get().markDirty(id);
958
971
  });
959
972
  };
973
+ export const createNodesAction = (set, get, ops) => runWithSceneCommitNodeIds(ops.flatMap(({ node, parentId }) => {
974
+ const effectiveParentId = parentId ?? node.parentId;
975
+ return effectiveParentId ? [node.id, effectiveParentId] : [node.id];
976
+ }), () => createNodesActionImpl(set, get, ops));
977
+ export const applyNodeChangesAction = (set, get, changes) => runWithSceneCommitNodeIds([
978
+ ...(changes.create ?? []).flatMap(({ node, parentId }) => {
979
+ const effectiveParentId = parentId ?? node.parentId;
980
+ return effectiveParentId ? [node.id, effectiveParentId] : [node.id];
981
+ }),
982
+ ...(changes.update ?? []).map(({ id }) => id),
983
+ ...(changes.delete ?? []),
984
+ ], () => applyNodeChangesActionImpl(set, get, changes));
985
+ export const updateNodesAction = (set, get, updates) => runWithSceneCommitNodeIds(updates.map(({ id }) => id), () => updateNodesActionImpl(set, get, updates));
986
+ export const deleteNodesAction = (set, get, ids) => runWithSceneCommitNodeIds(ids, () => deleteNodesActionImpl(set, get, ids));
@@ -13,6 +13,7 @@ export type SceneCommit = {
13
13
  origin: SceneCommitOrigin;
14
14
  before: SceneSnapshot;
15
15
  current: SceneSnapshot;
16
+ changedNodeIds?: ReadonlySet<AnyNodeId>;
16
17
  };
17
18
  export type SceneCommitListener = (commit: SceneCommit) => void;
18
19
  type TemporalStoreLike = {
@@ -33,11 +34,15 @@ type TemporalHistoryStoreLike<TPastState> = {
33
34
  }): void;
34
35
  };
35
36
  };
37
+ export declare function activeSceneCommitNodeIds(): ReadonlySet<AnyNodeId> | undefined;
38
+ export declare function addActiveSceneCommitNodeIds(nodeIds: Iterable<AnyNodeId>): void;
39
+ export declare function runWithSceneCommitNodeIds<TResult>(nodeIds: Iterable<AnyNodeId>, run: () => TResult): TResult;
36
40
  export declare function areSceneSnapshotsEqual(left: SceneSnapshot, right: SceneSnapshot): boolean;
37
41
  export declare function subscribeSceneCommits(listener: SceneCommitListener): () => void;
38
42
  export declare function notifySceneCommit(commit: SceneCommit): void;
39
43
  export declare function pauseSceneHistory(sceneStore: TemporalStoreLike): void;
40
44
  export declare function resumeSceneHistory(sceneStore: TemporalStoreLike): void;
45
+ export declare function acquireSceneHistoryPause(sceneStore: TemporalStoreLike): () => void;
41
46
  export declare function getSceneHistoryPauseDepth(): number;
42
47
  export declare function resetSceneHistoryPauseDepth(): void;
43
48
  export declare function runAsSingleSceneHistoryStep<TPastState, TResult>(sceneStore: TemporalHistoryStoreLike<TPastState>, run: () => TResult): TResult;
@@ -1 +1 @@
1
- {"version":3,"file":"history-control.d.ts","sourceRoot":"","sources":["../../src/store/history-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAIzD,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACjC,WAAW,EAAE,SAAS,EAAE,CAAA;IACxB,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAC7C,SAAS,EAAE,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IACjD,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,iBAAiB,CAAA;IACzB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,aAAa,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;AAE/D,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE;QACR,QAAQ,IAAI;YACV,KAAK,IAAI,IAAI,CAAA;YACb,MAAM,IAAI,IAAI,CAAA;SACf,CAAA;KACF,CAAA;CACF,CAAA;AAED,KAAK,wBAAwB,CAAC,UAAU,IAAI;IAC1C,QAAQ,EAAE;QACR,QAAQ,IAAI;YACV,UAAU,EAAE,UAAU,EAAE,CAAA;SACzB,CAAA;QACD,QAAQ,CAAC,KAAK,EAAE;YAAE,UAAU,EAAE,UAAU,EAAE,CAAA;SAAE,GAAG,IAAI,CAAA;KACpD,CAAA;CACF,CAAA;AA+BD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAQzF;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAK/E;AAYD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAiB3D;AAyBD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAKrE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAStE;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAkBD,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,OAAO,EAC7D,UAAU,EAAE,wBAAwB,CAAC,UAAU,CAAC,EAChD,GAAG,EAAE,MAAM,OAAO,GACjB,OAAO,CAuBT"}
1
+ {"version":3,"file":"history-control.d.ts","sourceRoot":"","sources":["../../src/store/history-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC9E,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAKzD,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACjC,WAAW,EAAE,SAAS,EAAE,CAAA;IACxB,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAC7C,SAAS,EAAE,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IACjD,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,iBAAiB,CAAA;IACzB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,aAAa,CAAA;IACtB,cAAc,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;AAE/D,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE;QACR,QAAQ,IAAI;YACV,KAAK,IAAI,IAAI,CAAA;YACb,MAAM,IAAI,IAAI,CAAA;SACf,CAAA;KACF,CAAA;CACF,CAAA;AAED,KAAK,wBAAwB,CAAC,UAAU,IAAI;IAC1C,QAAQ,EAAE;QACR,QAAQ,IAAI;YACV,UAAU,EAAE,UAAU,EAAE,CAAA;SACzB,CAAA;QACD,QAAQ,CAAC,KAAK,EAAE;YAAE,UAAU,EAAE,UAAU,EAAE,CAAA;SAAE,GAAG,IAAI,CAAA;KACpD,CAAA;CACF,CAAA;AAeD,wBAAgB,wBAAwB,IAAI,WAAW,CAAC,SAAS,CAAC,GAAG,SAAS,CAO7E;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,IAAI,CAI9E;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAC/C,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC5B,GAAG,EAAE,MAAM,OAAO,GACjB,OAAO,CAYT;AA2BD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAQzF;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAK/E;AAYD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAyB3D;AAyBD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAKrE;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAStE;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAelF;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD;AAkBD,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,OAAO,EAC7D,UAAU,EAAE,wBAAwB,CAAC,UAAU,CAAC,EAChD,GAAG,EAAE,MAAM,OAAO,GACjB,OAAO,CAuBT"}
@@ -1,7 +1,46 @@
1
1
  let sceneHistoryPauseDepth = 0;
2
+ const sceneHistoryPauseLeases = new Set();
2
3
  const sceneCommitListeners = new Set();
3
4
  let sceneCommitTransactionDepth = 0;
4
5
  let pendingSceneCommit = null;
6
+ const sceneCommitNodeIdScopes = [];
7
+ function mergedNodeIds(left, right) {
8
+ if (!(left || right))
9
+ return undefined;
10
+ return new Set([...(left ?? []), ...(right ?? [])]);
11
+ }
12
+ export function activeSceneCommitNodeIds() {
13
+ if (sceneCommitNodeIdScopes.length === 0)
14
+ return undefined;
15
+ const ids = new Set();
16
+ for (const scope of sceneCommitNodeIdScopes) {
17
+ for (const id of scope)
18
+ ids.add(id);
19
+ }
20
+ return ids;
21
+ }
22
+ export function addActiveSceneCommitNodeIds(nodeIds) {
23
+ const scope = sceneCommitNodeIdScopes.at(-1);
24
+ if (!scope)
25
+ return;
26
+ for (const id of nodeIds)
27
+ scope.add(id);
28
+ }
29
+ export function runWithSceneCommitNodeIds(nodeIds, run) {
30
+ const scope = new Set(nodeIds);
31
+ sceneCommitNodeIdScopes.push(scope);
32
+ try {
33
+ return run();
34
+ }
35
+ finally {
36
+ sceneCommitNodeIdScopes.pop();
37
+ const parentScope = sceneCommitNodeIdScopes.at(-1);
38
+ if (parentScope) {
39
+ for (const id of scope)
40
+ parentScope.add(id);
41
+ }
42
+ }
43
+ }
5
44
  function areSemanticValuesEqual(left, right) {
6
45
  if (Object.is(left, right))
7
46
  return true;
@@ -53,20 +92,25 @@ function emitSceneCommit(commit) {
53
92
  export function notifySceneCommit(commit) {
54
93
  if (areSceneSnapshotsEqual(commit.before, commit.current))
55
94
  return;
95
+ const contextualCommit = {
96
+ ...commit,
97
+ changedNodeIds: mergedNodeIds(commit.changedNodeIds, activeSceneCommitNodeIds()),
98
+ };
56
99
  if (sceneCommitTransactionDepth > 0) {
57
100
  if (pendingSceneCommit) {
58
101
  pendingSceneCommit = {
59
102
  origin: pendingSceneCommit.origin,
60
103
  before: pendingSceneCommit.before,
61
- current: commit.current,
104
+ current: contextualCommit.current,
105
+ changedNodeIds: mergedNodeIds(pendingSceneCommit.changedNodeIds, contextualCommit.changedNodeIds),
62
106
  };
63
107
  }
64
108
  else {
65
- pendingSceneCommit = commit;
109
+ pendingSceneCommit = contextualCommit;
66
110
  }
67
111
  return;
68
112
  }
69
- emitSceneCommit(commit);
113
+ emitSceneCommit(contextualCommit);
70
114
  }
71
115
  function beginSceneCommitTransaction() {
72
116
  sceneCommitTransactionDepth += 1;
@@ -88,7 +132,7 @@ function endSceneCommitTransaction() {
88
132
  }
89
133
  }
90
134
  export function pauseSceneHistory(sceneStore) {
91
- if (sceneHistoryPauseDepth === 0) {
135
+ if (getSceneHistoryPauseDepth() === 0) {
92
136
  sceneStore.temporal.getState().pause();
93
137
  }
94
138
  sceneHistoryPauseDepth += 1;
@@ -98,15 +142,33 @@ export function resumeSceneHistory(sceneStore) {
98
142
  return;
99
143
  }
100
144
  sceneHistoryPauseDepth -= 1;
101
- if (sceneHistoryPauseDepth === 0) {
145
+ if (getSceneHistoryPauseDepth() === 0) {
102
146
  sceneStore.temporal.getState().resume();
103
147
  }
104
148
  }
149
+ export function acquireSceneHistoryPause(sceneStore) {
150
+ if (getSceneHistoryPauseDepth() === 0) {
151
+ sceneStore.temporal.getState().pause();
152
+ }
153
+ const lease = Symbol('scene-history-pause');
154
+ sceneHistoryPauseLeases.add(lease);
155
+ let released = false;
156
+ return () => {
157
+ if (released)
158
+ return;
159
+ released = true;
160
+ sceneHistoryPauseLeases.delete(lease);
161
+ if (getSceneHistoryPauseDepth() === 0) {
162
+ sceneStore.temporal.getState().resume();
163
+ }
164
+ };
165
+ }
105
166
  export function getSceneHistoryPauseDepth() {
106
- return sceneHistoryPauseDepth;
167
+ return sceneHistoryPauseDepth + sceneHistoryPauseLeases.size;
107
168
  }
108
169
  export function resetSceneHistoryPauseDepth() {
109
170
  sceneHistoryPauseDepth = 0;
171
+ sceneHistoryPauseLeases.clear();
110
172
  }
111
173
  function retainedPastStateCount(before, after) {
112
174
  for (let start = 0; start < before.length; start += 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,OAAO,EAAU,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAInE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAoBrE,OAAO,EAEL,aAAa,EACb,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAA4B,MAAM,iBAAiB,CAAA;AAQxF,OAAO,EAOL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAA;AA0mC1B,MAAM,MAAM,UAAU,GAAG;IAEvB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAGjC,WAAW,EAAE,SAAS,EAAE,CAAA;IAGxB,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAG1B,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAC7C,SAAS,EAAE,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IACjD,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,6BAA6B,EAAE,OAAO,CAAA;IAGtC,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAGxC,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,CACR,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,WAAW,EAAE,SAAS,EAAE,EACxB,KAAK,CAAC,EAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;QAC9C,SAAS,CAAC,EAAE,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;QAClD,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;QAC3B,6BAA6B,CAAC,EAAE,OAAO,CAAA;KACxC,KACE,IAAI,CAAA;IACT,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAA;IAEpF,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAClC,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAEnC,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,IAAI,CAAA;IACzD,WAAW,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,IAAI,CAAA;IACrE,gBAAgB,EAAE,CAAC,OAAO,EAAE;QAC1B,MAAM,CAAC,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;SAAE,EAAE,CAAA;QAClD,MAAM,CAAC,EAAE;YAAE,EAAE,EAAE,SAAS,CAAC;YAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;SAAE,EAAE,CAAA;QACpD,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;KACrB,KAAK,IAAI,CAAA;IAEV,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IAC3D,WAAW,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,EAAE,KAAK,IAAI,CAAA;IAE3E,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IAGvC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,YAAY,CAAA;IACvE,gBAAgB,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAA;IAC5C,gBAAgB,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;IACnF,eAAe,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;IAC9D,oBAAoB,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;IAGnE,gBAAgB,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;IACnD,mBAAmB,EAAE,CAAC,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;IAC5F,mBAAmB,EAAE,CAAC,EAAE,EAAE,eAAe,KAAK,IAAI,CAAA;CACnD,CAAA;AAID,KAAK,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG;IACzD,QAAQ,EAAE,QAAQ,CAChB,aAAa,CACX,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,WAAW,GAAG,kBAAkB,CAAC,CAC7F,CACF,CAAA;CACF,CAAA;AAYD,QAAA,MAAM,QAAQ,EAAE,aAqTf,CAAA;AAED,eAAe,QAAQ,CAAA;AAKvB,wBAAgB,yBAAyB,IAAI,MAAM,IAAI,CAgBtD;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;IACtB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,EAAE,EAAE,eAAe,CAAA;IACnB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,eAAe,EAAE,kBAAkB,EAAE,CAAA;IACrC,WAAW,EAAE,cAAc,EAAE,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG;IAC7C,WAAW,EAAE,wBAAwB,EAAE,CAAA;IACvC,WAAW,EAAE,wBAAwB,EAAE,CAAA;CACxC,CAAA;AAkRD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CA0E9E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAM5D;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,EAAE,OAAO,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAAC,CAAA;CACpD,CAAA;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAyBT;AAOD,wBAAgB,iBAAiB,SAYhC"}
1
+ {"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"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"}