Phase 5 Stage D moves: live-drag mesh.position for slab / ceiling / fence
User-reported regressions on the 1:1 legacy ports: slab/ceiling moves were slow (polygon CSG rebuilds per scene.update tick), fence moves teleported briefly on commit (residual mesh.position offset survived the geometry rebuild). All three now use the same live-drag pattern the legacy fence move was designed for: - During drag, write only to `sceneRegistry.nodes.get(id).position` + `useLiveTransforms`. No `scene.update`, no polygon rebuild, no React re-render of geometry. - History stays UNPAUSED — scene state isn't changing. - On commit, a single `scene.update` writes the translated polygon (or fence start/end + linked-fence cascade). Recorded as one natural undo step. - Tools leave `mesh.position` at the drag delta on commit; GeometrySystem / CeilingSystem reset it to (0,0,0) when they rebuild the geometry on the next frame. By the time position clears, the new geometry is in place — no teleport. Two framework changes enable this: - `GeometrySystem` (viewer/systems/geometry) now resets `group.position` + `group.rotation` after every rebuild, matching the legacy `FenceSystem.updateFenceGeometry` behavior. Tools that translate the group during live-drag can rely on the reset. - Legacy `CeilingSystem.updateCeilingGeometry` extends its existing `position.y` reset to cover X/Z too — previously it left X/Z at the drag delta after rebuild, double-translating the visual. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
1e15e10185
commit
f4ea07e05b
@@ -54,7 +54,13 @@ function updateCeilingGeometry(node: CeilingNode, mesh: THREE.Mesh) {
|
||||
gridMesh.geometry = newGeo.clone()
|
||||
}
|
||||
|
||||
// Position at the ceiling height
|
||||
// Position at the ceiling height and reset X/Z so live-drag mesh
|
||||
// offsets (set by move tools during the drag) don't leak into the
|
||||
// canonical position after the rebuild. Matches the pattern used by
|
||||
// FenceSystem.updateFenceGeometry / GeometrySystem (both fully reset
|
||||
// position+rotation after rebuild).
|
||||
mesh.position.x = 0
|
||||
mesh.position.z = 0
|
||||
mesh.position.y = (node.height ?? 2.5) - 0.01 // Slight offset to avoid z-fighting with upper-level slabs
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,15 @@ export const GeometrySystem = () => {
|
||||
for (const child of [...built.children]) {
|
||||
group.add(child)
|
||||
}
|
||||
// Reset transform — matches the legacy per-kind systems
|
||||
// (e.g. FenceSystem.updateFenceGeometry) which clear
|
||||
// mesh.position/rotation when rebuilding. Tools that translate
|
||||
// the group via `mesh.position` for live-drag visuals rely on
|
||||
// this reset to restore the canonical position after scene
|
||||
// state catches up (otherwise the geometry rebuild renders on
|
||||
// top of the residual offset → double-translation teleport).
|
||||
group.position.set(0, 0, 0)
|
||||
group.rotation.set(0, 0, 0)
|
||||
|
||||
clearDirty(id as AnyNodeId)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user