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.




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
¿Te interesa cómo está resuelto algo de aquí, o tienes un problema parecido?