feat(graph-layout): implement caching for spawn Y positions to prevent jitter

- Introduced a caching mechanism for spawn Y positions of child sessions to maintain stability during parent action accumulation.
- Updated the layoutGraph function to utilize cached values, reducing recalculation and improving layout consistency.
- Added cleanup logic to remove entries from the cache for sessions that no longer exist, ensuring efficient memory usage.
This commit is contained in:
Luciano Castillo
2026-01-30 11:46:42 -05:00
parent f9dbd9b0bf
commit 5af254087c
+24 -2
View File
@@ -35,6 +35,10 @@ const ROOT_START_Y = 200 // Vertical offset from crab to first root session
const MIN_SESSION_GAP = 120 // Minimum vertical gap between sessions in same column
const ROOT_HORIZONTAL_GAP = 0 // Gap between root sessions in horizontal mode
// Cache spawn Y positions so they don't change as parent actions accumulate
// Key: session key, Value: calculated spawn Y offset
const spawnYCache = new Map<string, number>()
interface SessionColumn {
sessionKey: string
columnIndex: number
@@ -215,6 +219,7 @@ export function layoutGraph(
// Calculate spawn Y positions for child sessions
// When a session is spawned, find the Y position of the parent at that time
// Cache these values so they don't jitter as parent actions accumulate
for (const session of sessions) {
if (!session.spawnedBy) continue
@@ -222,6 +227,13 @@ export function layoutGraph(
const childCol = sessionColumns.get(session.key)
if (!parentCol || !childCol) continue
// Use cached spawn Y if available (prevents jitter from recalculation)
const cachedSpawnY = spawnYCache.get(session.key)
if (cachedSpawnY !== undefined) {
childCol.spawnY = cachedSpawnY
continue
}
// Find the approximate position in parent where spawn happened
// Use the child's creation time (approximated by first action time or session activity)
const childActions = actionsBySession.get(session.key) ?? []
@@ -239,8 +251,10 @@ export function layoutGraph(
}
}
// Calculate Y based on parent's item count
childCol.spawnY = parentItemsBeforeSpawn * (NODE_DIMENSIONS.action.height + ROW_GAP) + SPAWN_OFFSET
// Calculate Y based on parent's item count and cache it
const calculatedSpawnY = parentItemsBeforeSpawn * (NODE_DIMENSIONS.action.height + ROW_GAP) + SPAWN_OFFSET
spawnYCache.set(session.key, calculatedSpawnY)
childCol.spawnY = calculatedSpawnY
}
// Position all nodes
@@ -362,6 +376,14 @@ export function layoutGraph(
}
}
// Clean up spawn Y cache for sessions that no longer exist
const currentSessionKeys = new Set(sessions.map(s => s.key))
for (const key of spawnYCache.keys()) {
if (!currentSessionKeys.has(key)) {
spawnYCache.delete(key)
}
}
return { nodes: positionedNodes, edges }
}