OhMyGame
OhMyGame is the open-source studio for making games with AI. Design, build, playtest, and publish games in one app, with your own model keys.
Crie uma sala, mande o link e jogue com até 8 pessoas. Sem cadastro.
Translation pending
GamesJavaScript · CSSGitHub @flashfabsOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Salinha: jogos com a galera por link, sem cadastro, ligados por WebRTC. Primeiro jogo: Pavio, arena de bombas para até 8 pessoas.
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Site público para jogar com a galera direto no navegador, sem cadastro: alguém cria uma sala, manda o link e quem abre o link cai direto na sala. Pedido do Victor em 27/10/2026 (áudio): sala por link, conexão em tempo real por WebRTC, base para vários jogos, primeiro jogo de bombas para até 8 pessoas com WASD/setas e espaço.
O primeiro jogo é o Pavio, uma arena de bombas original (nome, personagens e visual próprios): explodir caixas, pegar itens e ser o último de pé. A morte súbita começa mais cedo a cada partida da rodada (de 2 minutos no Pátio a 90 s na Fornalha) e fecha a arena de fora para dentro.
Fluxo de uma sala (pedidos do Victor de 27/10/2026):
site/js/sala.js é a camada de sala, comum a todos os jogos: conexões WebRTC (canais de dados) por meio do PeerJS, em estrela em volta de quem criou a sala (o anfitrião). O código da sala (5 letras) é o id do anfitrião no servidor de sinalização; o link é https://<site>/#CODIGO. A sala cuida de entrada e saída, lista de membros, ping e queda; o jogo só troca as próprias mensagens.0.peerjs.com), usado só para os navegadores se acharem; os dados do jogo vão direto entre os navegadores.site/js/rede.js pede credenciais de 24 h à Netlify Function netlify/functions/ice.mjs (/api/ice), e a chave do TURN fica só nas variáveis de ambiente da Netlify. Se a função faltar ou falhar, vale a configuração embutida do PeerJS 1.5.4, a mesma de antes (STUN do Google e TURN do próprio PeerJS). Esse TURN do PeerJS (eu-0 e us-0.turn.peerjs.com) não responde: os nomes não tinham DNS em 27 e 28/10/2026, então sem a chave da Cloudflare quem está em rede fechada continua sem conseguir entrar, como antes.?rede=peerjs volta à configuração embutida do PeerJS (a de antes) e ?rede=retransmissor força todas as ligações pelo TURN.site/js/pavio/robo.js é a IA dos robôs, que só existem no anfitrião: a cada passo da simulação cada robô lê a partida e devolve a mesma entrada de uma pessoa ({ d, d2 } e bomba). Ela calcula um mapa de perigo (quando cada célula vai pegar fogo, com reação em cadeia e morte súbita) e uma rota de fuga com tempo, e nunca solta bomba sem ter para onde correr. Bomba de detonador alheia conta como podendo explodir a qualquer momento, bomba congelada espera o gelo passar e bomba chutada pode parar em qualquer casa do caminho; com o detonador e uma bomba só, o robô solta, foge e detona de um lugar seguro, e por isso deixa de buscar bombas extras; sem saída e com gelo, congela a bomba que o mataria e foge; chute e atalho ele não usa (nunca anda contra bomba ou caixa). Quando a morte súbita começa, todos os níveis vão atrás dos outros, para a partida não acabar empatada com todo mundo esmagado. O fácil reage devagar, vagueia e só quebra caixas; o médio caça os outros; o difícil reage rápido, prefere fugas longe dos adversários e procura encurralar quem está perto.site/js/pavio/regras.js é a simulação pura (sem DOM nem rede). O anfitrião roda a 60 passos por segundo e manda um retrato 20 vezes por segundo, com a grade só quando ela muda e eventos repetidos em 3 retratos seguidos.O site é estático, sem build. Para abrir localmente (abrir duas abas, criar a sala numa e colar o link na outra):
python3 -m http.server 8792 --directory site
Os testes automáticos estão na seção Testes.
Três comandos, todos rodando na raiz do repositório:
npm test: testes das regras do jogo (testes/*.test.mjs, Node 22, sem dependências, menos de 1 s).npm run e2e: testes de ponta a ponta (testes/e2e/*.spec.mjs) com Playwright e Chromium sem janela; cada jogador é um navegador de verdade na sua própria página. Roda os cenários funcionais dois de cada vez (SALINHA_PROCESSOS muda isso) e depois o de desempenho sozinho, para os números não sofrerem com as outras páginas; tudo leva cerca de 3 min.npm run fumaca: teste de fumaça contra a produção (testes/e2e/producao.fumaca.mjs, cerca de 15 s): espera /versao.json mostrar o commit da main (ou COMMIT=<commit>), confere que /api/ice responde (503 enquanto a chave do TURN não existir), que /api/ranking responde, que /api/perfil recusa leitura sem credencial (401) e escrita de outro site (403), sem nunca gravar perfil, e joga o começo de uma rodada com dois jogadores no site publicado. SALINHA_URL=<endereço> aponta para outro lugar, como uma prévia da Netlify.Para publicar, scripts/preparar-publicacao.sh <pasta> monta uma pasta nova a partir da main (só netlify.toml, site/ e netlify/, com site/versao.json contendo commit e hora, e as dependencies das funções instaladas quando houver) e imprime o caminho dela; recusa quando a main local está atrás da origin/main. O passo a passo está no AGENTS.md.
Na primeira vez numa máquina nova, instalar as dependências e o Chromium do Playwright:
npm install
npx playwright install chromium
No GitHub, o Action .github/workflows/testes.yml roda npm test e os testes de ponta a ponta funcionais em cada pull request e em cada push na main, sem publicar nada. Os de desempenho ficam de fora: medem a GPU do Mac pelo Metal, e o servidor do GitHub não tem GPU.
Como funcionam os de ponta a ponta:
127.0.0.1 escolhida a cada execução (python3 -m http.server; SALINHA_PORTA=<porta> fixa uma) e o derruba no fim, então várias worktrees podem rodar a suíte ao mesmo tempo.0.peerjs.com), igual à produção, então os testes precisam de internet; a fonte e o PeerJS também vêm de CDN. Por isso há 1 nova tentativa automática por teste: um teste que só passa na segunda aparece como flaky no relatório, o que aponta rede instável e não defeito do jogo.requestAnimationFrame. Para rodar um arquivo só, npx playwright test <nome> (um teste de cada vez).window.__salinha, que site/js/app.js só instala quando o endereço tem ?teste=1 (os testes abrem /?teste=1 e o link do convite com ?teste=1). Ele só lê: __salinha.sala() devolve código, link, id e membros, e __salinha.jogo() devolve uma cópia do estado da rodada e da partida, vinda de espiar() no objeto que criarPavio devolve em site/js/pavio/pavio.js. Quem mexer no formato do estado do Pavio deve manter espiar() funcionando.Math.random puxado para [0,9, 1) (função semCaixas em testes/e2e/mesa.mjs): a arena sai sem caixas e sem itens e cada jogador nasce no canto da sua ordem de entrada (anfitrião em (1, 1), o segundo em (19, 13) e assim por diante). O teste de desempenho usa o mapa normal, com caixas e itens.andarAte em testes/e2e/mesa.mjs).test-results/ (npx playwright show-trace <arquivo>).O que cada cenário cobre:
sala.spec.mjs, entrada e largada: o anfitrião cria a sala e 4 convidados entram pelo link do convite; todos veem os 5 nomes e a coroa do anfitrião; com 4 prontos o anfitrião vê "Só falta você." e a rodada não começa; quando ele marca pronto, todos veem "Partida 1 de 5 · Pátio" e a partida começa. Um convidado anda 2 casas e o anfitrião vê a posição nova; ele solta uma bomba, que aparece para o anfitrião e para outro convidado, foge da explosão e continua vivo depois que ela estoura.sala.spec.mjs, saída no meio: anfitrião e 2 convidados em partida; um convidado clica em "Sair" e volta ao início; para os outros dois a rodada acaba com "Rodada interrompida" e o motivo " saiu da sala, então a rodada acabou.", o placar final lista os 3 e "Voltar ao lobby agora" leva todos de volta ao lobby.pontos.spec.mjs, eliminação e placar: anfitrião e convidada andam até se encontrar na linha de cima; a bomba da convidada elimina o anfitrião; a tela de resultado mostra "Íris venceu a partida! 🏆" (e passa no axe-core) (e "Você venceu a partida! 🏆" para ela), o placar com 1 vitória, 0 caixas, 1 eliminação e 20 pontos (5 + 15) para ela e tudo zero para ele, a legenda dos pontos e ⭐ 20 na lista da sala; as estatísticas da partida que chegam ao convidado batem com o que aconteceu (bomba solta, eliminação, morte do anfitrião pela bomba dela, distância andada, tempo vivo); depois do resultado, a partida 2 (Depósito) começa sozinha.toque.spec.mjs, iPad e celular: um iPad (7ª geração, deitado) e, em outro teste, um celular (Pixel 7, em pé), com toque ativo, entram na sala de um computador. Antes, numa página comum, o teste confirma que os gestos de pinça e de rolar do navegador de teste funcionam, para a checagem valer. No lobby o iPad mostra as instruções de toque e ainda não tem camada de toque, e a sala não rola nem aumenta com pinça; com a partida começando, a camada de toque e a dica 💣 aparecem (no computador, não); arrastar o dedo no lado esquerdo anda e o anfitrião vê; tocar no lado direito solta bomba; rolar e fazer pinça durante o jogo não mexem na página.jornada.spec.mjs, casos da jornada: código digitado errado e sala que não existe mais deixam a pessoa na tela inicial com uma explicação, e de lá criar sala continua funcionando; quem chega no meio de uma partida fica assistindo, fora da escalação, com aviso na tela e "assistindo" na lista, e não solta bomba. As checagens olham o que a pessoa consegue fazer, não o texto exato.acessibilidade.spec.mjs, acessibilidade: axe-core (WCAG 2.1 A e AA) na tela inicial e no lobby, no computador e no celular; problema sério ou crítico reprova.rede-ruim.spec.mjs, rede ruim: todos os canais de dados dos dois jogadores com 120 a 200 ms de atraso e 10% de perda no canal rápido; o ping aparece alto na lista, o convidado anda sem ser puxado para trás, o anfitrião vê o movimento e a bomba na casa certa, e o convidado vê o anfitrião andar.Números medidos em 27/10/2026, MacBook Pro M5 Pro, Chromium 153 sem janela, 8 jogadores: anfitrião e convidado a 60 fps (quadro p50 e p95 de 16,7 ms, pior quadro 50 ms), trabalho por quadro de 0,3 ms (p50) e 0,6 ms (p95), tique da simulação do anfitrião de 0,1 a 0,2 ms (p95), nenhuma tarefa longa.
Com a CPU 4x mais lenta, medido em 28/10/2026 na main com os poderes e o visual novos: anfitrião e convidado continuam a 60 fps, trabalho por quadro de 1,2 a 1,5 ms (p50) e 2,4 a 2,6 ms (p95), tique da simulação do anfitrião de 0,8 ms (p95).
Um segundo teste de desempenho põe o anfitrião sozinho com 7 robôs difíceis, que rodam dentro da simulação dele: em 28/10/2026, 60 fps, tique da simulação de 0,6 ms (p95) e 2,1 ms com a CPU 4x mais lenta (pior tique 4,5 ms), trabalho por quadro de 0,6 ms e 1,8 ms (p95).
Medido em 28/10/2026 às 01:55, main com o visual novo, GPU ligada e densidade 2x: sala com 8 pessoas a 57 fps no normal e 60 fps com a CPU 4x mais lenta (quadro p95 16,8 ms, trabalho por quadro p95 0,9 ms e 2,8 ms, nenhuma tarefa longa); anfitrião com 7 robôs difíceis a 60 fps nos dois casos (trabalho por quadro p95 0,7 ms e 2,6 ms, tique p95 0,6 ms e 3 ms).
Medido de novo às 05:10, no fim da noite (main com todas as entregas): sala com 8 pessoas a 60 fps no normal e com a CPU 4x mais lenta, quadro p95 de 16,7 ms, trabalho por quadro p95 de 0,6 a 0,7 ms e de 2,0 a 2,1 ms, tique p95 de 0,2 ms e 0,4 ms, nenhuma tarefa longa; anfitrião com 7 robôs difíceis a 60 fps, tique p95 de 0,6 ms e 2,3 ms. O medidor junta num quadro só os laços de animação que rodam no mesmo quadro (o do jogo e o dos bonecos animados) e soma o trabalho deles.
Galeria de capturas, fora da suíte normal: SALINHA_GALERIA=<pasta> npx playwright test galeria joga uma rodada inteira num iPad e num celular com dois robôs e salva capturas (JPEG) da página inicial, do convite, do lobby com QR, da contagem, da partida, do resumo e do pódio, com o canvas desenhado pela GPU (cerca de 9 min).
Teste longo, fora da suíte normal: SALINHA_LONGO=1 npx playwright test longo joga uma rodada inteira com o anfitrião e 7 robôs difíceis (cerca de 13 min) e mede, depois de cada partida, a memória JavaScript (depois de coletar o lixo), o número de nós do DOM e os quadros por segundo; reprova se a memória ou o DOM dobrarem. Em 28/10/2026 às 02:58: memória de 3,8 MB no começo para 5,2 MB no fim (cerca de 0,1 MB por partida depois da primeira), DOM estável em ~400 nós, sem vazamento.
O que os testes de ponta a ponta ainda não cobrem: Safari e Firefox (só Chromium), rede ruim ou retransmissor TURN (as páginas estão na mesma máquina), fechar a aba em vez de clicar em "Sair" (a queda só é percebida pelo silêncio de 12 s), o anfitrião saindo, a morte súbita, os poderes de cada mapa, pontos por caixa na tela de resultado, a rodada completa de 5 partidas e o controle de videogame.
Netlify, time pessoal vhccruz-projects, projeto salinha-jogos (id dddafa63-ffb4-434e-b394-c39aad054106; o nome salinha já era de outra pessoa), em https://salinha-jogos.netlify.app. A pasta publicada é site/ e as funções ficam em netlify/functions/ (ambas no netlify.toml); pela CLI, netlify deploy --prod --dir site --functions netlify/functions.
O TURN da Cloudflare depende de duas variáveis de ambiente no projeto da Netlify, criadas pelo Victor numa conta Cloudflare pessoal (Realtime → TURN Server → criar chave): CLOUDFLARE_TURN_KEY_ID e CLOUDFLARE_TURN_API_TOKEN. Sem elas, /api/ice responde 503 e o site segue com a configuração embutida do PeerJS, igual à de antes. Custo: 1.000 GB por mês grátis, depois US$ 0,05/GB; o uso esperado fica abaixo de 10 GB por mês.
Decisão da noite de 28/10/2026 (sem login com senha, e-mail ou Google, que ficam para o Victor decidir): cada aparelho tem um perfil com apelido, cor, símbolo e estatísticas, sem dado pessoal.
site/js/conta.js é a interface para as telas (obterPerfil, salvarPerfil, registrarPartida, historico, ranking, codigoDeRecuperacao, recuperar); funciona sem rede, com uma cópia local, e manda depois as partidas jogadas offline. site/js/conta-regras.js tem as regras puras (limpeza dos campos, pontos calculados de caixas, eliminações e vitória, recordes, histórico das últimas 30 partidas, linha do ranking, código de recuperação), usadas pelo navegador e pelo servidor.netlify/functions/perfil.mjs guarda os perfis no Netlify Blobs (armazém perfis; deploys fora de produção usam perfis-teste): POST/GET/PUT /api/perfil, POST /api/perfil/partidas, POST /api/perfil/recuperar e GET /api/ranking. O servidor guarda só o SHA-256 do segredo, aceita escrita só da origem do site, limita o corpo a 8 KB e uma chamada de registro a cada 3 s por perfil, e a Netlify limita 60 chamadas por minuto por IP.site/js/pavio/registro.js registra cada partida terminada: cada aparelho registra só o próprio jogador, pela diferença do placar da rodada entre o começo e o fim da partida. O ranking conta só partidas com pelo menos duas pessoas (robôs não contam) e é "de honra": como não há servidor de jogo, quem quiser trapacear consegue inflar os próprios números.O repositório é público e as contribuições entram por pull request: faça um fork, crie uma branch a partir da main, rode npm test e npm run e2e (instruções em "Rodar e testar") e abra o pull request contra a main. As regras de código e de commits estão no AGENTS.md: textos da interface em português do Brasil, identificadores em português, comentários e commits em inglês, no padrão Conventional Commits.
O projeto ainda não tem licença de uso, por decisão do Victor em 28/10/2026: dá para ler o código, fazer fork no GitHub e mandar pull request, mas não para reaproveitá-lo em outro lugar.
moverComColisao), e manda a posição ~30 vezes por segundo; o anfitrião aceita só posição plausível (velocidade e paredes) e o aparelho se corrige se ficar longe da versão do anfitrião. Os outros jogadores aparecem com um atraso que se ajusta à oscilação da rede. Chamas só machucam depois de 0,12 s, para compensar o atraso das posições.$s), e cada ponta mede a perda pelos buracos na sequência; o membro informa a dele no $pong e o anfitrião publica ping, perda e retransmissor de cada um no $qualidade. nivelConexao() em sala.js diz se a conexão está boa, média ou ruim; a lista mostra a perda ao lado do ping quando passa de 2%.site/js/relogio.js usa um Web Worker como relógio para o anfitrião continuar simulando mesmo com a aba dele em segundo plano.criarPavio({ sala, palco, som, aoMudarInfo }) e trocar a chamada em site/js/app.js.reconexao.spec.mjs, queda e volta: um script de teste corta todos os canais de dados de um convidado nos dois sentidos (como uma queda de Wi-Fi, com a sinalização no ar); com 6 s de corte o anfitrião marca o convidado como fora, ele volta sozinho com o mesmo id, a partida segue e o anfitrião o vê andar de novo; com 20 s de corte, passados os 10 s de tolerância, a rodada acaba com o nome dele no motivo e a página dele mostra a queda. Com o script de queda da frente 4 (caos.mjs, que corta canais e sinalização e mata as ligações antigas, como uma troca de Wi-Fi), o anfitrião cai por 5 s: os convidados veem "Reconectando…", voltam sozinhos com os mesmos ids e a rodada segue sem motivo de fim; e com o anfitrião fora de vez, passada a tolerância, os convidados veem "Conexão perdida".rodada.spec.mjs, rodada completa: a anfitriã joga contra um robô e se explode em cada partida, para a rodada andar rápido; as 5 partidas passam na ordem dos mapas (nomes lidos de MAPAS), a tela final mostra "Fim da rodada", o campeão (ou empate) e o placar dos dois, explodir a si mesma nunca conta eliminação, e "Voltar ao lobby agora" leva ao lobby com o robô ainda lá. Leva cerca de 1 min.troca-anfitriao.spec.mjs, troca de anfitrião: o anfitrião clica em "Sair", a confirmação diz que a sala passa para a convidada mais antiga, ela assume com o mesmo código, o outro convidado a segue com o mesmo id, todos voltam ao lobby, uma rodada nova começa com a nova anfitriã e o antigo anfitrião volta pelo mesmo link para assistir.robos.spec.mjs, robôs: o anfitrião adiciona um robô de cada nível pelo lobby, tira um quarto e troca o nível de outro; o convidado vê os 3 robôs prontos ("robô fácil", "robô médio", "robô difícil") sem os botões do anfitrião; com só as 2 pessoas prontas a partida começa com os 3 robôs na escalação, e eles andam e quebram caixas na simulação do anfitrião e na tela do convidado.desempenho.spec.mjs, desempenho com 8 jogadores: sala cheia (os 7 convidados entram ao mesmo tempo, e no fim uma nona pessoa é recusada com a explicação de sala cheia), mapa normal, convidados andando a esmo e 3 deles soltando bombas; mede por 8 s o intervalo entre quadros e o tempo gasto em cada quadro no anfitrião e num convidado, e o tempo de cada tique da simulação no anfitrião; depois repete por mais 8 s com a CPU desses dois 4x mais lenta (limitação do Chrome DevTools, parecido com um tablet). Os números saem no console a cada execução e anexados ao relatório; os limites que reprovam são folgados (quadro p95 abaixo de 40 ms, trabalho por quadro e tique p95 abaixo de 8 ms; com a CPU 4x mais lenta, 60 ms e 16 ms), feitos para pegar uma piora grande e não variação de máquina. O anfitrião e o convidado medidos rodam cada um no seu próprio Chromium, com tela de iPad deitado em densidade 2x (SALINHA_DENSIDADE muda) e usando a GPU do Mac (Metal): sem GPU, o Chromium sem janela desenha o canvas em software, o custo cresce com o número de pixels e não diz nada sobre um tablet (em 2x e com a CPU 4x mais lenta o anfitrião com 7 robôs caía para ~40 fps só por isso). Com as 8 páginas num navegador só, o processo de GPU que elas dividem também segura tudo em ~20 fps, por isso os navegadores separados.