1 Dispositivos, rastreamento e graus de liberdade — Resumo

Versão de revisão. As cinco definições deste módulo estão aqui inteiras, e as ressalvas também — elas são o que se erra quando se revisa às pressas. O que encolheu foi o número de exemplos. O tratamento longo está na versão completa deste capítulo e no capítulo correspondente do livro.

Alguém põe um visor no rosto pela primeira vez, olha em volta e sorri. O mundo desenhado gira com a cabeça, na direção certa e na hora certa. Então essa pessoa dá um passo à frente, e o mundo fica onde estava.

Guarde esse passo. Ele volta no fim, com a conta feita.

Em segundos vem o desconforto; em minutos, algo pior. Quem monta a demonstração aprende a contornar o assunto — pede que a pessoa fique parada, sugere que sente — e trata o sintoma como fragilidade de quem usa. É uma conta faltando. Aquele aparelho media três coisas sobre a cabeça e ignorava outras três: as medidas dizem para onde a cabeça aponta, e as ignoradas diriam onde ela está.

1.1 O corpo percebe antes de você nomear

O mal-estar tem causa geométrica, e ela se explica sem uma palavra de fisiologia avançada.

Dentro de cada ouvido interno há estruturas que medem movimento. Uma parte responde a rotação; outra, a aceleração linear. Os dois sinais chegam ao cérebro junto com o que os olhos veem, e a expectativa de coerência entre eles é permanente. Quando a pessoa virou a cabeça, tudo bateu. Quando ela deu o passo, o ouvido relatou deslocamento e os olhos relataram uma cena imóvel — que é o que se vê quando o corpo está parado.

flowchart TD
    A["a pessoa dá um passo<br/>à frente"] --> B["ouvido interno relata<br/>DESLOCAMENTO"]
    A --> C["sistema mede só<br/>a orientação"]
    C --> D["a cena desenhada<br/>fica onde estava"]
    D --> E["olhos relatam<br/>CORPO PARADO"]
    B --> F{"dois relatos<br/>incompatíveis"}
    E --> F
    F --> G["mal-estar"]
Figura 1: O desacordo entre o que o corpo relata e o que os olhos mostram, quando metade da pose não é medida.

Duas informações que não podem ser ambas verdadeiras, e nenhum critério para descartar uma. O desconforto não depende de a cena ser feia nem de o visor ser barato: um aparelho caro com a mesma lacuna produz o mesmo efeito, em melhor resolução. E daí sai a correção que contraria o instinto — sem saber para onde a pessoa se deslocou, o certo é não mover a cena. Uma cena movida por suposição erra em direção e em quantidade, e acrescenta um terceiro relato ao desacordo que já havia entre dois.

Separe dois casos que a conversa comum mistura. Um sistema pode não saber onde a pessoa está, e um sistema pode saber com atraso. O segundo é mais traiçoeiro porque tudo parece funcionar: quem usa diz apenas que “está um pouco estranho”, sem conseguir nomear o defeito, já que nada do que ele vê está no lugar errado. Está no tempo errado. Atraso melhora por graus, com menos trabalho por quadro; ausência de medida não melhora por graus, porque é uma metade da pose que ninguém estima.

1.2 Seis números, e três deles medidos

A briga entre visores caros e baratos cabe numa contagem de parâmetros independentes.

Um livro sobre a mesa precisa de três números para ter uma quina localizada, e de mais três para dizer para que lado ele aponta. Nenhum dos seis se deduz dos outros.

NotaDefinição — Pose e graus de liberdade

A pose de um corpo rígido é o par formado pela sua posição e pela sua orientação. Cada metade tem três parâmetros independentes, e cada parâmetro independente é um grau de liberdade.

Um sistema que estima só a orientação rastreia três graus de liberdade; um que estima as duas metades rastreia seis. A distinção é de quantos parâmetros o sistema mede, e não de quantos o corpo tem: o corpo tem sempre seis.

flowchart LR
    P["pose de um<br/>corpo rígido"] --> R["orientação<br/>3 parâmetros"]
    P --> T["posição<br/>3 parâmetros"]
    R --> S3["sistema de TRÊS graus<br/>estima só a orientação"]
    R --> S6["sistema de SEIS graus<br/>estima as duas metades"]
    T --> S6
    S3 -.-> N["andar é invisível:<br/>a cena não se move"]
    S6 -.-> M["andar move a cena<br/>na direção e na medida certas"]
Figura 2: As duas metades da pose, e o que cada sistema de medida deixa de ver.

A definição não diz nada sobre precisão, frequência ou método — um sistema de seis graus pode estimar mal as duas metades e continuar sendo de seis. E “visor de três graus de liberdade” é frase sobre o sistema de medida, embora o uso comum a trate como frase sobre o aparelho. O objeto tem os mesmos seis de sempre; o que fica menor é a descrição que o sistema produz dele.

Um sistema de três graus não está quebrado. Veja o caso da fotografia esférica: ela não ganha nada com rastreamento de posição, porque a imagem está no infinito. O problema aparece quando a cena tem objetos a distâncias finitas. Aproximar-se de uma bancada a um metro deveria aumentar o tamanho aparente dela, e o corpo espera isso com a precisão de quem acerta a mão numa maçaneta no escuro. A saída honesta admite o limite — objetos distantes, interação por direção do olhar, nenhuma promessa de escala corporal. A desonesta constrói como se a posição existisse e chama de “limitação do hardware” o enjoo que se segue.

Agora a parte incômoda: a plataforma não informa quantos graus o aparelho rastreia. Não há propriedade a ler. A camada que responde não sabe o que o sensor faz, sabe o que o sistema do aparelho aceitou entregar. O que sobra é inferir a partir dos espaços de referência concedidos. Um espaço ancorado no chão exige que o aparelho saiba onde o chão está, e um aparelho que só gira não sustenta essa relação enquanto a pessoa caminha.

a inferência sem aposta, em devices/graus.ts
export function grausDeLiberdade(leitura: LeituraDeEspacos): GrausDeLiberdade {
  const temChao: boolean =
    leitura.concedidos.includes('local-floor') ||
    leitura.concedidos.includes('bounded-floor') ||
    leitura.concedidos.includes('unbounded');
  if (temChao) {
    return 'seis';
  }
  if (leitura.concedidos.length === 1 && leitura.concedidos[0] === 'viewer') {
    return 'tres';
  }
  return 'indeterminado';
}

A linha que decide tudo é a última: existe um terceiro valor, indeterminado, para o caso em que a evidência não fecha. Devolver só tres ou seis obrigaria a escolher um lado no caso ambíguo, e escolher ali é apostar. A regra da inferência está escrita por extenso no próprio arquivo, porque inferência sem premissa exposta não pode ser contestada.

a regra por extenso, em devices/graus.ts
/**
 * Regra da inferência, escrita por extenso porque é ela que você precisa
 * poder contestar:
 *
 * - `local-floor` ou `bounded-floor` concedidos exigem que o aparelho saiba onde
 *   está o chão em relação a quem observa. Um visor que só gira não tem como
 *   sustentar isso, então a concessão é evidência forte de posição rastreada.
 * - `viewer` sozinho é o mínimo que qualquer sessão entrega: a origem acompanha
 *   quem observa, e translação alguma é observável a partir dela. Evidência forte
 *   da ausência.
 * - `local` no meio do caminho é ambíguo de verdade. A especificação o descreve
 *   como origem próxima de quem observa no início da sessão, e um aparelho de três
 *   graus pode concedê-lo mantendo a posição sempre na origem. Daí
 *   `indeterminado`, e não uma aposta.
 */

Guarde o limite dessa inferência. Ela lê concessões da plataforma, e concessão é decisão tomada por razões que podem não ter nada a ver com o sensor. Uma plataforma que concedesse o espaço ancorado no chão a um aparelho de três graus faria a inferência devolver seis. Por isso a função devolve uma leitura, e não um veredito.

1.3 Duas maneiras de saber onde se está

Posição é sempre posição em relação a alguma coisa, e alguém tem de decidir onde essa coisa mora.

NotaDefinição — Arranjo de rastreamento

Um arranjo de rastreamento é a disposição física do que mede a pose, e admite dois casos. No arranjo por infraestrutura externa, o que mede está fixo no ambiente e o corpo rastreado é observado de fora. No arranjo por sensores embarcados, o que mede viaja com o corpo, e a pose é estimada a partir do que esses sensores observam do ambiente.

A classificação é pela posição do que mede. Ela não diz nada sobre precisão, custo ou geração do equipamento.

Essa última frase impede o mal-entendido mais comum: existem arranjos externos imprecisos e embarcados excelentes, e a ordem entre dois equipamentos é pergunta sobre produtos.

flowchart TB
    Q["onde está o que mede<br/>a pose?"] --> E["INFRAESTRUTURA EXTERNA<br/>fixo no ambiente,<br/>observa o corpo de fora"]
    Q --> I["SENSORES EMBARCADOS<br/>viajam com o corpo,<br/>observam o ambiente"]
    E --> E1["funciona só no<br/>espaço preparado"]
    E --> E2["falha por oclusão:<br/>algo entre instrumento e corpo"]
    E --> E3["a região ruim é da SALA<br/>e fica onde está"]
    I --> I1["funciona em qualquer<br/>ambiente que ofereça<br/>o que observar"]
    I --> I2["falha por ambiente<br/>pobre em referências"]
    I --> I3["a região ruim ANDA<br/>junto com a pessoa"]
Figura 3: Os dois arranjos, e as três consequências que decorrem de onde está o instrumento.

O ancestral do primeiro arranjo é de 1968. O visor que Ivan Sutherland montou naquele ano ficava suspenso do teto do laboratório por um braço mecânico articulado, e o braço media a posição da cabeça, lendo os ângulos das próprias juntas. Geometria rígida conhecida no lugar do sensor que estima, com a precisão paga em imobilidade — o alcance do movimento era o alcance do braço. O braço não foi adotado por ser a melhor forma concebível de medir uma cabeça: ele já estava lá segurando o peso, e ler os ângulos era a informação mais barata disponível. O apelido “espada de Dâmocles” veio depois, dado por outras pessoas.

A diferença que mais muda o projeto está no modo de falhar. Num arranjo externo, a região problemática é da sala: descoberta uma vez, continua no mesmo lugar amanhã. Num arranjo embarcado, ela viaja com a pessoa. Com instalação fixa você testa a sala e afirma que o sistema funciona nela; sem instalação, cada sala é um caso novo, e o que se pode afirmar é como o ambiente se comporta diante da degradação.

E é o arranjo embarcado que sustenta um ambiente aberto por uma URL em três aparelhos diferentes. Em troca, ele transfere ao aparelho a tarefa de descobrir onde está. O aparelho desenha a planta da sala enquanto atravessa a sala, e corrige o desenho toda vez que reconhece um canto por onde já passou.

NotaDefinição — Localização e mapeamento simultâneos

Dado um corpo que se desloca por um ambiente desconhecido, o problema de localização e mapeamento simultâneos consiste em estimar, ao mesmo tempo, a trajetória do corpo e um mapa do ambiente, a partir apenas das observações feitas pelos sensores que viajam com ele.

As duas estimativas são mutuamente dependentes, e ambas são revisáveis — uma observação nova pode alterar retroativamente o que já se julgava conhecido.

flowchart LR
    subgraph CIRC["o círculo, desfeito pela simultaneidade"]
        POS["posição estimada<br/>melhor aposta atual"] --> MAP["mapa estimado<br/>melhor aposta atual"]
        MAP --> POS
    end
    OBS["observação nova<br/>do sensor"] --> CIRC
    CIRC --> REC{"reconhece um lugar<br/>por onde já passou?"}
    REC -->|"não"| ACU["o erro pequeno<br/>continua acumulando"]
    REC -->|"sim, e é o lugar certo"| COR["correção RETROATIVA:<br/>mapa e trajetória revistos"]
    REC -->|"sim, mas é lugar errado"| DOB["o mapa dobra<br/>sobre si mesmo"]
Figura 4: O ciclo entre posição e mapa, e os três desfechos possíveis de uma tentativa de reconhecimento.

O círculo é real: para saber onde está, o aparelho precisa do mapa; para desenhar o mapa, precisa saber onde está. A saída abandona a ordem e faz as duas coisas ao mesmo tempo, com as duas produzindo estimativas. Reconhecer um lugar, porém, custa caro — comparar a vista atual contra tudo o que já foi visto cresce com o percurso, e o resultado precisa sair dentro de um quadro. Guarda-se, então, uma descrição compacta de cada lugar e verifica-se em detalhe só os candidatos que sobrevivem ao filtro barato. Disso decorre algo que ninguém adivinharia: reconhecer é mais provável quando se olha o lugar do mesmo ângulo de antes.

Repare que os dois erros possíveis têm custos muito diferentes. Deixar de reconhecer custa uma oportunidade de correção; reconhecer um lugar onde nunca se esteve dobra o mapa sobre si mesmo, e o estrago vale retroativamente. Por isso esses algoritmos exigem evidência forte antes de aceitar um reencontro, e quem os observa de fora chama de lentidão o que é cuidado com preço.

Antes de seguir. Se a posição informada pode ser corrigida retroativamente, o que acontece com um objeto virtual cujas coordenadas você anotou dez minutos atrás? Responda antes de ler o parágrafo seguinte.

A posição informada é estimativa sujeita a revisão, e não medida de régua: duas leituras no mesmo lugar físico podem divergir sem que nenhuma esteja errada, porque entre elas o mapa foi corrigido. Daí a resposta sobre prender um objeto ao mundo. Anotar coordenadas funciona por alguns minutos e escorrega, porque as coordenadas envelhecem quando o mapa que as define é corrigido embaixo delas. Ancorar consiste em pedir ao aparelho que mantenha o objeto preso a um ponto do mapa e corrija as coordenadas sozinho.

Duas ressalvas fecham o assunto. A correção melhora a coerência do espaço já mapeado, e não a precisão do próximo passo. E a plataforma não entrega o mapa: não há nuvem de pontos, contagem de pontos nem aviso de correção. Chegam quatro efeitos — a pose a cada quadro, o raio lançado contra superfície real, os planos reconhecidos e a âncora. Um ambiente correto tolera correções que nunca vê chegar.

1.4 A sala limpa é a pior sala

Um aparelho que se orienta por cantos precisa de cantos. São três as condições que o deixam sem eles.

A primeira é a superfície sem textura: uma parede lisa, sem quadro, sem tomada e sem rodapé no campo da câmera não oferece ponto distinguível dos vizinhos. A segunda é a iluminação pobre, e aqui o problema é o contraste — mesmo com textura, a câmera precisa distinguir claros e escuros para extrair um canto. A terceira é o movimento brusco: um giro rápido borra a imagem, e um canto borrado deixa de ser um canto justamente nos quadros em que a continuidade era mais necessária.

As três juntas descrevem uma sala recém-pintada de branco, bem iluminada por luz difusa — que qualquer pessoa chamaria de limpa e adequada, e que para o aparelho é uma sala sem informação. Luz abundante não compensa nada: ela ilumina bem uma superfície que não tem o que mostrar.

flowchart TD
    T["superfície sem textura"] --> SC["nenhum canto<br/>a reconhecer"]
    L["iluminação pobre"] --> SC
    M["movimento brusco"] --> SC
    SC --> QSP["o quadro chega<br/>e a pose não vem"]
    MEN["menu do sistema aberto:<br/>a sessão saiu de foco"] --> QSP
    QSP --> C{"a sessão estava<br/>visível naquele quadro?"}
    C -->|"sim"| DEG["conta como<br/>degradação de rastreamento"]
    C -->|"não"| NOR["comportamento normal<br/>do sistema, não conta"]
Figura 5: As três causas, o sintoma único que chega ao código, e o caso que precisa ser separado dele.

As três têm relação diferente com o tempo. Falta de textura é permanente enquanto ninguém pregar um cartaz na parede. Luz fraca é intermitente e obedece ao relógio, o que produz o relato irreprodutível de que “às vezes trava”. Movimento brusco é a única que depende de quem usa, e por isso a única sobre a qual a interface tem alavanca. Repare: um ambiente que põe o objeto de interesse atrás de quem observa está pedindo o giro que degrada o rastreamento.

Do lado de quem programa, a plataforma oferece um único indício: o quadro chega e a pose não vem. Um quadro assim, isolado, é normal; uma sequência deles é a degradação acontecendo, e a diferença entre as duas coisas é contagem que o programa faz sozinho.

a distinção que salva o diagnóstico, em devices/estabilidade.ts
/**
 * Acumula a contagem quadro a quadro.
 *
 * O parâmetro `visivel` é o que separa perda de rastreamento de sessão que saiu
 * de foco. Quando quem usa abre o menu do sistema do visor, a sessão continua
 * viva, os quadros continuam chegando e a pose deixa de vir — e contar isso como
 * falha de sensor acusaria o aparelho de um defeito que é comportamento normal
 * do sistema operacional.
 */
export class ContadorDeEstabilidade {
  private quadros: number = 0;
  private quadrosSemPose: number = 0;
  private quadrosOcultos: number = 0;
  private maiorLacuna: number = 0;
  private lacunaCorrente: number = 0;

  public registrar(temPose: boolean, visivel: boolean): void {

O segundo parâmetro impede um diagnóstico falso. Quando alguém abre o menu do sistema do visor para ver a hora, a sessão continua viva, os quadros continuam chegando e a pose deixa de vir. Sintoma idêntico, causa que é comportamento normal do sistema operacional — e um contador que ignorasse a diferença reprovaria o aparelho toda vez que alguém consultasse o relógio.

O contador conta e não julga: a interpretação mora numa função separada. Um medidor que interpreta embute a expectativa de quem o escreveu, e passa a concordar sempre com essa pessoa. Mantendo a contagem burra, o número pode ser usado como argumento contra quem o produziu. A frase de diagnóstico, do outro lado, também se recusa a apontar qual das três causas ocorreu — daqui não se distingue textura de luz e de movimento, e escolher uma seria inventar o diagnóstico junto com a medida.

1.5 O que se pergunta a um aparelho

Quantas classes de aparelho existem? Três perguntas feitas em tempo de execução dispensam a resposta.

NotaDefinição — Capacidade declarada

Uma capacidade declarada é uma propriedade que a plataforma responde quando interrogada sobre o aparelho, e não uma propriedade do aparelho. São três as famílias interrogáveis: os tipos de sessão suportados, os recursos opcionais concedidos a uma sessão aberta e as fontes de entrada que a sessão apresenta.

A resposta pertence à camada que responde. Um aparelho pode ter um sensor cuja capacidade correspondente a plataforma não declara, e o programa não tem como usar o que não foi declarado.

flowchart TB
    F["fora de qualquer sessão"] --> P1["que tipos de sessão<br/>este aparelho aceita abrir?"]
    P1 --> R1["sim / não / não sei"]
    G["gesto de quem usa<br/>abre a sessão"] --> D["dentro da sessão"]
    D --> P2["que recursos opcionais<br/>foram concedidos?"]
    D --> P3["que fontes de entrada<br/>a sessão apresenta?"]
    P2 --> R2["concedido / negado / indeterminado"]
    P3 --> R3["tem raio? tem pose própria?"]
    F -.->|"perguntar aqui o que<br/>só existe lá produz suposição"| D
Figura 6: O que se pode perguntar de fora da sessão, o que só existe dentro dela, e a resposta de cada família.

Um celular com câmera e sensores, aberto num navegador que não implementa a interface de sessões imersivas, tem tudo o que seria necessário e declara nada. Para o programa, a capacidade não existe. A tentação é completar a declaração por dedução — este visor é da geração tal, logo deve ter aquilo —, que é a origem de uma família de defeitos que só aparecem no aparelho de outra pessoa.

Da terceira família, duas propriedades decidem quase tudo: se a fonte tem raio, isto é, direção de apontamento, e se ela tem pose própria, isto é, se é rastreada no espaço. Um dedo na tela tem a primeira e não a segunda; um controle empunhado tem as duas; um mouse não tem nenhuma. A lista muda durante o uso — um controle ligado no meio da sessão aparece nela.

A consulta sobre tipos de sessão parece binária, e bastaria um valor lógico. Bastaria, se ela sempre respondesse.

a resposta que admite não saber, em modes/verificacao.ts
/**
 * `desconhecido` não é sinônimo de `nao`. O navegador sem a API XR não está
 * dizendo que o aparelho não serve — está dizendo que não sabe responder, e
 * tratar as duas coisas como a mesma é o erro que faz um relatório honesto
 * virar um relatório confiante e errado.
 */
export type Suporte = 'sim' | 'nao' | 'desconhecido';

Uma linha de tipo decide o comportamento de um relatório inteiro. O terceiro valor obriga todo consumidor a tratar o caso em que não se sabe, e o verificador reclama de quem esquecer. Um relatório que diz não suporta onde deveria dizer não sei afirma, sobre o aparelho de quem lê, um fato errado.

Duas restrições da plataforma decidem a forma de qualquer sonda. Metade das respostas só existe dentro da sessão — recursos concedidos, composição do fundo, espaços de referência e fontes de entrada são propriedades da sessão, e a consulta externa devolve suposição bem formatada. E abrir sessão imersiva exige gesto de quem usa: o pedido que não vem de um clique é recusado, e a recusa chega como exceção com nome em inglês. Some-se o terceiro obstáculo, que derruba mais demonstrações que os dois: sessão imersiva exige contexto seguro, e o certificado autoassinado do servidor de desenvolvimento produz um aviso que precisa ser aceito em cada aparelho, uma vez. Antes disso o botão não reage, e o sintoma não diz por quê.

1.6 Concedido, negado, e o que ninguém respondeu

Uma sessão aberta com pedido de recursos opcionais devolve a lista do que foi habilitado. O que fazer com o que ficou de fora dela?

NotaDefinição — Estado de um recurso opcional

O que se sabe sobre um recurso opcional, depois de a sessão abrir, assume exatamente um de três valores. Concedido: a sessão reportou a lista dos recursos habilitados e o nome está nela. Negado: a sessão reportou a lista e o nome não está nela. Indeterminado: a sessão não reportou lista alguma.

O terceiro valor é ausência de resposta, e não resposta negativa. Confundi-los produz um relatório que afirma, com a mesma sintaxe das outras linhas, um fato que ninguém verificou.

flowchart TD
    A["a sessão abriu"] --> B{"ela reportou a lista<br/>de recursos habilitados?"}
    B -->|"não reportou"| I["INDETERMINADO<br/>ausência de resposta"]
    B -->|"reportou"| C{"o nome do recurso<br/>está na lista?"}
    C -->|"sim"| G["CONCEDIDO<br/>pode ser usado"]
    C -->|"não"| N["NEGADO<br/>recusado, e sem razão exposta"]
    I -.->|"o atalho que estraga tudo"| N
Figura 7: Os três estados possíveis de um recurso opcional, e o atalho que destrói a distinção.
os três estados, em devices/recursos.ts
/**
 * O que se sabe sobre um recurso depois de a sessão abrir.
 *
 * - `concedido`: o nome está em `enabledFeatures`, e o recurso pode ser usado.
 * - `negado`: a sessão reportou a lista e o nome não está nela — o aparelho ou o
 *   navegador recusou, e a razão não é exposta.
 * - `indeterminado`: a sessão não reportou lista alguma. Não é negativa; é
 *   ausência de resposta, e tratá-la como negativa produz relatório confiante e
 *   errado.
 */
export type EstadoDeRecurso = 'concedido' | 'negado' | 'indeterminado';

O mesmo endereço aberto em dois navegadores mostra a diferença. Num deles a lista vem e três recursos aparecem como negados; no outro a lista não vem, e os mesmos três aparecem como indeterminados. Perceba que as duas telas se parecem e afirmam coisas diferentes. E a razão da negativa nunca é exposta pela plataforma — um programa que a registrasse estaria inventando.

O padrão geral extrapola o assunto: sempre que um valor lógico registra o resultado de uma consulta que pode não responder, a ignorância vira negativa em silêncio. O sintoma tem assinatura reconhecível — o sistema fica mais confiante quanto menos informação recebe. E a distinção só sobrevive se os três estados forem carregados juntos até o ponto de decisão; qualquer camada intermediária que simplifique para dois destrói a informação sem erro de compilação.

Pedir um recurso exige o nome exato da especificação, sem tradução e sem tolerância a erro de digitação — escrever errado produz um pedido que não é atendido, sem mensagem. Daí o catálogo, e o campo que importa nele é o segundo.

o catálogo com motivo, em devices/recursos.ts
/** Um recurso opcional da API XR, com o motivo de ele estar no catálogo. */
export interface RecursoOpcional {
  /** O nome exato aceito por `optionalFeatures` — não traduzir. */
  readonly nome: string;
  /** O que ele habilita no percurso, em uma frase. */
  readonly paraQueServe: string;
}

Cada entrada carrega o motivo de estar ali, em uma frase. O campo é opcional para a máquina e é o que impede a lista de crescer sozinha: cada recurso pedido é uma coisa a mais que a sessão pode negar e um caso a mais a tratar. E a lista precisa estar decidida antes de a sessão existir — não dá para abrir, olhar em volta e pedir mais coisas depois.

Neste ponto do percurso, a Bancada ainda não desenha nada. O que ela ganhou foi a capacidade de perguntar, com o relatório escrito onde alguém consiga lê-lo com o aparelho no rosto. Note que não existe console de depuração dentro de um visor: erro registrado ali é indistinguível de um programa que decidiu não fazer nada. A linha mais valiosa desse relatório é a que compara a composição do fundo declarada no marco anterior com a que a sessão informou. Quando os dois valores não batem, a frase diz qual dos dois estava errado, e não é o aparelho.

Volte ao passo do começo. O sistema estimava a orientação e ignorava a posição, o ouvido interno relatou uma translação que os olhos não confirmaram, e o mal-estar veio do desacordo. Cada peça daquela cena tem nome agora, e nenhuma delas foi decidida por quem escreve o ambiente — todas chegam prontas, do outro lado de uma interface. A única alavanca disponível é perguntar antes de supor, que é exatamente o que um primeiro artefato sem um único polígono já consegue fazer.