O Whoop que uso todos os dias tem um acelerômetro e um giroscópio que medem 100 vezes por segundo. O app oficial usa isso para passos, sono e esforço. Eu queria saber se dava para algo mais divertido: um jogo de bateria estilo Guitar Hero, com uma pulseira em cada mão. O Whoop na esquerda, um Apple Watch na direita, as notas descendo pela pista e você batendo no ar no tempo certo.
Funciona. E o mais interessante não foi o jogo, mas o problema que precisei resolver para ele funcionar.
Como é montado
Uma pequena ponte em Python se conecta ao Whoop por Bluetooth, liga o sensor de movimento, detecta as batidas e as distribui por WebSocket. O jogo roda no navegador: Three.js servido como módulos ES, sem build, e a bateria é um sintetizador com Web Audio, sem samples. O Apple Watch manda seu movimento para a mesma ponte por Wi-Fi, e o teclado também joga, para testar sem pulseiras.
Detectar uma batida é a parte mais simples. Em repouso a aceleração é 1 g, a gravidade. Uma batida é um pico acima de 2,5 g, seguido de 300 ms de pausa para não contar o rebote duas vezes. Nada de machine learning.
O problema: o Whoop chega atrasado
A primeira coisa que fiz foi medir o atraso. O Whoop mede a 100 Hz, mas não envia cada amostra: junta um segundo inteiro e manda em um pacote. Então cada batida chega ao Mac entre 0,5 e 1 segundo depois de acontecer.
Num jogo de ritmo isso é uma eternidade. A janela de um Perfeito é de 70 ms.
Parecia o fim do projeto, até eu olhar o que cada pacote trazia: cada amostra vem com a hora exata em que foi medida. Então o jogo não avalia a batida pela hora em que ela chegou, mas pela hora em que ela aconteceu. Uma batida que chega 900 ms atrasada, mas que você deu no tempo certo, é um Perfeito.
Mais dois detalhes fazem o atraso não ser sentido. A música é tocada pelo jogo, não pela sua batida, então a música nunca sai do tempo. E uma nota só é dada como perdida depois do tempo máximo que aquela pulseira pode levar para entregar a batida. Senão o jogo diria "erro" e mudaria de ideia um segundo depois.
O segundo problema: o feedback também atrasa
Um placar correto não basta. Se você bate e o tambor acende um segundo depois, parece quebrado mesmo com o número final certo.
A solução é um pequeno truque. Se você vem acertando as notas da mão lenta, o jogo assume que você vai acertar a próxima e a faz explodir no momento exato. Quando a batida real chega, ela só confirma a nota ou a transforma em erro. Na pista lenta, a batida guia também soa mais alta e substitui o som da sua própria batida. É o que os jogos online fazem com a latência de rede: prever e depois corrigir.
Calibrar em vez de adivinhar
Cada dispositivo tem seu próprio atraso, e o relógio dele pode estar um pouco defasado em relação ao do Mac. Em vez de modelar tudo isso, há uma tela de Calibrar: oito cliques, um a cada dois segundos, e você bate com cada mão. O jogo pega a mediana da diferença entre suas batidas e os cliques, e essa é a correção daquele dispositivo. Um único número absorve o atraso do sensor, a defasagem do relógio e até o seu jeito de bater.
Os cliques são lentos de propósito. Com uma defasagem de relógio grande, um ritmo rápido emparelharia cada batida com o clique errado.
O que aprendi
Antes de descartar uma ideia por latência, veja se os dados trazem a hora. O atraso do Whoop parecia fatal. Não era, porque o que importa num jogo de ritmo não é quando você fica sabendo da batida, mas quando ela aconteceu. Medir primeiro mudou todo o design.
A latência decide quais jogos você pode fazer. A mesma técnica serve para ritmo e para nada em tempo real: mirar ou desviar com a mão do Whoop é impossível. Por isso a lista de jogos é bateria, boxe no ritmo da música e um de carregar energia com a respiração. Nenhum jogo de reflexo.
Acertar o número não basta; tem que parecer certo. O placar estava certo desde o primeiro dia. O que faltava era feedback imediato, e isso veio da previsão, não de mais precisão.
O hardware real sempre corrige o README. Várias coisas só apareceram com a pulseira na mão:
- O Whoop só entra em modo de pareamento fora do pulso: tire, espere as luzes apagarem e toque firme com dois dedos até piscar em azul.
- Ele pareia com um dispositivo por vez, então o Bluetooth do celular precisa estar desligado.
- O sensor de movimento leva uns 10 segundos para começar a mandar dados. Meu primeiro aviso de "nada está chegando" disparava cedo demais.
- Se a pulseira recusa o pareamento, tentar sem parar só gasta a bateria. A ponte agora desiste depois de três recusas.
- Quando a conexão funciona, a pulseira vibra. Essa vibração acabou sendo um sinal de "funciona" melhor do que qualquer linha de log.
Às vezes o caminho sem código é o melhor. Para o Apple Watch fiz um app nativo para o Watch e o iPhone. Com uma conta gratuita da Apple, o Xcode nunca encontrou meu relógio, que tinha ficado no watchOS 26 ao lado de um iPhone com iOS 27. A saída foi o Sensor Logger, um app gratuito da App Store que envia o movimento do Watch por HTTP. A ponte recebe, detecta as batidas e pronto, sem Xcode. Os dados chegam até 2 segundos atrasados, mas a mesma técnica da hora real resolve.
Leia a licença do que você usa como referência. O protocolo Bluetooth do Whoop não é público. Eu o implementei a partir da documentação do projeto open source noop. O código é meu, mas a licença do noop é não comercial, e deixei isso anotado no projeto antes de pensar em publicar qualquer coisa.
O que vem depois
Boxe, com combos no ritmo da música. A força do soco vai importar menos do que eu esperava, porque o acelerômetro do Whoop satura perto de 8 g e todos os socos fortes medem parecido. E Ki: carregar energia com a respiração e os batimentos, que o Whoop também transmite ao vivo, e lançá-la com as duas mãos.
Projeto independente, sem relação com a WHOOP, Inc. nem com a Apple. Use apenas com dispositivos seus.