Todos los proyectos

Enjambre — simulación de vida artificial en GPU

Miles de partículas de colores que se organizan solas en enjambres, células, anillos y ondas viajeras a partir de reglas simples de atracción y repulsión. Nadie programa los patrones: emergen. Debajo hay dos motores distintos, siete shaders y un grabador de vídeo vertical.

Rust · workspace de 4 cratesjun–jul 2026Ver el repositorio
12.717
líneas de Rust
7
shaders WGSL
4
crates en el workspace
41
commits
Enjambre en modo «mismo color»: cada color se agrupa formando anillos concéntricos
Modo «mismo color»: cada matiz se agrupa en anillos.
Matriz de fuerzas de Enjambre: la tabla de atracción y repulsión entre cada par de colores
La matriz de fuerzas: quién atrae a quién, y cuánto.
Estructuras en roseta de colores generadas por Enjambre en formato vertical
Rosetas emergentes, capturadas en el modo de vídeo 9:16.
Herramienta de encuadre de Enjambre para componer el vídeo vertical
El encuadre del vídeo se compone dentro de la propia app.

La regla, y lo que sale de ella

Cada partícula tiene un matiz en la rueda de color y siente una fuerza hacia las demás que depende de ese matiz y de la distancia. La configuración entera cabe en una matriz de fuerzas: quién atrae a quién y cuánto.

De ahí salen enjambres, células con membrana, cadenas y ondas viajeras. Ninguno de esos patrones está programado —no hay código que dibuje una célula—, y esa es exactamente la gracia del experimento.

Dos motores para el mismo modelo

El crate sim es la ruta CPU: macroquad para el render y rayon para paralelizar el cálculo de fuerzas entre partículas. Es la implementación de referencia, la que dice cuál es el comportamiento correcto.

El crate sim-gpu es la reescritura sobre wgpu 24 y winit 0.30, con la simulación entera en shaders de cómputo. Ahí es donde el número de partículas deja de ser el límite. panel es la interfaz de control en eframe/egui, un proceso aparte que habla con la simulación por IPC, y shared guarda lo común: el modelo, el protocolo, el audio y el vídeo.

Que convivan las dos rutas no es indecisión: la de CPU es el patrón contra el que se verifica la de GPU.

Los siete shaders

sim.wgsl calcula el paso de simulación y particles.wgsl dibuja el resultado. grid.wgsl resuelve la vecindad espacial —sin ella el cálculo sería cuadrático sobre el número de partículas—, params.wgsl comparte la configuración con la GPU, color.wgsl traduce matiz a color, photo.wgsl proyecta una imagen sobre el campo de partículas y post.wgsl cierra con el postproceso.

Todo se escribe a mano en WGSL contra wgpu, con bytemuck para cruzar las estructuras entre Rust y la GPU sin copias raras y pollster para resolver la inicialización asíncrona.

Música y vídeo, sin dependencias nativas

El enjambre reacciona a la música: shared/src/music.rs y shared/src/audio.rs hacen el análisis con realfft, una FFT pura en Rust —flujo espectral, detección de beats y bandas de frecuencia—. La elección es deliberada: no enlaza nada nativo, y por eso no repite el conflicto con ALSA que descartó cpal.

shared/src/video.rs decodifica vídeo por streaming lanzando ffmpeg como subproceso y consumiendo fotogramas RGBA con contrapresión: si el consumidor se retrasa, ffmpeg se pausa. La grabación sale en 9:16 a 1080×1920, pensada para publicarse tal cual.

Stack

Rustwgpu 24WGSLrayonegui / eframerealfftffmpeg

¿Te interesa cómo está resuelto algo de aquí, o tienes un problema parecido?