@pascal-app/core 0.3.0 → 0.3.1
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.
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +37 -12
- package/dist/store/use-scene.d.ts +5 -0
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +13 -2
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +0 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-actions.d.ts","sourceRoot":"","sources":["../../../src/store/actions/node-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"node-actions.d.ts","sourceRoot":"","sources":["../../../src/store/actions/node-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAEtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAQ9C,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;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,EAAE,SA2C/C,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,SAgErD,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,SA4EjB,CAAA"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Track pending RAF for updateNodesAction to prevent multiple queued callbacks
|
|
2
|
+
let pendingRafId = null;
|
|
3
|
+
let pendingUpdates = new Set();
|
|
1
4
|
export const createNodesAction = (set, get, ops) => {
|
|
2
5
|
set((state) => {
|
|
3
6
|
const nextNodes = { ...state.nodes };
|
|
@@ -39,6 +42,7 @@ export const createNodesAction = (set, get, ops) => {
|
|
|
39
42
|
};
|
|
40
43
|
export const updateNodesAction = (set, get, updates) => {
|
|
41
44
|
const parentsToUpdate = new Set();
|
|
45
|
+
const idsToMarkDirty = new Set();
|
|
42
46
|
set((state) => {
|
|
43
47
|
const nextNodes = { ...state.nodes };
|
|
44
48
|
for (const { id, data } of updates) {
|
|
@@ -73,14 +77,22 @@ export const updateNodesAction = (set, get, updates) => {
|
|
|
73
77
|
}
|
|
74
78
|
return { nodes: nextNodes };
|
|
75
79
|
});
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
// Collect all IDs that need to be marked dirty
|
|
81
|
+
updates.forEach((u) => idsToMarkDirty.add(u.id));
|
|
82
|
+
parentsToUpdate.forEach((pId) => idsToMarkDirty.add(pId));
|
|
83
|
+
// Add to pending updates set
|
|
84
|
+
idsToMarkDirty.forEach((id) => pendingUpdates.add(id));
|
|
85
|
+
// Cancel any pending RAF and schedule a new one
|
|
86
|
+
if (pendingRafId !== null) {
|
|
87
|
+
cancelAnimationFrame(pendingRafId);
|
|
88
|
+
}
|
|
89
|
+
pendingRafId = requestAnimationFrame(() => {
|
|
90
|
+
// Mark all pending updates as dirty
|
|
91
|
+
pendingUpdates.forEach((id) => {
|
|
92
|
+
get().markDirty(id);
|
|
83
93
|
});
|
|
94
|
+
pendingUpdates.clear();
|
|
95
|
+
pendingRafId = null;
|
|
84
96
|
});
|
|
85
97
|
};
|
|
86
98
|
export const deleteNodesAction = (set, get, ids) => {
|
|
@@ -89,7 +101,25 @@ export const deleteNodesAction = (set, get, ids) => {
|
|
|
89
101
|
const nextNodes = { ...state.nodes };
|
|
90
102
|
const nextCollections = { ...state.collections };
|
|
91
103
|
let nextRootIds = [...state.rootNodeIds];
|
|
104
|
+
// Collect all IDs to delete (including descendants) in a first pass
|
|
105
|
+
// This avoids issues with recursive calls during state mutation
|
|
106
|
+
const allIdsToDelete = new Set();
|
|
107
|
+
const collectDescendants = (id) => {
|
|
108
|
+
const node = nextNodes[id];
|
|
109
|
+
if (!node)
|
|
110
|
+
return;
|
|
111
|
+
allIdsToDelete.add(id);
|
|
112
|
+
if ('children' in node && node.children) {
|
|
113
|
+
for (const childId of node.children) {
|
|
114
|
+
collectDescendants(childId);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
92
118
|
for (const id of ids) {
|
|
119
|
+
collectDescendants(id);
|
|
120
|
+
}
|
|
121
|
+
// Now process all nodes for deletion
|
|
122
|
+
for (const id of allIdsToDelete) {
|
|
93
123
|
const node = nextNodes[id];
|
|
94
124
|
if (!node)
|
|
95
125
|
continue;
|
|
@@ -118,11 +148,6 @@ export const deleteNodesAction = (set, get, ids) => {
|
|
|
118
148
|
}
|
|
119
149
|
// 4. Delete the node itself
|
|
120
150
|
delete nextNodes[id];
|
|
121
|
-
// Inside the deleteNodes loop
|
|
122
|
-
if ('children' in node && node.children.length > 0) {
|
|
123
|
-
// Recursively delete all children first
|
|
124
|
-
get().deleteNodes(node.children);
|
|
125
|
-
}
|
|
126
151
|
}
|
|
127
152
|
return { nodes: nextNodes, rootNodeIds: nextRootIds, collections: nextCollections };
|
|
128
153
|
});
|
|
@@ -36,5 +36,10 @@ type UseSceneStore = UseBoundStore<StoreApi<SceneState>> & {
|
|
|
36
36
|
};
|
|
37
37
|
declare const useScene: UseSceneStore;
|
|
38
38
|
export default useScene;
|
|
39
|
+
/**
|
|
40
|
+
* Clears temporal history tracking variables to prevent memory leaks.
|
|
41
|
+
* Should be called when unloading a scene to release node references.
|
|
42
|
+
*/
|
|
43
|
+
export declare function clearTemporalTracking(): void;
|
|
39
44
|
export declare function clearSceneHistory(): void;
|
|
40
45
|
//# sourceMappingURL=use-scene.d.ts.map
|
|
@@ -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;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAIrE,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AA8CzD,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;IAG7C,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IAE/E,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;IAErE,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;CACpE,CAAA;AAID,KAAK,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG;IACzD,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;CAC7F,CAAA;AAED,QAAA,MAAM,QAAQ,EAAE,
|
|
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;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAIrE,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AA8CzD,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;IAG7C,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IAE/E,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;IAErE,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;CACpE,CAAA;AAID,KAAK,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG;IACzD,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;CAC7F,CAAA;AAED,QAAA,MAAM,QAAQ,EAAE,aA0Mf,CAAA;AAED,eAAe,QAAQ,CAAA;AAOvB;;;GAGG;AACH,wBAAgB,qBAAqB,SAIpC;AAED,wBAAgB,iBAAiB,SAGhC"}
|
package/dist/store/use-scene.js
CHANGED
|
@@ -56,6 +56,10 @@ const useScene = create()(temporal((set, get) => ({
|
|
|
56
56
|
// 4. Collections
|
|
57
57
|
collections: {},
|
|
58
58
|
unloadScene: () => {
|
|
59
|
+
// Clear temporal tracking to prevent memory leaks from stale node references
|
|
60
|
+
prevPastLength = 0;
|
|
61
|
+
prevFutureLength = 0;
|
|
62
|
+
prevNodesSnapshot = null;
|
|
59
63
|
set({
|
|
60
64
|
nodes: {},
|
|
61
65
|
rootNodeIds: [],
|
|
@@ -222,12 +226,19 @@ export default useScene;
|
|
|
222
226
|
let prevPastLength = 0;
|
|
223
227
|
let prevFutureLength = 0;
|
|
224
228
|
let prevNodesSnapshot = null;
|
|
225
|
-
|
|
226
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Clears temporal history tracking variables to prevent memory leaks.
|
|
231
|
+
* Should be called when unloading a scene to release node references.
|
|
232
|
+
*/
|
|
233
|
+
export function clearTemporalTracking() {
|
|
227
234
|
prevPastLength = 0;
|
|
228
235
|
prevFutureLength = 0;
|
|
229
236
|
prevNodesSnapshot = null;
|
|
230
237
|
}
|
|
238
|
+
export function clearSceneHistory() {
|
|
239
|
+
useScene.temporal.getState().clear();
|
|
240
|
+
clearTemporalTracking();
|
|
241
|
+
}
|
|
231
242
|
// Subscribe to the temporal store (Undo/Redo events)
|
|
232
243
|
useScene.temporal.subscribe((state) => {
|
|
233
244
|
const currentPastLength = state.pastStates.length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wall-system.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-system.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGhE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"wall-system.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-system.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,OAAO,EAAa,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGhE,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,iBAAiB,CAAA;AASxB,eAAO,MAAM,UAAU,YAsDtB,CAAA;AA0DD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,OAAO,EAAE,EACxB,SAAS,EAAE,aAAa,EACxB,aAAa,SAAI,oFA+FlB"}
|
|
@@ -13,7 +13,6 @@ const csgEvaluator = new Evaluator();
|
|
|
13
13
|
// ============================================================================
|
|
14
14
|
// WALL SYSTEM
|
|
15
15
|
// ============================================================================
|
|
16
|
-
let useFrameNb = 0;
|
|
17
16
|
export const WallSystem = () => {
|
|
18
17
|
const dirtyNodes = useScene((state) => state.dirtyNodes);
|
|
19
18
|
const clearDirty = useScene((state) => state.clearDirty);
|
|
@@ -23,7 +22,6 @@ export const WallSystem = () => {
|
|
|
23
22
|
const nodes = useScene.getState().nodes;
|
|
24
23
|
// Collect dirty walls and their levels
|
|
25
24
|
const dirtyWallsByLevel = new Map();
|
|
26
|
-
useFrameNb += 1;
|
|
27
25
|
dirtyNodes.forEach((id) => {
|
|
28
26
|
const node = nodes[id];
|
|
29
27
|
if (!node || node.type !== 'wall')
|