Qué estás viendo
Un campo de flujo es una función que, para cada punto del lienzo, devuelve una dirección. Las partículas no saben nada más: leen el ángulo que les corresponde, dan un paso y repiten. No hay masa, ni colisiones, ni fuerzas acumulándose, porque nada de eso se vería.
Todo lo interesante está en el campo. Por eso los tres patrones usan exactamente las mismas partículas y producen imágenes que no se parecen en nada.
El ruido tiene que ser continuo
La condición que lo decide todo es que dos puntos vecinos devuelvan ángulos parecidos. Si no, las partículas se dispersan en vez de fluir.
Eso descarta el hash directo de coordenadas que usa el grano de la esfera del sitio, que busca justo lo contrario: un valor distinto en cada píxel. Aquí se hashea una retícula y se interpolan los valores entre sus esquinas.
const u = smooth(x - Math.floor(x));
const v = smooth(y - Math.floor(y));
const w = smooth(z - Math.floor(z));
El smoothstep sobre el interpolante no es decorativo: la interpolación lineal es continua en el valor pero no en su pendiente, y esa discontinuidad se ve como una retícula de pliegues.
El error que costó encontrar
La primera versión interpolaba en X e Y y pasaba el tiempo directamente al hash. Como el tiempo avanza una fracción en cada fotograma, hash(x, y, z) devolvía un valor sin ninguna relación con el anterior: el campo se reconstruía entero sesenta veces por segundo.
El resultado era ruido gris, y no había parámetro que lo arreglara — porque las partículas no estaban siguiendo nada. Interpolar también el eje temporal es lo que convierte la deriva en una deformación lenta en lugar de un parpadeo.
La estela es la acumulación
El lienzo no se borra nunca. Cada fotograma pinta encima un rectángulo translúcido del color del fondo, así que un trazo recién dibujado está oscuro y uno de hace dos segundos casi se ha disuelto.
Eso da una relación que conviene tener presente: un trazo sobrevive alrededor de 1 / fade fotogramas y recorre speed píxeles en cada uno.
fade 0.055 · speed 1.1 -> 18 fotogramas, 20 px (un guión)
fade 0.012 · speed 1.6 -> 83 fotogramas, 133 px (una línea)
Con los primeros valores, mil partículas dibujaban mil guiones, que es una textura y no un campo. La diferencia entre las dos imágenes es esa aritmética, no el número de partículas.