Files
SteelXR2/.lovable/plan.md
T
gpt-engineer-app[bot] c6d50b07a4 Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
2026-05-21 21:05:48 +00:00

5.1 KiB

Objetivo

Alinhar o comportamento dos controles Touch Plus (Meta Quest 3) ao padrão pedido:

  • Grip = único responsável por mover a peça (pan, zoom, orbit).
  • Trigger = apenas seleção, medição e ações pontuais (nunca move/rotaciona a peça).
  • Thumbstick = navegação do usuário (teletransporte/recuar/girar a câmera), nunca mais ajuste fino do modelo.
  • Botão Menu = mantém comportamento nativo (não tocar).

Mapeamento alvo

Mão               Botão              Ação
─────────────────────────────────────────────────────────
Esquerda/Direita  Grip (1 mão)       Pan da peça (translação 6DOF, sem rotação)
Ambas as mãos     Grip + afastar     Zoom uniforme (escala)
Ambas as mãos     Grip + giro oposto Orbitar/rotacionar a peça
Direita           Trigger            Selecionar componente / adicionar ponto de medida
Esquerda          Trigger            Alternar snap de vértice (já existe)
Direita           Botão A            Desfazer última medida (já existe)
Direita           Botão B            Limpar medidas (já existe)
Thumbstick        Frente + soltar    Teletransporte para o ponto apontado
Thumbstick        Lados              Snap-rotate da câmera (±30°)
Thumbstick        Trás               Recuar o usuário (passo)

Mudanças no código

1. src/components/three/XRGrabbable.tsx

  • One-hand grip: passar a aplicar apenas translação (pan). Hoje aplica matriz completa do grip → leva rotação junto. Vou capturar o offset de posição e atualizar só group.position, mantendo quaternion e scale.
  • Two-hand grip: manter rotação pelo eixo entre as mãos + forçar allowScale = true sempre (zoom passa a vir do grip, não depende mais do toggle do HUD).
  • Remover a prop allowScale da assinatura (ou ignorar e tratar como true).

2. src/pages/XRSession.tsx

  • Remover o estado allowScale e os toggles correspondentes nas duas instâncias de <XRGrabbable>.
  • Substituir <ControllerFineTuning /> por um novo <ControllerLocomotion /> (ver item 4) — o joystick não deve mais editar fineTuning do modelo.
  • Garantir que XRHitTestPlacement só consome onSelect (trigger) quando placementMode === true; fora disso o trigger é roteado integralmente para XRControllerMeasure.

3. src/components/XRHud.tsx e src/components/three/XRHudInWorld.tsx

  • Remover botão/toggle “Permitir escala” (allowScale) — agora é sempre via grip duplo.
  • Remover/relabelar o toggle “Movimento livre” (freeMove) já que o joystick deixa de ajustar o modelo; manter apenas se ainda fizer sentido para outra função (caso não, remover prop também de XRSession.tsx).

4. Novo src/components/three/ControllerLocomotion.tsx

Componente que substitui ControllerFineTuning. Lê useXR().session e implementa:

  • Joystick esquerdo (ou ambos, configurável):
    • axes[1] < -0.7 mantido por ~200 ms → dispara teleport: raycast a partir do controle direito contra scene.children no plano horizontal mais próximo; aplica xrOrigin.position para reposicionar.
    • axes[1] > 0.7 → recua o XROrigin em passos de 0.3 m por trigger.
    • axes[0] cruzando ±0.7 (com histerese) → snap-rotate de ±30° no XROrigin.rotation.y.
  • Usar a API XROrigin já montada em XRSession.tsx (referência via useRef ou store) para escrever pose.
  • Desligar tudo se lockedActive (modelo travado) — locomoção do usuário ainda funciona, só não move o modelo.

5. src/components/three/XRControllerMeasure.tsx

  • Sem mudanças funcionais — já usa apenas trigger e botões A/B. Apenas confirmar que o early-return (!measureMode && !selectionMode) continua: quando nenhum dos modos está ativo, o trigger não dispara nada relacionado à medição (e não interfere em XRHitTestPlacement, que respeita placementMode).

6. src/components/three/XRHitTestPlacement.tsx

  • Garantir que o handler onSelect (trigger) verifica placementMode antes de colocar o modelo. Hoje o tap-plane invisível pode estar capturando o select mesmo fora do placement — adicionar guarda explícita e visible={placementMode}.

Validação

  1. Desktop SimXR (devkit): pressionar Q/W (grip simulado) move a peça; pressionar A/S (trigger simulado) não muda pose nenhuma.
  2. Quest 3 real (passthrough):
    • Grip único arrasta a peça sem rotacionar.
    • Dois grips afastando = zoom; dois grips em rotação oposta = orbit.
    • Trigger direito fora dos modos medir/selecionar/colocar = nada acontece.
    • Trigger direito em modo Selecionar = seleciona componente IFC.
    • Trigger direito em modo Medir = adiciona ponto com snap.
    • Joystick esquerdo para frente = teletransporte; lados = snap-rotate; trás = recua.
  3. Logs [XR][grab] continuam mostrando início/fim de one-hand e two-hand.

Fora do escopo

  • Não mexer no botão Menu (Universal Menu do Quest é nativo).
  • Não alterar handlers DOM/mouse do modo desktop (Viewer).
  • Não tocar em RLS, store de dados ou backend.