5.9 KiB
Objetivo
Construir uma "giga de teste" (DevKit) que vista o app com simulação completa de XR + instrumentação, permitindo:
- Você (sem Quest): validar quase 100% do fluxo direto no navegador, incluindo grab, posicionamento e medição.
- Testador (com Quest): receber um build com painel de diagnóstico visível e log persistente, devolvendo feedback objetivo.
- Remoção limpa: quando o app estiver maduro, apagar 1 pasta + remover 3 imports + apagar 1 flag → app puro restaurado.
Princípios de isolamento
- Todo código do DevKit vive em
src/devkit/(pasta nova). Nada de código de simulação espalhado pelo app. - Ativação por flag única
?devkit=1na URL OUlocalStorage.setItem('devkit', '1'). Sem flag → app roda exatamente como hoje. - Componentes do DevKit são montados condicionalmente em 3 pontos de injeção apenas (todos em
XRSession.tsx). Esses pontos ficam marcados com comentário// DEVKIT: remove this blockpara facilitar a limpeza futura. - Zero alteração de lógica de negócio. Tudo que o DevKit faz é observar (logger), simular (fake inputs) ou adicionar UI extra (painel).
Componentes do DevKit
1. devkit/DevKitFlag.ts — detector de modo
Hook useDevKit() retorna boolean. Lê URLSearchParams + localStorage. Se true, ativa todo o resto.
2. devkit/SimXRSession.tsx — modo "Faux-XR" pra desktop
Resolve seu problema #1: validar tudo sem headset.
Quando ativado (botão "🧪 Simular XR" no header, só aparece com ?devkit=1):
- Não chama
store.enterAR()(que falha sem HTTPS/headset compatível). - Em vez disso, força
inXR=truenum estado paralelosimXR. - Renderiza a árvore
XRGrabbable + XRModelsemXRHitTestPlacement(auto-posiciona em[0,0,-1.5]). - Substitui leitura de
session.inputSourcespor uma fonte fake (ver #3). - Câmera fica controlável por
OrbitControls(você navega como quiser).
3. devkit/FakeControllers.tsx — controles virtuais com mouse/teclado
Resolve seu problema #2: testar grab sem Touch Plus.
- Desenha 2 esferas coloridas (L=azul, R=vermelho) na cena, posicionáveis por arrastar com mouse.
- Atalhos teclado:
Q/W→ segurar grip esquerdo / direito (analógico simulado em 1.0)A/S→ segurar trigger esquerdo / direitoSetas→ mover controle ativoShift + Setas→ mover controle no eixo Z
- Expõe um
FakeInputProvider(Context) queuseControllerGrabconsome quando em modo DevKit. Sem DevKit, hook continua lendosession.inputSourcesreal. - Mudança mínima em
useControllerGrab.ts: uma linha checandoif (devkit) return useFakeInputs(). Removível.
4. devkit/DevPanel.tsx — painel de diagnóstico flutuante
Painel HTML overlay (canto direito), só visível com ?devkit=1:
- Aba "Inputs": valores ao vivo de cada controle (real ou fake) — grip, trigger, axes, hasPose
- Aba "Cena": posição/rotação/escala do grupo grabável, contagem de meshes, bbox
- Aba "XR":
session?.mode, hit-test ativo, planos detectados (count + labels), FPS - Aba "Logs": últimos 100 console.logs com timestamp, filtro por tag (
[XR],[grab],[HitTest]) - Botão "Exportar relatório" → baixa JSON com snapshot atual + screenshot do canvas. Você pede pro testador clicar isso e te enviar o arquivo.
5. devkit/XRDevHud.tsx — HUD in-world expandido (substitui o XRDebugHud atual quando ativo)
Painel 3D maior, ancorado no pulso esquerdo (não na câmera, pra não atrapalhar). Mostra mesmas infos da aba "Inputs" + "XR" do DevPanel. Visível dentro do headset, essencial pro testador.
6. devkit/SmokeTest.tsx — roteiro automático
Rota nova /devkit/smoke (só roteada com ?devkit=1):
- Sequência scriptada: carrega demo → simula grip esquerdo → move 50cm → solta → mede 2 pontos → screenshot → checklist.
- Cada passo mostra ✅/❌ + tempo.
- Você roda antes de mandar build pro testador.
7. devkit/RecordSession.tsx — gravador de "macros"
Botão "Gravar" no DevPanel: captura por 30s todos inputs + posições da cena num JSON. Botão "Reproduzir": replay do macro. Útil pra reproduzir um bug que o testador relatou ("clico aqui, viro assim, peça desaparece").
Pontos de injeção em XRSession.tsx
Apenas 3 blocos curtos, todos cercados por {devkit && <... />}:
// DEVKIT: remove this block
{devkit && <SimXRButton onActivate={setSimXR} />}
// DEVKIT: remove this block
{devkit && simXR && <FakeControllers />}
// DEVKIT: remove this block
{devkit && <DevPanel />}
E uma linha em useControllerGrab.ts:
// DEVKIT: remove this conditional
if (typeof window !== 'undefined' && useDevKitFake()) return fakeRef;
Como remover o DevKit no futuro (1 minuto)
rm -rf src/devkit/- Em
XRSession.tsx: deletar 3 blocos marcados// DEVKIT:+ import. - Em
useControllerGrab.ts: deletar linha marcada// DEVKIT:. - Pronto — app puro, zero resíduo.
Entregas desta primeira leva (priorizadas)
Pra não fazer tudo de uma vez, proponho entregar nesta ordem, validando cada etapa antes da próxima:
Fase 1 (essencial — destrava você hoje):
- DevKitFlag + SimXRSession + FakeControllers + DevPanel (aba Inputs + Logs)
Fase 2 (essencial — instrumenta o testador):
- XRDevHud expandido + DevPanel aba Cena/XR + Exportar relatório
Fase 3 (qualidade de vida):
- SmokeTest + RecordSession
Posso entregar a Fase 1 inteira agora numa única leva, e as fases 2 e 3 sob demanda quando você validar que a 1 te serve. Cabe?
Detalhes técnicos
- Sem novas dependências. Tudo com Three.js, R3F, Zustand já presentes.
- TypeScript rigoroso. Tipos compartilhados entre real e fake (mesma interface
ControllerGrabSnapshot). - Zero impacto em produção: sem flag, bundle do DevKit nem é importado se usarmos
React.lazy()na entrada. - Hot-swappable: ligar/desligar o DevKit não recarrega a página (estado da cena preservado).