3 pontos por GN⁺ 2024-05-21 | 1 comentários | Compartilhar no WhatsApp

City In A Bottle – sistema de raycasting de 256 bytes

  • Introdução

    • Hoje vamos apresentar um pequeno motor de raycasting e um gerador de cidades contidos em um arquivo HTML de 256 bytes.
    • É possível entender este programa como se estivesse resolvendo um quebra-cabeça que condensa vários conceitos em um espaço minúsculo.
    • Os principais componentes são o código HTML, o loop de atualização de frames, o sistema de renderização, o motor de raycasting e a própria cidade.
  • Código completo

    • Este código não é apenas um snippet simples de JavaScript, mas sim um programa HTML completo.
    • <canvas style=width:99% id=c onclick=setInterval('for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a',t=9)>
      

Código HTML

  • Código HTML
    • A parte em HTML é composta por um elemento canvas simples e um evento onclick.
    • <canvas style=width:99% id=c onclick=setInterval('',t=9)>
      
    • O id do elemento canvas é definido como c, permitindo acesso via JavaScript.
    • O evento onclick inicia o programa e cria o loop de atualização por meio da chamada a setInterval.

Código JavaScript

  • Código JavaScript

    • Código JavaScript de 199 bytes executado quando o canvas é clicado.
    • for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a
      
  • Análise do código

    • O código foi decomposto para facilitar a leitura.
    • c.width = w = 99
      ++t
      for (i = 6e3; i--;){
        a = i%w/50 - 1
        s = b = 1 - i/4e3
        X = t
        Y = Z = d = 1
        for(; ++Z<w &  (Y < 6 - (32<Z & 27<X%w && X/9^Z/8)*8%46 ||  d | (s = (X&Y&Z)%3/Z, a = b = 1, d = Z/w));) {
          X += a
          Y -= b
        }
        c.getContext`2d`.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1)
      }
      
  • Explicação passo a passo do código

    • c.width = w = 99: inicializa o canvas e define sua largura como 99 pixels.
    • ++t: incrementa a variável de tempo para criar a animação.
    • for (i = 6e3; i--;){}: usa um loop para determinar o brilho de cada pixel.
    • a = i % w / 50 - 1: calcula o componente horizontal do vetor da câmera.
    • b = s = 1 - i / 4e3: calcula o componente vertical do vetor da câmera.
    • X = t: usa o valor do tempo como posição X inicial.
    • Y = Z = d = 1: inicializa os valores de Y, Z e d.
    • for(; ++Z<w & ...;): o sistema de raycasting continua em loop até detectar uma colisão.
    • c.getContext2d.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1): desenha cada pixel para formar a imagem final.

Aprendizado adicional

  • Aprendizado adicional
    • Este demo foi apresentado na demoparty Revision 2022 e pode ser conferido no Pouet.
    • Também é possível ver uma versão expandida para um shader de 256 bytes no Shadertoy.
    • Uma ferramenta interativa criada por Daniel Darabos permite manipular em tempo real vários aspectos do programa.

Opinião do GN⁺

  • Pontos interessantes

    • Este programa mostra como gerar gráficos complexos com uma quantidade extremamente pequena de código.
    • Usa apenas matemática básica, o que o torna compreensível até para engenheiros de software iniciantes.
    • É um bom exemplo de otimização de código e minimalismo, podendo ser útil em competições como code golf.
  • Visão crítica

    • Como o código é extremamente comprimido, a legibilidade pode ser prejudicada.
    • Ele é mais adequado para fins artísticos e experimentais do que para aplicações práticas.
  • Tecnologias relacionadas

    • Em projetos semelhantes, é possível encontrar diversos exemplos de shaders no Shadertoy.
    • Também dá para explorar outros exemplos de código curto em plataformas como o Dwitter.
  • Considerações para adoção da tecnologia

    • Ao adotar essa técnica, é preciso considerar a legibilidade e a manutenibilidade do código.
    • Também é importante reconhecer as dificuldades de otimização de desempenho e depuração ao implementar funcionalidades complexas com pouco código.

1 comentários

 
GN⁺ 2024-05-21
Opiniões no Hacker News

Resumo da coletânea de comentários do Hacker News

  • Jogo de Pinball de 1K em JavaScript:

    • "É impressionante conseguir colocar tanta informação em tão pouco código."
    • "Isso é realmente muito legal, mas enquanto eu lia o artigo o loop continuava rodando e meu notebook superaqueceu."
    • "Material relacionado: como o mundo de Pitfall, do [Atari 2600], foi construído, geração procedural, avaliação preguiçosa etc."
  • Geração procedural e avaliação preguiçosa:

    • "Fornece vários links de materiais sobre geração procedural."
    • "Observação sobre a semelhança entre avaliação preguiçosa e algoritmos de ray tracing."
  • Outras opiniões:

    • "Muito legal mesmo! Bom trabalho."
    • "Tanto o trabalho quanto o artigo são impressionantes."
    • "Remnants by Alcatraz, semelhante a uma demo de 256 bytes para MS-DOS — inclui link do YouTube."
    • "O fato de ter sido escrito em JavaScript é ainda mais impressionante."
    • "Realmente impressionante."
    • "É divertido de ler."
    • "Se você gosta disso, provavelmente também vai gostar de #tweetcart no Twitter. São programas do tamanho de um tweet para o console virtual Pico-8."