From 11bbf1e66352f92ef8bc47950229ccea82c4279d Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Tue, 4 Aug 2026 20:55:34 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Auto-deploy:=20melhoria=20no=20s?= =?UTF-8?q?nap=20e=20medi=C3=A7=C3=A3o=20AR=20em=2004/08/2026=2020:55:34?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/three/XRGrabbable.tsx | 18 ++++++- src/lab/QuestCubeLab.tsx | 72 +++++++++++++++++----------- 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/components/three/XRGrabbable.tsx b/src/components/three/XRGrabbable.tsx index 8aff615..292b994 100644 --- a/src/components/three/XRGrabbable.tsx +++ b/src/components/three/XRGrabbable.tsx @@ -16,6 +16,8 @@ interface XRGrabbableProps { lockedActive?: boolean; /** Called the first time the user grabs (e.g. to exit placement mode) */ onGrabStart?: () => void; + /** Optional callback to sync transforms to local state instead of store */ + onSync?: (pos: THREE.Vector3, quat: THREE.Quaternion, scale: THREE.Vector3) => void; children: ReactNode; } @@ -54,7 +56,7 @@ const _tmpQuat = new THREE.Quaternion(); * segurar ambos os botões de Grip (L+R) e mover as mãos em direções opostas (giro) ou * afastar/aproximar as mãos (zoom). */ -export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabStart, children }: XRGrabbableProps) { +export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabStart, onSync, children }: XRGrabbableProps) { const groupRef = useRef(null); const grab = useControllerGrab(); const session = useXR((s) => s.session); @@ -88,6 +90,20 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta const group = groupRef.current; if (!group) return; + if (onSync) { + const finalPos = new THREE.Vector3(); + const finalQuat = new THREE.Quaternion(); + const finalScale = new THREE.Vector3(); + group.matrixWorld.decompose(finalPos, finalQuat, finalScale); + + group.position.set(0, 0, 0); + group.quaternion.identity(); + group.scale.set(1, 1, 1); + + onSync(finalPos, finalQuat, finalScale); + return; + } + const state = useModelStore.getState(); const activeModelId = state.activeModelId; if (!activeModelId) return; diff --git a/src/lab/QuestCubeLab.tsx b/src/lab/QuestCubeLab.tsx index 479c473..794a3b2 100644 --- a/src/lab/QuestCubeLab.tsx +++ b/src/lab/QuestCubeLab.tsx @@ -19,6 +19,7 @@ import { Hand, } from "lucide-react"; import { Suspense } from "react"; +import { XRGrabbable } from "@/components/three/XRGrabbable"; /** * ============================================================ @@ -167,36 +168,53 @@ const CubeControlado = ({ }); return ( - { - e.stopPropagation(); - if (!e.intersections[0].face) return; - const localNormal = e.intersections[0].face.normal; + { + posRef.current.x = pos.x; + posRef.current.y = Math.max(0.5, pos.y); + posRef.current.z = pos.z; - if (alignPhase === 'IDLE') { - face1Ref.current.copy(localNormal); - setAlignPhase('WAIT_SURFACE'); - } else if (alignPhase === 'WAIT_FACE2') { - if (Math.abs(face1Ref.current.dot(localNormal)) < 0.1) { - face2Ref.current.copy(localNormal); - setAlignPhase('WAIT_EDGE'); - } else { - alert("Por favor, selecione uma face diferente da primeira (ortogonal) para alinhar a direção."); - } - } + const euler = new THREE.Euler().setFromQuaternion(quat, 'YXZ'); + rotRef.current.x = euler.x; + rotRef.current.y = euler.y; + rotRef.current.z = euler.z; + + scaleRef.current = scale.x; }} - onPointerOver={(e) => { e.stopPropagation(); document.body.style.cursor = 'pointer'; }} - onPointerOut={() => { document.body.style.cursor = 'auto'; }} > - - {materials.map((m, i) => ( - - ))} - + { + e.stopPropagation(); + if (!e.intersections[0].face) return; + const localNormal = e.intersections[0].face.normal; + + if (alignPhase === 'IDLE') { + face1Ref.current.copy(localNormal); + setAlignPhase('WAIT_SURFACE'); + } else if (alignPhase === 'WAIT_FACE2') { + if (Math.abs(face1Ref.current.dot(localNormal)) < 0.1) { + face2Ref.current.copy(localNormal); + setAlignPhase('WAIT_EDGE'); + } else { + alert("Por favor, selecione uma face diferente da primeira (ortogonal) para alinhar a direção."); + } + } + }} + onPointerOver={(e) => { e.stopPropagation(); document.body.style.cursor = 'pointer'; }} + onPointerOut={() => { document.body.style.cursor = 'auto'; }} + > + + {materials.map((m, i) => ( + + ))} + + ); };