OhMyGame
OhMyGame은 AI로 게임을 만들 수 있는 오픈소스 스튜디오로, 디자인·구축·플레이테스트·출판을 하나의 앱에서 모델 키와 함께 수행합니다
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
Salinha: jogos com a galera por link, sem cadastro, ligados por WebRTC. Primeiro jogo: Pavio, arena de bombas para até 8 pessoas.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
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.