15

GLM 5.2 Pac-Man One-Shot

Como conduzi e preservei um experimento one-shot de geração de um jogo Pac-Man completo com GLM-5.2.

Captura de tela do jogo Pac-Man gerado pelo experimento

GLM 5.2 Pac-Man One-Shot: anatomia de uma geração de jogo em uma única tentativa

Quis verificar até onde uma única geração, sem projeto inicial, ferramentas ou segunda tentativa, poderia produzir um jogo executável. Publiquei no GLM-5.2 One-Shot Pac-Man os dois prompts e o pacman.html autocontido gerado pelo GLM-5.2 em esforço Max. A principal contribuição é preservar um estudo de caso inspecionável: 879 linhas, sem bibliotecas, imagens, servidor, etapa de build ou URL externa [1, 2].

Preservei os prompts, o protocolo que executei, o HTML gerado e as verificações que realizei. Como fiz uma única tentativa, N = 1, demonstrei a existência desse resultado específico; não estimei taxa de sucesso, variância entre amostras nem superioridade geral do modelo.

Motivação e contexto do modelo

Escolhi um jogo porque ele comprime vários problemas de engenharia em um artefato pequeno: entrada concorrente, estado mutável, temporização, desenho, colisão, regras de pontuação e agentes com comportamentos diferentes. Ao contrário de completar uma função isolada, uma falha de integração pode tornar todo o resultado injogável. Meu objetivo foi testar geração from scratch sob restrições duras, não substituir benchmarks padronizados [1].

A Z.ai descreve o GLM-5.2 como modelo de texto com contexto de 1 milhão de tokens, saída máxima de 128 mil tokens, uso de ferramentas e níveis configuráveis de esforço de raciocínio; o exemplo oficial usa reasoning_effort: "max" [7]. O modelo possui pesos 744B-A40B sob MIT e resultados do fornecedor em benchmarks [8]. Esses dados caracterizam o modelo, mas não transformam meu Pac-Man em benchmark. O relatório acadêmico disponível é do GLM-5, antecessor orientado a tarefas longas de engenharia; ele fornece contexto de família, não uma medição deste experimento [9].

Protocolo one-shot exato

Executei o experimento no GLM Coding Plan, com GLM-5.2 em esforço Max. Em uma única interação, enviei o prompt de sistema e o prompt de tarefa abaixo, recebi a resposta completa e não fiz correção, nova tentativa ou mensagem posterior. Publiquei pacman.html sem editar a implementação gerada [1].

O prompt de sistema, reproduzido literalmente do README, impôs três blocos: análise prévia, implementação e revisão interna [1]:

You are the world's leading expert in vanilla web development, specifically in creating
high-performance, single-file web applications using only HTML5, CSS3, and ES6+ JavaScript.
You reject frameworks in favor of clean, efficient, and semantic code.
 
Your goal is to receive a requirement and produce a single, self-contained HTML file that
functions perfectly without external dependencies (no CDNs, no images, no libraries).
 
Because you must complete this task in a "one-shot" continuous generation, you must think
before you code. You will follow a strict "Chain of Thought" protocol to ensure correctness.
 
Follow this specific execution format for every response:
 
<analysis>
    1. REQUIREMENTS BREAKDOWN:
    - List every functional and non-functional requirement.
    - Identify potential edge cases.
 
    2. ARCHITECTURAL PLAN:
        - CSS Strategy: Define the variable system, layout approach (Flexbox/Grid), and
          responsive breakpoints.
        - JS Architecture: Define state management, event listeners, and core logic functions.
        - HTML Structure: specific semantic tags to be used.
 
    3. PRE-MORTEM & STRATEGY:
        - Identify the most likely point of failure.
        - Define the solution for that specific failure point before writing code.
</analysis>
 
<implementation>
    (Provide the complete, valid HTML string here. Include CSS in <style> and JS in <script>
     tags. The code must be production-ready, accessible, and clean.)
</implementation>
 
<code_review>
Self-Correction and Validation Report:
 
    1. Does the code meet all requirements listed in the analysis? [Yes/No]
    2. Are there any distinct accessibility (a11y) violations?
    3. Verify that no external libraries were used.
</code_review>

O prompt de tarefa definiu escopo e oito condições de aceite [1]:

[INTENT] Build a complete, playable Pac-Man clone as a self-contained HTML page that runs
         by double-clicking the file.
 
[SCOPE]
  - Classic Pac-Man gameplay: navigate maze, eat dots, avoid ghosts
  - Core mechanics: maze with walls, dot collection, score, lives, 4 ghosts, power pellets
    with frightened-ghost mode
  - Standard arcade elements: 4 ghosts with distinct AI personalities, wrap-around tunnel,
    multiple levels
 
[APPROACH]
  - Single pacman.html file with inline <style> and <script>
  - HTML5 Canvas for rendering (grid-based maze, ~28x31 tiles like the original)
  - Vanilla JavaScript, no frameworks
  - Keyboard controls: arrow keys + WASD
 
[CONSTRAINTS]
  - Must work offline by opening the file directly in a browser
  - No external dependencies, CDNs, or asset files
  - No build step
 
[DELIVERABLE]
  - One complete pacman.html file
 
[DONE WHEN]
  - Game launches by double-clicking the file
  - Pac-Man moves with keyboard and respects maze walls
  - Dots are eatable; score increments
  - 4 ghosts move with distinct behaviors and chase Pac-Man
  - Power pellets turn ghosts vulnerable; eating a vulnerable ghost resets that ghost
  - Pac-Man loses a life on ghost contact when not powered
  - Game ends at 0 lives; restart works
  - Score and lives visible on screen

Na versão inicial, não preservei a resposta bruta com <analysis> e <code_review>, o identificador da requisição, os parâmetros de amostragem ou o snapshot do serviço. Assim, é possível validar o prompt e o produto final, mas não reconstituir criptograficamente toda a sessão.

Arquitetura do arquivo único

O HTML usa elementos semânticos para HUD e controles, uma sobreposição DOM para mensagens e um Canvas de 560 × 620 pixels para a cena. A especificação HTML define Canvas como bitmap dependente de resolução, desenhado por script, e recomenda conteúdo alternativo equivalente; aqui existe aria-label, mas não há fallback jogável ou descrição textual dentro do elemento [10]. CSS cuida de enquadramento responsivo e aparência; JavaScript, encapsulado em uma IIFE e em modo estrito, concentra estado, regras, IA e desenho [2].

Renderizando diagrama...

Estado global e entidades

Não há classes nem store. Variáveis fechadas pela IIFE guardam maze, dotsLeft, score, level, lives, gameState, temporizadores, pacman, ghosts e popups. newGame() zera placar, nível e vidas; startLevel() recompõe o mapa e agenda ready; resetPositions() preserva placar e labirinto ao reiniciar uma vida [2]. É uma solução econômica para um arquivo único, embora o acoplamento dificulte testes unitários.

Cada entidade combina coordenadas inteiras tileX/tileY, direção atual, direção desejada e progress entre 0 e 1. A posição visual é r=tile+direcao×progressr=\mathrm{tile}+\mathrm{direcao}\times\mathrm{progress}. Assim, decisões de curva e parede acontecem no centro lógico do ladrilho, enquanto o sprite se move suavemente entre centros. O Pac-Man avança 0,0850{,}085 ladrilho por tick:

0,085×60=5,1 ladrilhos/s,5,1×20=102 pixels/s.0{,}085\times60=5{,}1\ \text{ladrilhos/s}, \qquad 5{,}1\times20=102\ \text{pixels/s}.

O fantasma comum começa em 0,072×60=4,320{,}072\times60=4{,}32 ladrilhos/s e acelera com o nível [2].

Renderizando diagrama...

Os fantasmas têm outra máquina implícita: house, leaving, scatter, chase, frightened e eaten. Pinky, Inky e Clyde saem após 90, 300 e 480 ticks; a porta - só aceita fantasmas em leaving ou eaten. O modo global segue scatter 7 s → chase 20 s → scatter 7 s → chase 20 s → scatter 5 s → chase indefinido, congelando durante vulnerabilidade [2].

Passo fixo e orçamento de FPS

requestAnimationFrame() solicita um callback antes da próxima repintura e sua frequência normalmente acompanha o monitor; abas em segundo plano costumam ser pausadas. Por isso, usar o timestamp, em vez de presumir um quadro por chamada, evita acelerar a simulação em telas rápidas [11]. A anatomia de jogos da MDN também apresenta a separação entre atualização fixa e desenho como uma opção para manter variáveis não cosméticas em frequência constante [12].

O jogo implementa o acumulador clássico:

let last = performance.now(), acc = 0;
const STEP = 1000 / 60;
function loop(now) {
  acc += now - last;
  last = now;
  if (acc > 200) acc = 200;
  while (acc >= STEP) { update(); acc -= STEP; }
  render();
  requestAnimationFrame(loop);
}

Formalmente, para intervalo real Δt\Delta t, A=min(A+Δt,200ms)A'=\min(A+\Delta t,200\,\mathrm{ms}) e o número de atualizações é n=A/hn=\lfloor A'/h\rfloor, com h=1000/6016,667msh=1000/60\approx16{,}667\,\mathrm{ms}; o resto A=AnhA''=A'-nh segue para o próximo quadro. O teto admite no máximo 200/16,667=12200/16{,}667=12 atualizações de recuperação, evitando uma espiral ilimitada após suspensão. Em 60 Hz, atualização e renderização disputam um orçamento nominal de 16,667 ms; em 120 Hz, há render a cada 8,333 ms, mas update apenas quando o acumulador completa um passo. Não há interpolação pelo resto A/hA''/h, então quadros extras podem repetir a mesma posição. Também não há perfil de desempenho versionado: dizer que o jogo cabe no orçamento é plausível para 868 ladrilhos, mas não é uma medição.

Labirinto, colisão e IA

MAZE_DEF é uma matriz literal de 31 strings com 28 caracteres. A legenda é # parede, . ponto, o energizador, espaço corredor vazio e - porta. Uma contagem direta encontra 298 pontos, 4 energizadores e 2 células de porta; rebuildMaze() copia as strings para arrays mutáveis e define dotsLeft = 302 [2]. O túnel horizontal usa

wrapX(x)=((xmod28)+28)mod28.\operatorname{wrapX}(x)=((x\bmod28)+28)\bmod28.

canGo() bloqueia paredes, limites verticais e a porta conforme o estado. O Canvas é redesenhado inteiro: fundo, paredes, bordas, itens e sprites; cópias nas bordas escondem o salto visual do túnel [2].

A colisão usa os centros interpolados. Se Δx2+Δy2<0,25\Delta x^2+\Delta y^2<0{,}25, a distância Euclidiana é menor que meio ladrilho. Fantasma vulnerável vira eaten; outro fantasma causa dying. Isso é concreto e barato, mas não é colisão varrida: duas entidades que cruzassem entre ticks poderiam escapar, e a distância não considera circularidade no túnel [2].

As personalidades compartilham navegação gulosa e diferem no alvo. Em cada centro, removem-se paredes e, salvo estados especiais, a reversão; a ordem de desempate é cima, esquerda, baixo, direita. Para candidato cc e alvo tt, o código minimiza a Euclidiana ao quadrado,

dE2(c,t)=(cxtx)2+(cyty)2.d_E^2(c,t)=(c_x-t_x)^2+(c_y-t_y)^2.

Extrair a raiz não mudaria a ordenação. Uma alternativa comum em grades seria Manhattan,

d1(c,t)=cxtx+cyty,d_1(c,t)=|c_x-t_x|+|c_y-t_y|,

mas ela não é usada aqui e poderia escolher outra curva [2].

  • Blinky mira a posição atual P.
  • Pinky mira P + 4·direção.
  • Inky calcula A=P+2direcaoA=P+2\,\mathrm{direcao} e mira T=2ABlinkyT=2A-\mathrm{Blinky}.
  • Clyde mede dE=(gxpx)2+(gypy)2d_E=\sqrt{(g_x-p_x)^2+(g_y-p_y)^2}; persegue se dE>8d_E>8, caso contrário mira seu canto.

Em frightened, a escolha é aleatória entre direções válidas, a velocidade cai para 0,05 e a duração é max(120, 360 - 30·(nível-1)) ticks: 6 s no nível 1 e piso de 2 s. Fantasmas sucessivos valem 200·2^k, com k limitado a 3, produzindo 200, 400, 800 e 1.600 pontos [2].

Critérios de aceite e verificação

Na validação estática, confirmei implementação correspondente aos oito itens: abertura local sem recursos externos; teclado; paredes; consumo e placar; quatro definições e alvos; vulnerabilidade; perda de vida; gameover, reinício, HUD e níveis [2]. A cobertura de requisitos é

C=requisitos com evidencia estruturalrequisitos totais=88=100%.C=\frac{\text{requisitos com evidencia estrutural}}{\text{requisitos totais}}=\frac{8}{8}=100\%.

Isso mede presença de caminhos no código, não taxa de sucesso em execução.

No README, registrei a aprovação dos oito itens no primeiro lançamento, a verificação sintática, a validação geométrica e uma simulação headless de cerca de 500 ticks [1]. Não preservei teste, harness, relatório ou log desse ensaio. Para uma nova reprodução, adotaria primeiro a extração e compilação do script sem executar o DOM:

git clone https://github.com/DominguesM/glm5.2-pacman-oneshot.git
cd glm5.2-pacman-oneshot
open pacman.html
 
node -e 'const fs=require("fs"),vm=require("vm"); const h=fs.readFileSync("pacman.html","utf8"); new vm.Script(h.match(/<script>([\s\S]*?)<\/script>/)[1]); console.log("JavaScript válido")'

Na publicação da demonstração, a primeira execução parou em Setup Pages; depois, executei o workflow manualmente com sucesso [5][6]. Configurei esse workflow apenas para copiar pacman.html para _site/index.html, incluir README e licença e publicar o artefato com actions oficiais; ele não transpila nem testa [4].

Resultados, limites e interpretação

Com uma única geração, obtive um artefato pequeno, legível e jogável com ciclo completo, 302 itens, quatro alvos, pontuação, três vidas, pausa, toque, fases, vida extra e deploy [2][3]. A amostra cobre estruturalmente a especificação e foi publicada com sucesso, mas não permite derivar a probabilidade de sucesso do modelo nem compará-lo quantitativamente a outros modelos.

Ao revisitar o jogo, identifiquei simplificações concretas. Mantive as dimensões pedidas para o mapa, mas não validei a descrição “arcade-accurate”. A distância dos fantasmas não usa o menor caminho nem distância circular no túnel. Um fantasma eaten mira a saída da casa e volta a chase/scatter ao chegar nela; não entra na casa nem cumpre novo atraso, apesar da descrição mais forte que registrei no README. A colisão não trata o túnel como espaço toroidal. Também preservei tile(), roundRect() e a variável ed sem uso, em contraste com minha observação no README sobre ausência de código morto [1][2]. Na acessibilidade, implementei HUD semântico, rótulos e aria-live, mas o Canvas não oferece alternativa equivalente para jogar sem visão, o teclado exige janela focada e o movimento por swipe não substitui controles explícitos [2][10].

Na versão inicial, também não registrei sementes para Math.random(), captura da resposta original, configuração completa de inferência, testes automatizados, matriz de navegadores, telemetria de FPS e múltiplas amostras [1][2]. Logo, “reproduzir o software” é fácil; “reproduzir exatamente a geração” não é.

Reprodutibilidade, deploy e licença

Para reproduzir o produto publicado, clone a branch main, abra pacman.html e use setas ou WASD; P pausa, R reinicia e swipe controla em telas de toque [2][3]. Para repetir o experimento, use os dois prompts literais em uma única solicitação ao modelo glm-5.2, pensamento habilitado e esforço max, não envie correções e preserve separadamente a resposta bruta, os parâmetros e a data. Registre também uma verificação de integridade do artefato em seu próprio ambiente. A API oficial documenta os campos de modelo e esforço, mas uma execução futura ainda pode divergir por amostragem ou atualização do serviço [7].

O repositório aplica licença MIT, copyright 2026 de Maicon Domingues, permitindo usar, copiar, modificar, publicar e sublicenciar, desde que aviso e licença sejam preservados; o software é fornecido sem garantia [13]. Isso cobre os arquivos licenciados pelo autor, não concede automaticamente direitos sobre marcas, personagens ou elementos de terceiros associados a Pac-Man. Para distribuição comercial, essa camada de propriedade intelectual exige análise própria.

Conclusão

Com este experimento, preservei um jogo autocontido produzido em uma única geração e tornei inspecionável sua integração de estado, desenho e regras. O resultado demonstra esse caso específico, sem generalizá-lo para outras execuções; aprendi que prompts e artefatos finais ganham valor experimental quando acompanhados também por logs e parâmetros completos.

Referências

  1. DominguesM, README do GLM-5.2 One-Shot Pac-Man na branch main
  2. DominguesM, pacman.html na branch main
  3. GitHub, histórico de commits do repositório
  4. DominguesM, workflow deploy.yml na branch main
  5. GitHub Actions, histórico do workflow de deploy
  6. Demonstração ao vivo no GitHub Pages
  7. Z.ai, documentação oficial do GLM-5.2
  8. Z.ai, repositório e cartão oficial da família GLM-5
  9. GLM-5 Team, “GLM-5: from Vibe Coding to Agentic Engineering”, arXiv:2602.15763
@misc{glm5team2026glm5,
  title        = {GLM-5: from Vibe Coding to Agentic Engineering},
  author       = {{GLM-5 Team}},
  year         = {2026},
  eprint       = {2602.15763},
  archivePrefix= {arXiv},
  primaryClass = {cs.LG},
  doi          = {10.48550/arXiv.2602.15763},
  url          = {https://arxiv.org/abs/2602.15763}
}
  1. WHATWG, HTML Living Standard: o elemento Canvas
  2. WHATWG, HTML Living Standard: Animation Frames
  3. MDN Web Docs, Anatomy of a video game
  4. DominguesM, licença MIT do projeto na branch main