Fix shelf cursor tracking + bigger snap step; tint registry spawn red
Three small follow-ups after the first user-visible spike test. shelf cursor stuck at origin: The placeholder cursor is a translucent slab inside a <group ref>. The tool was calling setCursor(state) on every grid:move, which triggered a React re-render. R3F re-applies props on each render, and since the <group> had no `position` prop, the implicit default [0,0,0] clobbered the imperative `position.set` from the previous tick. Result: cursor stuck at level origin instead of following the mouse. Fix: drop the unused useState entirely. Pure imperative position updates via the ref. No re-renders, no clobbering. (The legacy spawn tool gets away with the same pattern because CursorSphere buffers its position prop differently — but for the spike, the simpler model is fine.) shelf snap step: Was 0.1 (10cm) — much finer than the editor's default 0.5 grid. Bumped to 0.5 (matches the toolbar grid setting and the legacy half-meter snap pattern used by spawn/column). registry-driven spawn renderer paints red: Temporary verification marker. With NEXT_PUBLIC_USE_REGISTRY_FOR_ SPAWN=1, spawns rendered via the new path now appear in #ef4444 red. Legacy renderer stays in #22c55e green. Easy visual check for "which dispatch path is this spawn on?" Reverted in the PR that signs off spawn parity (alongside legacy file deletion). 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
88546d26f0
commit
ac71c1a83b
@@ -3,42 +3,43 @@
|
||||
import {
|
||||
emitter,
|
||||
type GridEvent,
|
||||
ShelfNode,
|
||||
sceneRegistry,
|
||||
ShelfNode,
|
||||
snapPointToGrid,
|
||||
useScene,
|
||||
} from '@pascal-app/core'
|
||||
import { useViewer } from '@pascal-app/viewer'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { type Group, Vector3 } from 'three'
|
||||
|
||||
const worldVector = new Vector3()
|
||||
const GRID_STEP = 0.5 // match the editor's default placement grid
|
||||
|
||||
function getLevelLocalPosition(levelId: string, event: GridEvent): [number, number, number] {
|
||||
const levelObject = sceneRegistry.nodes.get(levelId)
|
||||
if (!levelObject) {
|
||||
const [sx, sz] = snapPointToGrid([event.localPosition[0], event.localPosition[2]], 0.1)
|
||||
const [sx, sz] = snapPointToGrid([event.localPosition[0], event.localPosition[2]], GRID_STEP)
|
||||
return [sx, event.localPosition[1], sz]
|
||||
}
|
||||
worldVector.set(event.position[0], event.position[1], event.position[2])
|
||||
levelObject.updateWorldMatrix(true, false)
|
||||
levelObject.worldToLocal(worldVector)
|
||||
const [sx, sz] = snapPointToGrid([worldVector.x, worldVector.z], 0.1)
|
||||
const [sx, sz] = snapPointToGrid([worldVector.x, worldVector.z], GRID_STEP)
|
||||
return [sx, worldVector.y, sz]
|
||||
}
|
||||
|
||||
const ShelfTool = () => {
|
||||
const activeLevelId = useViewer((state) => state.selection.levelId)
|
||||
const [, setCursor] = useState<[number, number, number] | null>(null)
|
||||
const cursorRef = useRef<Group>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeLevelId) return
|
||||
|
||||
const onGridMove = (event: GridEvent) => {
|
||||
const [sx, sz] = snapPointToGrid([event.localPosition[0], event.localPosition[2]], 0.1)
|
||||
const next: [number, number, number] = [sx, event.localPosition[1], sz]
|
||||
setCursor(next)
|
||||
// Imperative position update — no React state, so the component
|
||||
// doesn't re-render. R3F-applied props would otherwise clobber the
|
||||
// imperative `position.set` on the next render.
|
||||
const next = getLevelLocalPosition(activeLevelId, event)
|
||||
cursorRef.current?.position.set(next[0], next[1], next[2])
|
||||
}
|
||||
|
||||
@@ -64,6 +65,9 @@ const ShelfTool = () => {
|
||||
|
||||
if (!activeLevelId) return null
|
||||
|
||||
// Cursor preview — a translucent shelf-shaped slab. No `position` prop on
|
||||
// the group; we move it imperatively via the ref so React re-renders don't
|
||||
// reset it to the origin.
|
||||
return (
|
||||
<group ref={cursorRef}>
|
||||
<mesh position={[0, 0.9, 0]}>
|
||||
|
||||
Reference in New Issue
Block a user