El motor, una pieza cada vez
Cada ejemplo enseña una sola cosa y se ejecuta aquí mismo. Edítalo y verás el resultado al momento; el editor conoce la API de la versión que elijas, así que te autocompleta y te subraya los errores antes de que ejecutes nada.
Sprites y 2D
Capas y transparenciaEn 2D no hay búfer de profundidad: el orden de dibujado es la capa. Los sprites llevan un zIndex y el renderizador los ordena por él en cada fotograma.
Tinte y colorEl tinte de un sprite se multiplica por su imagen en cada fotograma: la base de los destellos de golpe y los fundidos.
Pixel artLa opción smooth elige entre filtrado nítido y suavizado: píxeles duros al ampliar un sprite retro.
Más cosas de un spriteflipX lo refleja, anchor mueve el punto de giro, y un atlas enseña solo una parte de la imagen.
Animación de spritesAnimación por fotogramas desde un atlas, en rejilla o con rectángulos con nombre, con clips en bucle y de una sola vez.
Atlas en un ficheroUn atlas escrito como fichero .atlas: la textura, cómo se corta y sus secuencias con nombre, en un solo recurso.
TilemapUn nivel entero desde un fichero .tilemap: capas por delante y por detrás de los personajes, una llamada de dibujo por capa, casillas que se animan y casillas que se rompen.
PartículasUna reserva de partículas simulada en la CPU y dibujada de una vez por emisor: fuego, humo y una ráfaga con cada clic.
Cámara que sigueUna cámara 2D que sigue a un objetivo en movimiento, moviendo su posición en cada fotograma.
ParallaxCinco capas de bosque, cada una a su velocidad: la ilusión de profundidad de los 16 bits.
FormaciónCuarenta sprites que comparten una textura, colocados y animados como un solo grupo.
Cámara y HUDUna cámara 2D desplaza el mundo mientras useScreenSpace clava el HUD a la pantalla: una escena, dos espacios.
Tweens y curvasuseTween lleva un valor de un sitio a otro a través de una curva, con retardo, repetición e ida y vuelta.
Controlar un tweenArrancar un tween devuelve sus mandos: pausarlo, reanudarlo, cancelarlo o llevarlo al final.
Hola, mundoEl juego más pequeño posible: un lienzo, un color de fondo y el bucle en marcha.
SpritesCada sprite se dibuja como un cuadrado con textura; uno sin textura se dibuja como un cuadrado de color.
BunnymarkLa prueba de estrés clásica: cientos de sprites rebotando a la vez para medir cuánto aguanta el 2D.
Carga de texturasuseLoadTexture devuelve la textura en el acto y la rellena cuando llega la imagen: los sprites aparecen según aterrizan.
TransformPosición, giro y escala en el transform del sprite. Giro y escala pivotan en su centro, así que gira donde está.
Tamaño automáticoSin width ni height, un sprite toma el tamaño natural de su textura en cuanto se carga.
Reparto aleatoriouseRandom es el generador con semilla del juego: con la misma semilla, el mismo reparto en cada ejecución.
RenderizadoresEl motor trae WebGPU y WebGL2, y el juego nunca sabe cuál dibuja. Cambia RENDERER y todo sale igual.
Mallas y 3D
Partículas 3DLa misma reserva de partículas, dibujada como cuadrados que miran a la cámara, en unidades del mundo.
Partículas en el espacioUn géiser y polvo desde sus propios ficheros, uno torcido por la caja de la que cuelga, y un orbe cuya aura viaja con él mientras su estela se queda atrás.
Partículas en una escaleraChispas que rebotan escaleras abajo y lluvia que acaba sobre ellas: cada escalón lleva un colisionador de partículas.
Dos cámarasLas capas 2D y 3D miran por cámaras distintas: WASD mueve una, las flechas la otra, y ninguna toca la otra capa.
Un cuboUn modelo es una forma, un sitio y una superficie. La luz se calcula en las esquinas y se reparte por cada cara, como hacían las consolas de la época.
LucesTres clases de luz: un sol con dirección y sin sitio, una lámpara que se apaga con la distancia y un foco estrechado a un cono.
Luz puntualusePointLight es una bombilla: tiene un sitio y se apaga con la distancia. Al pasar cerca de una fila de cubos, cada uno se ilumina y se apaga.
FocouseSpotLight es una luz puntual estrechada a un cono, que barre una fila de cubos sobre un suelo.
Suelo 3DusePlaneGeometry como suelo bajo un cubo, con la cámara levantada y mirando hacia abajo para que el plano se vea.
Píxeles y piezasUna cámara 3D ortográfica mide en los mismos píxeles que un sprite, así que una pieza 3D puede ponerse encima de una casilla 2D.
Modelo glTFuseLoadGltf devuelve el modelo al momento, aún cargando, y createModel lo pone en la escena: aparece solo cuando llega el fichero.
Un modelo y sus piezasEste camión son cinco piezas: una rueda a cada lado y una carrocería que es pintura, cristal y embellecedor. Un solo sitio las mueve todas.
HuesosUn modelo con esqueleto es una piel sobre unos huesos: un zorro que otea, camina y corre, y que cambia de movimiento suavemente en las articulaciones.
FlatwoodUna criatura animada a mano en un .glb con once huesos y cuatro movimientos. Tres se repiten; el cuarto termina, y onEnd avisa cuando llega.
2D y 3DLas dos mitades en una misma escena y ordenadas por el mismo zIndex: un sprite detrás del modelo y un panel delante.
JerarquíaLos mismos tres niveles en píxeles planos y en tres dimensiones: la luna solo sabe a qué distancia está de su planeta.
2D dentro de 3DcreateSpriteTexture dibuja un componente entero en una imagen en cada fotograma, y un modelo la enseña: la pantalla de una consola portátil.
Un juego 2D en una pantalla 3DUn minijuego 2D escrito con componentes normales, que no sabe dónde se enseña, dibujado en la pantalla de un panel y en la piel de una caja.
Líneas de depuración y pickingUna rejilla, los ejes y un gizmo en cada caja, y el puntero convertido en un rayo que coloca una cruz en el suelo y elige cajas.
WebGPU frente a WebGL2La misma escena, dos juegos, dos renderizadores, uno al lado del otro. La escena nunca sabe con cuál se dibuja.
Densidad de píxelesLa misma escena con pixelRatio 1, 2 y el de la pantalla: bordes 3D más finos en pantallas densas, y un sprite que enseña por qué el pixel art se queda en 1.
1997Todos los rasgos de PlayStation a la vez: temblor de vértices, texturas afines, niebla y dither. Apágalos para ver la misma escena hoy.
NieblauseFog: los modelos se funden con un color según se alejan de la cámara, la seña de Nintendo 64 y la forma clásica de esconder dónde termina el mundo.
Texturas afinesLas texturas que nadan de PlayStation: con affine, la imagen se estira en línea recta por la pantalla sin corregir la profundidad.
Cubo afínDos cubos girando con la misma textura: el de la derecha es afín y su imagen se dobla y nada como en PlayStation.
Temblor de vérticesEl temblor de PlayStation: con vertexSnap, los vértices caen en una rejilla gruesa de la pantalla y los modelos saltan al moverse.
PrimitivasOcho formas construidas en código en vez de cargadas: el menú Add Mesh de Blender sin el mono.
Muchas lucesHasta ocho luces a la vez, el techo de la época. Solo una proyecta sombra, y las demás siguen iluminando dentro de ella.
Sombra de manchauseBlobShadow pone un disco oscuro y suave bajo algo: la sombra barata que usaban de verdad las consolas de la época.
Sombras proyectadasUna luz con castShadow proyecta la forma de las cosas sobre lo que tienen detrás; el zorro proyecta la pose en la que está.
Sombreado plano o suaveCómo mira la superficie de un modelo decide si parece tallado o moldeado: arriba flat, abajo smooth.
Duelo de cartasCartas 3D al estilo de los duelos de cartas: se roban, se invocan boca arriba, se colocan boca abajo y de lado, y se giran.
Entrada
Teclado y punterouseKeyboard para mover un sprite y tres maneras de darle eventos de puntero a un sprite.
MandoUn probador de mandos: todos los botones, gatillos y sticks a la vez, y vibración. Necesita un mando.
Mapa de entradaAcciones con nombre unidas a teclas, botones y direcciones del stick a la vez, declaradas en project.json, y una pantalla de controles para cambiarlas.
Elegir con el punterousePointer es una sola entrada para toda la escena, y cada evento dice qué hay debajo del puntero.
Pantalla completaEl juego pide la pantalla completa con un clic o una tecla, y la escala a múltiplos enteros con bandas de su color.
Físicas
Cajas que caenUna sala cuyo suelo, repisa y cuatro cajas son un documento JSON, con colisionadores y gravedad. El motor guarda el formato pero no lo mueve: un installPhysics2d() es lo que lo hace caer.
RebotadoresLa misma física escrita a mano: usePhysicsWorld2d y usePhysicsBody2d dicen de qué está hecho cada objeto, y el adaptador hace lo que el formato no puede decir.
Física 2D con RapierEl punto de partida de la física 2D: caen cajas y se apilan contra paredes estáticas. En píxeles, con la y hacia abajo.
Escalera de rebotesSeis bolas iguales soltadas desde la misma altura, que solo se diferencian en su restitución, de 0 a 0,95.
Torre y bola de demoliciónUna torre de ocho cajas que tiene que aguantar en pie. Haz clic para lanzar una bola pesada contra ella.
Polígonos convexosTriángulos, rombos, pentágonos y hexágonos rodando por rampas estáticas. Las esquinas se escriben alrededor del centro del objeto.
Plataforma cinemáticaEl tercer tipo de cuerpo: una plataforma que lleva y empuja cajas, pero a la que nada puede empujar.
Sensores y contactosLas cajas cruzan una franja sensor y cambian de color con onEnter y onExit, sabiendo con qué objeto se han cruzado.
Física desde un documentoLas mismas cajas, escritas como datos: un documento de escena pasado por sceneFromDoc, con installPhysics2d() poniendo la simulación.
Bolas que rebotanEsferas que conservan su energía durante muchos botes. La restitución es de la pareja, así que el suelo también la pide.
Torre de cajasOcho cajas apiladas en una torre que no se mueve. Haz clic para tirarla con un impulso lateral.
DominóUna reacción en cadena que nadie programa: sale del contacto y la gravedad. Haz clic para empujar la primera ficha.
BolosUna esfera densa y un applyImpulse contra diez bolos ligeros: el pleno es transferencia de momento. Haz clic para lanzar.
PachinkoBolas dinámicas que caen entre pivotes estáticos: el mismo colisionador con otro tipo de cuerpo. Haz clic para subirlas.
Cascada de rampasCanicas que ruedan por rampas inclinadas en zigzag. El giro orienta el colisionador, no solo la malla.
PersonajeUn personaje, no un cuerpo: una cápsula que se mueve con consultas al mundo en vez de con fuerzas. WASD para andar, espacio para saltar.
Cubos que caenLa introducción a la física 3D con el adaptador opcional nacatamalon/physics3d (Box3D en WASM). Haz clic para dar una patada a los cubos.
Torre desde un documentoLa misma física, escrita como datos: un documento de escena pasado por sceneFromDoc. La torre cae porque el documento lo dice.
Puerta sensorUn sensor se guarda con la escena; oírlo es cosa del adaptador. La puerta marca cada caja que la atraviesa sin parar ninguna.
Shaders y post
Post-procesoUn shader sobre el fotograma entero: líneas de barrido y cuantización de color, que se encienden y apagan en vivo.
Carga de energíaUn uniform que se mueve desde el juego: el objeto que pasas a createMaterial es el que lee el renderizador, así que escribir un número en él llega al siguiente fotograma.
Efectos de shaderUna galería de materiales: disolución, holograma, posterizado, fantasma, destello, tono, onda y aberración cromática, cada uno una sola función.
Efectos 3DShaders de superficie en mallas: disolución, holograma con fresnel, campo de fuerza y tornasol por ángulo.
Efectos de shader IIUna segunda tanda sobre sampleTexture(uv): glitch, remolino, desenfoque, ondas, curvatura CRT, bordes, película antigua y caleidoscopio.
Efectos 3D IIOtra tanda de superficie: lava procedural, una banda de escaneo, paleta térmica y un tramado Bayer de 1 bit.
Mar de lavaUn océano ondulante a lo Wave Race, pero de lava: un material con los dos ganchos de malla, vértice y efecto.
Efectos combinadosCuatro materiales con los dos ganchos a la vez: un portal, un fantasma, un cristal y una gelatina.
EspecularEl brillo Blinn-Phong del modelo de luz: una fila de esferas de mate a brillante, cambiando solo shininess.
Grafo de shaderUn shader escrito como valores tipados en vez de WGSL: compileShader escribe el fn effect que toma createMaterial, en los dos lenguajes.
Grafo de shader 3DUn grafo que mueve las dos etapas del material de un modelo: el color y la posición.
Portable por construcciónEl mismo sombreado cel con borde compuesto como grafo, sin WGSL ni GLSL, dibujado por los dos renderizadores a la vez.
Shaders portablesWebGL2 no compila WGSL y el motor no finge traducirlo: un material puede llevar una segunda mitad en GLSL.
Un shader solo para WebGPULa degradación, enseñada a propósito: con solo su mitad WGSL, en WebGL2 el objeto se dibuja con el shader de serie y un aviso en la consola.
Líneas de barridoEl primer material con shader propio: createMaterial recibe una función y el motor le da la imagen ya leída y teñida.
Sombreado celEl material de un modelo tiene dos ganchos: uno de color que corta la luz en bandas y otro de vértices que ondula la superficie.
Uniforms por spriteUn material compartido por quince sprites: el shader se compila una vez y cada sprite pone sus propios uniforms.
Shader en un ficheroUn efecto en su propio fichero: la escena guarda la clave y nunca el código, así que se puede compartir entre escenas.
Efectos de vérticeLa mitad de vértices de un material de malla: temblor a lo PS1, inflado, torsión y onda, con la luz intacta.
Gelatina 2DBlobs a lo LocoRoco: el gancho de vértices hace temblar el contorno y el de fragmento pinta color, brillo y cara.
Tramadodither() recorta cada canal a pocos pasos y esconde las bandas con un patrón ordenado, como las consolas de la época.
Posterizadoposterize() lleva cada color al paso más cercano de unos pocos: un degradado se convierte en bandas planas.
Paleta de una consolapaletteMatch() cambia cada color por el más cercano de una paleta: NES con 54 colores o Game Boy con cuatro verdes.
Gradación con LUTlutGrade() busca cada color en una tabla de gradación: atardecer, noche o sepia, y cuánto aplicar.
Pantalla CRTcrt() pone el fotograma en un televisor de tubo: líneas de barrido, máscara de fósforo, curvatura y viñeta.
Audio
Sonido y audio espacialuseLoadAudio carga un clip como una textura y useSound lo reproduce: efectos que se solapan, música en su canal y un sonido que cruza la pantalla con el pájaro.
Audio espacial 3DLos oídos están en la cámara de perspectiva y miran hacia donde mira: un sonido que da vueltas se oye todo alrededor.
Escenario sonoroUn nivel en cuatro capas de sonido: música en dos capas, un ambiente por zona, una pajarera con cono y una moneda. Los oídos van en el jugador.
Escenas
Primera escenaUna escena con un sprite y un useUpdate, repartida en tres ficheros: la anatomía de cualquier escena.
Aparecer y desaparecerObjetos que van y vienen mientras corre el juego: un tanque dispara balas con useSpawn y cada bala acaba su propia vida con destroy.
Varias escenasTres escenas registradas al crear el juego: solo arranca la primera, y se cambia entre ellas por su nombre.
Una escena dentro de otraUna escena es un objeto: la que corre el sistema de escenas es la que se dibuja, y con useSpawn es una parte más de otra.
Usar un packUn pack cargado como cualquier recurso (useLoadPack) y colocado dos veces (createPack), cada copia con su sitio y sus ajustes.
Pack: un kit de interfazUn pack que ofrece varias piezas (un panel, un botón, una insignia): tres copias de un mismo botón, cada una con su texto, avisando al juego con un evento.
Pack: lógica y escenasUn pack que ofrece una escena con su lógica: una sala para andar y coger monedas, colocada dos veces dentro de otra escena.
Escena desde un documentoLa misma sala desde JSON y a mano, una al lado de la otra: sceneFromDoc devuelve una función de escena normal.
Transiciones de escenafade, wipe, iris y pixelate sobre scene.change: el shader es la mitad fácil, el ciclo de vida es el resto.
Menú de pausaLanza un menú y pausa el mundo: una escena en pausa se sigue dibujando, y eso es lo que lo hace posible. Y cámara lenta.
Barra de cargaUna escena de carga pide 78 imágenes y sigue su progreso con useLoader; luego pasa a un nivel que usa unas pocas por su clave.
HUD con launchuseScene().launch corre una escena de HUD junto a la del juego, en paralelo, en vez de sustituirla.
Cambio de escenauseScene().change sustituye la escena actual por otra: título y juego se alternan con un temporizador.
Estado y scripts
Adjuntar un scriptUn comportamiento con nombre, escrito una vez y adjuntado a tres objetos con ajustes distintos.
Scripts que se componenTres comportamientos en un objeto, en tres ficheros y sin imports entre ellos: spin publica cómo pararlo y toggle lo alcanza por nombre.
Datos y watchuseData es estado de una parte de la escena, leído como lives.value; useWatch corre cuando cambia y una vez en el primer fotograma.
Datos compartidosUn useData pasado a tres partes de la escena: un HUD, una barra y el generador que lo cambia. Cada una lo vigila por su cuenta.
Vigilar una cargauseWatch sobre un recurso: la textura avisa cuando llega, así que el marcador se cambia con una función que corre dos veces.
Store y persistenciacreateGameStore repartido en ficheros (estado y acciones) y guardado en localStorage, así que la mascota sobrevive a recargar.
SeñalesUn canal de eventos a lo Godot: un botón emite con createGameSignal y una pantalla lejana reacciona con useSignal, sin referencia entre ellos.
Texto e interfaz
Nine-sliceUn marco a cualquier tamaño sin deformar sus esquinas: un sprite estirado junto a createNineSlice estirando, repitiendo y encajando.
Texto de mapa de bitsuseLoadFont carga una fuente de mapa de bits y createText escribe con ella, marcador en vivo incluido.
Galería de fuentesDos fuentes de mapa de bits libres a distintos tamaños y colores, y una cinta de texto que se desplaza.
Récords de recreativaLa tabla de récords de toda la vida, con la entrada del nombre por teclado.
Letras que bailanUna onda letra a letra, un arcoíris en cascada, un fallo de CRT y una cinta que se desplaza: cada carácter animado por su cuenta.
Menú de textoLos textos reciben los mismos eventos del puntero que los sprites: un menú que se ilumina al pasar por encima y cambia de escena.
Experimentos
TelaLa tela clásica: 1.040 puntos unidos por muelles. El ratón la empuja, al arrastrar se agarra y se rompe, y con mayúsculas se corta.
Túnel warpEl clásico de la demoscene: un tubo de alambre que se curva y cambia de color, y 700 estrellas que se estiran en estelas al saltar al hiperespacio.
Mode 7El suelo de F-Zero y Super Mario Kart, a los 320×224 de la SNES: una sola imagen del circuito, girada y estirada píxel a píxel por un material.
BandadaUn banco de 450 peces sin líder, que sigue tres reglas. El ratón es un depredador y un clic echa comida.
Plasma y metabolasDos clásicos de la demoscene en un solo material: un plasma que rota su paleta y seis manchas de lava que se funden, una de ellas pegada al ratón.
HogueraUna hoguera de noche en un claro: llamas, chispas que rebotan en el suelo y humo, una luz que parpadea y la luna proyectando sombras.
TentáculosUna criatura con ocho brazos de 24 articulaciones, resueltos por cinemática inversa: alcanzan el ratón y un clic la manda nadando.
OndasUn estanque visto desde arriba: cada gota lanza un anillo que refracta el fondo y brilla al pasar.
El juego de la vidaEl juego de la vida de Conway sobre 17.000 células, calculado entero en la tarjeta gráfica con dos texturas que se turnan.
El fuego de DoomEl fuego de Doom en PlayStation y Nintendo 64, con una palabra ardiendo, calculado en la tarjeta gráfica.
Fuegos artificialesCohetes que revientan en palmeras de chispas que chisporrotean al apagarse: tres ficheros .particles que se disparan entre sí.
TormentaUn pueblo bajo la lluvia: un clic en el suelo hace caer un rayo que lo ilumina todo, y el trueno llega más tarde cuanto más lejos cae.
CracktroUna intro de Amiga a 320×256: barras de cobre, un logo que rebota letra a letra, estrellas en tres capas, un texto ondulante y una música chiptune.