diff --git a/apps/editor/components/tools/item/placement-strategies.ts b/apps/editor/components/tools/item/placement-strategies.ts index cc7d7c8e..08b782ef 100644 --- a/apps/editor/components/tools/item/placement-strategies.ts +++ b/apps/editor/components/tools/item/placement-strategies.ts @@ -80,6 +80,7 @@ export const floorStrategy = { return { nodeUpdate: { position: pos, + parentId: ctx.levelId, metadata: stripTransient(ctx.draftItem.metadata), }, stopPropagation: false, diff --git a/apps/editor/components/tools/item/use-placement-coordinator.tsx b/apps/editor/components/tools/item/use-placement-coordinator.tsx index 27b136be..7f22a1ee 100644 --- a/apps/editor/components/tools/item/use-placement-coordinator.tsx +++ b/apps/editor/components/tools/item/use-placement-coordinator.tsx @@ -693,6 +693,17 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea } }, [asset, canPlaceOnFloor, canPlaceOnWall, canPlaceOnCeiling, draftNode]) + // Reparent floor draft to the new level when the user switches levels mid-placement. + // Wall/ceiling items are managed by their own surface entry events (ensureDraft / reparent). + const viewerLevelId = useViewer((s) => s.selection.levelId) + useEffect(() => { + const draft = draftNode.current + if (!draft || !viewerLevelId || asset.attachTo) return + if (draft.parentId === viewerLevelId) return + draft.parentId = viewerLevelId + useScene.getState().updateNode(draft.id as AnyNodeId, { parentId: viewerLevelId }) + }, [viewerLevelId, draftNode, asset]) + useFrame((_, delta) => { if (!draftNode.current) return const mesh = sceneRegistry.nodes.get(draftNode.current.id) @@ -724,7 +735,10 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea draftNode.current.rotation, ) mesh.position.y = slabElevation - cursorGroupRef.current.position.y = slabElevation + // Cursor group is at the world root (not inside a level group), so add the + // level group's current world Y to convert from level-local to world space. + const levelGroup = sceneRegistry.nodes.get(levelId as AnyNodeId) + cursorGroupRef.current.position.y = slabElevation + (levelGroup?.position.y ?? 0) } } })