Astra ha aprendido a plasmar muy bien lo que tengo en mente, tanto en las mecánicas del juego como en la dirección artística. Lo he estado usando en Codex para crear Void Explorer, un juego de exploración espacial en el que puedes viajar desde estrellas lejanas hasta la superficie de mundos alienígenas.
Recopilación de escenas de juego de Void Explorer.
El juego tiene 2048 sistemas estelares y más de 10 000 planetas generados de forma procedural, incluidos mundos del tamaño de la Tierra. Cada estrella visible forma parte del universo y puedes seleccionarla como destino. Puedes elegir un punto de luz a lo lejos y viajar hasta él.
Puedes acercarte a un planeta desde el espacio, atravesar su atmósfera y seguir descendiendo hasta sobrevolar la costa. Puedes aterrizar, salir de la nave, caminar por los alrededores y volver a despegar. Para que todo ese recorrido funcionara, tuve que resolver en conjunto los problemas de escala, terreno, controles y renderizado.
Incluí algunos de los prompts que usé durante el desarrollo. Los acorté y los edité para que fueran más claros. Muestran cómo describí lo que quería y cómo avanzó el trabajo técnico a partir de ahí.
Empieza por la experiencia de juego
En mis instrucciones iniciales describí lo que el jugador debía poder hacer:
Debería poder llegar a todo lo que veo. Mantén las distancias reales y ajusta la escala y la velocidad para que sea posible recorrerlas. Quiero volar desde el espacio, entrar en la atmósfera de un planeta y descender hasta el suelo. Los planetas pueden ser tan grandes como la Tierra, así que necesitaremos terreno procedural y un motor de renderizado que trabaje por bloques.
Así, Astra tenía restricciones concretas. Una estrella no podía ser solo un punto pintado en el fondo. Un planeta no podía convertirse en un nivel aparte cuando me acercaba. Había que recorrer distancias reales, y para que eso fuera viable recurrimos a dos formas ficticias de desplazamiento: el viaje por pulsos y la hiperpropulsión.
También usé la generación de imágenes para definir el aspecto del juego cuando aún llevaba poco tiempo de desarrollo. Los primeros diseños eran demasiado realistas. El siguiente estilo era demasiado simple. Esta fue una de mis correcciones:
Ahora quedó un poco demasiado simple. Necesitamos un punto medio: mejores colores, luz de neón y más contraste para evocar el espacio profundo. Muéstrame cómo se ve a gran velocidad, con estrellas y polvo alrededor de la nave.
Cuando quedé conforme con las imágenes, le pedí a Astra que las guardara y las usara como referencias para el estilo del juego. Ya sabíamos cómo queríamos que se vieran el vuelo orbital, el vuelo a gran velocidad, la entrada en la atmósfera y el aterrizaje. Con esas imágenes fue mucho más fácil evaluar la siguiente versión.

Esta ilustración conceptual generada definió la paleta de colores y el estilo visual del juego.
Deja que Astra proponga la arquitectura
Yo definí las restricciones y Astra propuso la implementación. La aplicación usa TypeScript y Vite, con Three.js para el renderizado. Así, el código controla directamente las mallas, los materiales, la iluminación y la geometría procedural, que concentran la mayor parte del trabajo visual del juego.
El motor de renderizado de la primera versión jugable usaba WebGL2. Más adelante pregunté si Three.js limitaba la calidad visual. Astra recomendó conservar la simulación y migrar el motor de renderizado a la arquitectura WebGPU de Three.js. Mantuvimos los sistemas del universo, la navegación y el terreno mientras cambiábamos la capa de renderizado.
El motor de renderizado usa los materiales basados en nodos de Three.js y Three.js Shading Language (TSL) para definir en código la atmósfera, el agua y los efectos de iluminación.
La generación de terreno se ejecuta en Web Workers para preparar la geometría fuera del hilo que procesa los controles y dibuja la escena. Las pruebas con Vitest cubren aspectos como la reproducibilidad de la generación, los cálculos con coordenadas y los contratos del sistema de terreno. Playwright pone a prueba el juego en un navegador. Así, Astra podía comprobar los sistemas subyacentes mientras yo seguía evaluando la experiencia de juego.
La dirección artística nos sirvió de guía durante todo el proceso. La atmósfera que rodea un planeta, el brillo de sus anillos, la luz de color de las estrellas y el efecto Neon Phosphor contribuyen al aspecto del juego. El filtro añade una textura de pantalla retro sin dificultar la lectura de los indicadores de navegación.

Captura del juego con el efecto Neon Phosphor activado.
Dale a Astra una forma de inspeccionar el juego y jugarlo
Yo seguía jugando, pero Astra también necesitaba formas de investigar un problema más allá de leer mi descripción. El juego expone una pequeña interfaz de JavaScript, window.__VOID_EXPLORER__, que las pruebas de navegador pueden consultar para conocer el estado actual: a qué cuerpo celeste me acerco, en qué modo de vuelo estoy, si el terreno está listo y qué cámara está activa. También ofrece contadores de renderizado y de carga progresiva que indican cuántas llamadas de dibujo, triángulos y tareas de terreno en cola hay, y cuántos datos de terreno hay en el búfer.
El juego tiene escenas de prueba identificadas por nombre para el vuelo orbital, el viaje por pulsos, el descenso atmosférico y el aterrizaje en la costa. Con ellas, Astra puede volver al punto de partida que necesita sin tener que atravesar el universo cada vez. Playwright puede cargar una escena, esperar a que el terreno esté listo, tomar una captura de pantalla y comprobar el estado del juego en ese momento. Otras pruebas recorren los trayectos con los controles reales y registran las posiciones y los cambios de estado mientras se ejecuta el juego. Así, preparar una escena de aterrizaje no sustituye la prueba de la maniobra en sí.
Estas pruebas cubren el aterrizaje, la salida de la nave, el desplazamiento a pie, el guardado y la recarga de la partida, el regreso a bordo y el despegue. Pueden detectar problemas que una captura por sí sola no revelaría, como una superficie de colisión que aún no está lista o una nave que salta de una posición a otra durante una transición.
También podía pedirle a Astra que inspeccionara la pestaña del navegador en la que estaba jugando. Cuando le pregunté si las nubes de Aurelia seguían siendo visibles, capturó lo que yo veía en ese momento y leyó la información de vuelo en pantalla. Eran comprobaciones puntuales. Astra no observaba continuamente cada fotograma del vuelo.
El proceso consistía en reproducir el problema, examinar las capturas y el estado del juego, seguir la ejecución del código pertinente, hacer un cambio y repetir la comprobación. Si hiciera otro juego, crearía estas herramientas desde el principio: algunas escenas reproducibles, contadores útiles de estado y rendimiento, y pruebas de navegador para las interacciones principales. Así, Astra puede investigar y probar los cambios por su cuenta mientras yo sigo evaluando el aspecto del juego y la respuesta de los controles.
Representa el universo a varias escalas
Tener miles de planetas no implica cargar miles de mallas detalladas. Cada planeta parte de una descripción que incluye su radio, su órbita, su atmósfera y una semilla. La semilla permite reproducir su terreno. El juego genera la geometría en torno a la zona a la que me acerco y puede volver a generar el mismo paisaje cuando regreso.
Las coordenadas requieren un cuidado similar. Las distancias de años luz y las de una persona de pie junto a una nave corresponden a escalas muy distintas. Si enviáramos esas coordenadas enormes directamente a la GPU, perderíamos la precisión que necesitamos cerca del suelo.
Astra separó la ubicación física de la posición que se usa para dibujar. El universo se divide en celdas grandes identificadas con números enteros, con desplazamientos locales más pequeños dentro de cada celda. Antes de renderizar, el juego resta la posición del observador para que la cámara permanezca en el origen y las coordenadas de los objetos cercanos sean pequeñas. Las distancias que se muestran y los tamaños relativos se mantienen coherentes.
Los elementos en movimiento también deben compartir una referencia temporal. Las estrellas, los planetas y las lunas siguen órbitas definidas por ecuaciones analíticas. El motor de renderizado calcula tanto sus posiciones como la del observador para un mismo instante de la simulación. Una nave estacionada permanece fija respecto del planeta mientras este gira. La iluminación se calcula a partir de las posiciones y los colores de las estrellas, así que los dos soles que veo ponerse en un sistema binario son las mismas estrellas que vi desde la órbita.
Haz que el descenso sea continuo
Vuelo desde el espacio hacia la superficie de una luna en Void Explorer.
La transición del espacio al suelo requirió muchos ajustes. Uno de mis prompts surgió al acercarme a un planeta con muy poco ángulo de descenso:
Cuando me acerco en una trayectoria casi paralela a la superficie de un planeta, todavía puedo entrar demasiado rápido, y el planeta casi desaparece mientras se carga el terreno. Tenemos que ajustar en conjunto la curva de velocidad y la carga progresiva del terreno. ¿Podría la atmósfera suavizar la transición entre el nivel de detalle que se usa a distancia y el terreno detallado? El planeta nunca debería desaparecer durante la aproximación.
Para las aproximaciones con poco ángulo, el controlador de vuelo ahora aplica un límite de velocidad específico. Lo calcula a partir de la altitud y de una velocidad orbital estimada según el radio y la gravedad del planeta. Más cerca del suelo, también toma muestras del terreno que la nave tiene por delante para ajustar el frenado.
El juego usa varios niveles de detalle o LOD. Visto desde lejos, un planeta es una esfera facetada de bajo costo de renderizado, llamada proxy. A medida que ocupa más espacio en la pantalla, el motor de renderizado añade detalle. Al acercarte a la superficie, se activa un terreno construido a partir de las seis caras de un cubo proyectadas sobre una esfera. Cada cara puede dividirse en cuatro cuadrados más pequeños, y cada cuadrado puede volver a subdividirse de la misma manera. La estructura resultante es un árbol cuaternario.
Así, el juego puede aumentar el detalle del terreno en el área visible y en la dirección de avance sin generar una superficie del tamaño de la Tierra con la resolución necesaria para recorrerla a pie. Cerca del suelo, pequeñas secciones de terreno aportan geometría más detallada alrededor de la nave y del jugador.
Todas esas representaciones toman muestras de los mismos datos del planeta. Una función compartida combina continentes, crestas montañosas, cráteres y accidentes del relieve de menor tamaño. Proporciona la elevación, la presencia de agua, el bioma y otros datos que se usan para generar el paisaje. Las mallas de bajo y alto detalle representan esos datos a distintas resoluciones y aplican los mismos criterios de color para que el planeta conserve su aspecto.
El paso de una representación a otra importa tanto como la generación. El planeta que se ve a lo lejos permanece visible hasta que están listas las seis caras del terreno de bajo detalle. Cada bloque de terreno permanece en su lugar hasta que están listos los cuatro bloques en los que se subdivide. Durante la transición, dos máscaras complementarias asignan cada píxel a la superficie anterior o a la nueva. Así se evita que todo el planeta se vuelva transparente mientras se carga su reemplazo.
La atmósfera cambia según la altitud física y las nubes se desplazan sobre el relieve del planeta. Ambas ayudan a dar continuidad entre la vista orbital y el paisaje. El motor de renderizado solo retira el terreno de bajo detalle en las zonas donde ya está listo el de mayor detalle. Las siluetas de las montañas aún pueden cambiar cuando aparece la geometría más detallada.
El aterrizaje impone un requisito más estricto. En la zona de contacto, el suelo visible, los triángulos de colisión y las superficies líquidas peligrosas deben provenir del mismo ciclo de generación y estar listos al mismo tiempo. Para el desplazamiento a pie, el juego usa Rapier en una simulación física local de pequeña escala. Por separado, la lógica de aterrizaje comprueba cómo se apoyan las patas de la nave en el terreno, la pendiente y el espacio libre entre la nave y el suelo.
Hay una limitación deliberada: los planetas usan campos de altura, con una sola elevación para cada dirección desde el centro hacia la superficie. Esto funciona bien para paisajes extensos, pero no permite representar cuevas, salientes de roca ni túneles destructibles.
Mide cuánto trabajo requiere un fotograma lento
Algunos de mis comentarios abarcaban tanto el aspecto visual como el rendimiento porque observaba ambos problemas durante el mismo vuelo:
¿Puedes revisar cómo cargamos y renderizamos un planeta mientras vuelo desde el espacio hacia el suelo? El planeta visto desde lejos y el terreno detallado tienen un aspecto distinto, y la transición es brusca, sobre todo cuando cambian los colores. Quiero entender qué causa esos saltos visuales y dónde podemos reducir el trabajo necesario para cargar más detalle, de modo que el descenso se vea mejor y sea fluido.
Astra usó los contadores del motor de renderizado de Three.js para examinar las llamadas de dibujo, los triángulos, las geometrías y las texturas. Una prueba con Playwright midió 90 intervalos entre fotogramas y, junto con esos recuentos, informó el promedio y los percentiles de los tiempos. Para investigar problemas visuales, las pruebas también podían comparar los píxeles renderizados con un efecto específico activado y desactivado. Por ejemplo, podían comparar el terreno con y sin la máscara que oculta las superficies superpuestas. Eso ayudó a aislar la causa de la desaparición del suelo sin depender solo de una captura de la escena en la que se veía el problema.
Una versión anterior de la nave mostró para qué servían estas mediciones. Al reemplazar la nave procedural por el primer modelo AURORA creado en Blender, aumentó la cantidad de triángulos de la escena, pero disminuyeron las llamadas de dibujo. Astra ejecutó la misma prueba orbital de 90 fotogramas antes y después del cambio con el backend de WebGPU:
| Medición | Antes | Después |
|---|---|---|
| Total de llamadas de dibujo de la escena | 119 | 77 |
| Total de triángulos de la escena | 48 809 | 61 092 |
| Intervalo promedio entre fotogramas | 251,48 ms | 199,26 ms |
Hicimos esta comparación en Chromium sin interfaz gráfica, con renderizado por software mediante SwiftShader, antes de crear la nave de cuatro alas que se muestra más abajo. La comparación mide el efecto del cambio en ese entorno de prueba, no la tasa de fotogramas en mi GPU. Las herramientas le dieron a Astra mediciones de tiempo del navegador, imágenes renderizadas y recuentos de recursos. No midieron los comandos individuales de la GPU ni los tiempos de ejecución de los shaders.
Astra investigó qué trabajo se hacía durante la carga y el descenso: cuánta geometría se generaba, cuántos datos se transferían entre los workers y el motor de renderizado, y con qué frecuencia se descartaban las tareas de terreno antes de que se aprovecharan sus resultados.
Uno de los cambios fue asignar a cada planeta lejano un nivel de detalle acorde con su tamaño en pantalla. Un planeta que ocupa toda la vista necesita una silueta bien definida desde el primer momento. Uno que ocupa menos de un píxel no necesita la misma geometría. En una comparación controlada de la escena inicial, el nuevo criterio usó 7040 triángulos para las representaciones proxy en lugar de 51 200. En ambos casos se usó el mismo generador de geometría, lo que permitió aislar el efecto de la decisión de carga.
Otra mejora conservó exactamente la misma cantidad de triángulos de terreno. Las mallas indexadas reutilizan los vértices que comparten los triángulos vecinos para no repetir sus datos de posición, color y vector normal. En la prueba con la calidad del terreno configurada en Alta, el tamaño total de los búferes transferidos para las seis capas de suelo bajó de unos 35 MB a 15 MB, con los mismos 241 952 triángulos. La generación del suelo y la de los elementos del paisaje también se separaron en tareas distintas. Así, la geometría del suelo podía estar lista sin esperar a que terminara la decoración.
El selector de terreno también hacía trabajo que luego se desperdiciaba. Podía solicitar bloques, cambiar de decisión, descartarlos y pedir otros en su lugar. Astra hizo más estables las decisiones sobre cuándo aumentar el detalle y solo subdividió un bloque cuando el presupuesto de recursos alcanzaba para los cuatro bloques resultantes. En una simulación controlada con latencia fija de los workers, tras seis segundos de descenso y tres segundos para que la escena se estabilizara, se descartaron 13 tareas en lugar de 6074.

En una simulación controlada con dos workers y una latencia simulada de 100 ms por worker, la cantidad de tareas programadas que se descartaron bajó de 6074 a 13. Esta medición evalúa la planificación de las tareas de terreno, no la tasa de fotogramas.
Los workers por sí solos no evitan todas las pausas. El mecanismo alternativo de generación de terreno en el hilo principal también necesitaba ceder el control. Astra dividió la generación en pasos que se podían pausar y reanudar, con un presupuesto de unos 4 ms por fotograma. Así, una tarea grande de terreno no tenía que completarse de una sola vez sin interrupciones. El motor de renderizado también limita la resolución del mundo por separado de la interfaz, de modo que el texto de navegación sigue siendo nítido cuando se reduce la calidad visual.
Estas mediciones del terreno muestran que se generó menos geometría, se transfirieron menos datos y se descartaron menos tareas. No son pruebas de la tasa de fotogramas del hardware. Sigue siendo importante jugar en el navegador para evaluar la compilación de shaders, la transferencia de datos a la GPU, el movimiento y el aspecto real de la transición.
Mi aporte fueron las observaciones que hice al jugar: qué se sentía lento, qué se veía mal y qué quería mejorar. Astra siguió la ejecución del código, escribió scripts para reproducir las pruebas de terreno y registró las mediciones. Cuando aprobé el enfoque, implementó los cambios y volvió a ejecutar las mismas pruebas para comparar los resultados. Astra se encargó de la investigación y la implementación sin que yo tuviera que indicarle cada paso, mientras yo seguía evaluando cómo se veía el juego y cómo se sentía al jugarlo.
Convierte el arte conceptual en recursos para el juego
La mayor parte del universo se genera con código: los planetas, el terreno, las nubes, los anillos y las estrellas. La nave del jugador es el principal recurso 3D modelado por separado, y para crearla seguí otro proceso.
Usé ilustraciones conceptuales generadas e imágenes renderizadas en Blender para revisar la nave antes de incorporarla al juego. Cuando las alas no coincidían con lo que tenía en mente, pedí referencias que me sirvieran mejor:
Genera vistas claras de esta nave desde varios ángulos. Presta atención a las alas delanteras y traseras. Usaremos esas imágenes para rehacer el modelo 3D. No me gustan las alas unidas y redondeadas del modelo actual.
Elegí la referencia que tenía cuatro alas separadas, una forma simétrica y luces rosas en las puntas. Luego le pedí a Astra que creara en Blender un modelo nuevo con el mismo estilo artístico del juego y que lo incorporara al juego.
Para ello hubo que convertir la referencia en geometría, revisar la silueta y los materiales, y preparar el recurso para usarlo durante la ejecución. El archivo fuente de Blender tiene 193 mallas editables. La nave exportada tiene 14 968 triángulos, agrupados en ocho lotes de materiales opacos. Yo podía pedir más detalle en el modelo mientras Astra mantenía bajo control el costo de renderizar la versión exportada.

El diseño generado de la nave que aprobé.

Imagen renderizada en Blender del modelo que se usa en el juego.
Experimenta con el agua procedural
También pasé mucho tiempo experimentando con el agua en Sunwake, un juego en el que pilotas una lancha pequeña por un océano procedural. Quería olas facetadas, movimientos fluidos y los colores de un vitral. Astra creó en Three.js un motor de renderizado a medida para el agua. Un mismo modelo de oleaje determina tanto el aspecto del mar como la flotabilidad de la lancha. El casco se eleva, cabecea y se balancea con las olas. Una simulación local propaga las ondulaciones y la espuma, y la lancha deja estelas y levanta salpicaduras. Más adelante le pedí a Astra que creara una lancha más detallada en Blender y la incorporara al juego. Es el mismo enfoque que en Void Explorer: un entorno procedural y un vehículo modelado por separado que interactúan a través de la simulación.

Sunwake combina un océano procedural con una lancha modelada en Blender.
En Hollowflux exploré otra posibilidad con el agua. Es un pequeño juego de rol de acción en 2D ambientado en torno a un río subterráneo luminoso. Las cuevas, los personajes y el equipo se dibujan con código, sin importar hojas de sprites. Le pedí varias veces a Astra que el agua reaccionara de forma más convincente al caminar, hacer un movimiento rápido o atacar. Una cuadrícula de celdas registra la altura del agua, las corrientes, la espuma y la carga eléctrica. Los pasos producen ondulaciones, las estocadas de lanza abren estelas estrechas y los golpes de martillo generan ondas circulares. Las corrientes forman remolinos junto a las orillas y arrastran la espuma río abajo. Ese mismo flujo empuja al jugador y a los enemigos. El agua también influye en el combate: la descarga de una anguila se propaga por las zonas de agua conectadas entre sí, así que el jugador puede protegerse de ella si pisa una roca seca.

Hollowflux dibuja sus gráficos con código y el agua reacciona al movimiento y al combate.
Crear y compartir juegos
Lo que me gusta de trabajar con Astra es que puedo empezar por la experiencia que quiero crear, usar imágenes para concretar el estilo visual y darle mi opinión después de jugar. Si le digo que un planeta desaparece, eso puede llevar a cambios en la carga progresiva, la geometría y el movimiento. Si le pido que el agua se comporte de forma más convincente, el resultado puede ser una simulación que determine tanto su aspecto como su efecto en el juego. Me sigue tocando decidir si la experiencia se siente como quiero, pero Astra puede plasmar esas decisiones en el código, los recursos y las pruebas.
Compartir un juego de navegador también es sencillo. Con el complemento Sites, puedes pedirle a Astra lo siguiente:
Publícalo con acceso público y cualquiera podrá jugar directamente en su navegador.
Puedes jugar Void Explorer, Sunwake y Hollowflux en tu navegador.
Si tienes una idea para un juego, prueba a crear una pequeña versión jugable con Astra. Empieza por un aspecto que quieras que se sienta bien al jugar, dale a Astra algunas referencias visuales y prueba el resultado. Basta con una lancha, una habitación o una sola interacción para empezar. Juega, describe con precisión qué quieres cambiar y sigue desarrollando el juego a partir de ahí.