Ajustou grid à face inferior

X-Lovable-Edit-ID: edt-9adbb18a-f106-4dcf-a001-1173b3d4655d
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot]
2026-05-24 20:45:58 +00:00
+16 -13
View File
@@ -1035,25 +1035,27 @@ function GridLayer() {
); );
} }
/** Computes min Y of all visible models and updates store gridY when auto-follow is on. */ /** Continuously aligns the grid Y to the bottom of all visible models so the
* piece always looks like it is sitting on the grid — including after
* calibration, fine-tuning, repositioning or scale changes. */
function GridAutoFollower() { function GridAutoFollower() {
const models = useModelStore((s) => s.models);
const { scene } = useThree(); const { scene } = useThree();
useEffect(() => { const lastY = useRef<number>(Number.NaN);
const acc = useRef(0);
useFrame((_, dt) => {
const auto = useModelStore.getState().gridAutoFollow; const auto = useModelStore.getState().gridAutoFollow;
if (!auto) return; if (!auto) return;
// Defer to next tick so models have rendered/positioned // Throttle to ~10 Hz to keep this cheap.
const id = setTimeout(() => { acc.current += dt;
if (!useModelStore.getState().gridAutoFollow) return; if (acc.current < 0.1) return;
acc.current = 0;
const box = new THREE.Box3(); const box = new THREE.Box3();
let has = false; let has = false;
scene.traverse((obj) => { scene.traverse((obj) => {
if (obj instanceof THREE.Mesh && obj.geometry) { if (obj instanceof THREE.Mesh && obj.geometry) {
// Skip helpers (markers, rings)
if (obj.geometry instanceof THREE.SphereGeometry) return; if (obj.geometry instanceof THREE.SphereGeometry) return;
if (obj.geometry instanceof THREE.RingGeometry) return; if (obj.geometry instanceof THREE.RingGeometry) return;
if (obj.userData.__edgeLine) return; if (obj.userData.__edgeLine) return;
obj.updateWorldMatrix(true, false);
const b = new THREE.Box3().setFromObject(obj); const b = new THREE.Box3().setFromObject(obj);
if (isFinite(b.min.y)) { if (isFinite(b.min.y)) {
if (!has) { box.copy(b); has = true; } if (!has) { box.copy(b); has = true; }
@@ -1061,12 +1063,13 @@ function GridAutoFollower() {
} }
} }
}); });
if (has) { if (!has) return;
useModelStore.setState({ gridY: box.min.y - 0.005 }); const target = box.min.y - 0.005;
if (!Number.isFinite(lastY.current) || Math.abs(target - lastY.current) > 1e-4) {
lastY.current = target;
useModelStore.setState({ gridY: target });
} }
}, 100); });
return () => clearTimeout(id);
}, [models, scene]);
return null; return null;
} }