E.03 · Código abiertoOpen sourceFiguras de ChladniChladni figures
cos(nπx)cos(mπy) − cos(mπx)cos(nπy) = 0
Cien mil granos de arena sobre una placa que vibra: en cada golpe cambia el modo de vibración y la arena salta hasta dibujar sus líneas nodales.One hundred thousand grains of sand on a vibrating plate: on every hit the vibration mode changes and the sand jumps until it draws the nodal lines.
Escena del teaserScene from the teaser
// 01La cienciaThe science
Si se esparce arena sobre una placa de metal y se la hace vibrar, la arena salta en las zonas que se mueven y se acumula en las que quedan quietas: las líneas nodales. Cada frecuencia de vibración dibuja una figura distinta.
Ernst Chladni publicó estas figuras en 1787 y abrió el estudio de la acústica de placas. Detrás está la misma física de una cuerda de guitarra, pero en dos dimensiones: ondas estacionarias que solo existen en ciertos modos.
Sprinkle sand on a metal plate and make it vibrate: the sand bounces off the moving areas and gathers where the plate stays still, the nodal lines. Each vibration frequency draws a different figure.
Ernst Chladni published these figures in 1787 and started the study of plate acoustics. Behind them is the same physics as a guitar string, in two dimensions: standing waves that only exist in certain modes.
// 02Cómo se calculaHow it is computed
- Cada modo
(n, m)de una placa cuadrada se aproxima conf(x, y) = cos(nπx)·cos(mπy) − cos(mπx)·cos(nπy). Las líneas nodales son dondef = 0. - Hay 100 000 granos. Con cada cambio de modo, cada grano salta según cuánto vibra su punto: lejos en los antinodos y casi nada en las líneas que siguen quietas.
- Después cada grano baja hasta la línea nodal más cercana con 22 pasos de tipo Newton sobre
|f|²:x ← x − f·∇f / |∇f|². - Los modos avanzan (1,2) → (1,3) → (2,3) → (2,5) → (3,5) → (4,7) → (5,8), cada vez más complejos, uno por golpe de la canción.
- La placa se dibuja en 3D, con perspectiva y una cámara que orbita. En el teaser los granos nacen de los píxeles claros del último cuadro de Gray-Scott y al final se condensan en la hélice del ADN.
- Each mode
(n, m)of a square plate is approximated byf(x, y) = cos(nπx)·cos(mπy) − cos(mπx)·cos(nπy). The nodal lines are wheref = 0. - There are 100,000 grains. On each mode change, every grain jumps according to how much its point vibrates: far at the antinodes, barely at all on lines that stay still.
- Each grain then slides down to the nearest nodal line with 22 Newton-style steps on
|f|²:x ← x − f·∇f / |∇f|². - The modes go (1,2) → (1,3) → (2,3) → (2,5) → (3,5) → (4,7) → (5,8), more complex each time, one per hit of the song.
- The plate is drawn in 3D, in perspective, with an orbiting camera. In the teaser the grains are born from the bright pixels of the last Gray-Scott frame and end up condensing into the DNA helix.
// 03El códigoThe code
Este es el código que corre en el video, tal como está en el repositorio. Todo es función del tiempo: cualquier cuadro se puede calcular solo y sale igual.
This is the code that runs in the video, exactly as it is in the repository. Everything is a function of time: any frame can be computed on its own and comes out the same.
Los modos de la placa y la función cuyas raíces son las líneas nodales.The plate modes and the function whose zeros are the nodal lines.
const MODOS: [number, number][] = [[1, 2], [1, 3], [2, 3], [2, 5], [3, 5], [4, 7], [5, 8]];const TINTES = ["236,240,255", "255,232,204", "226,236,255", "214,226,255", "236,222,255", "200,244,236", "160,250,226"];const EV_CHL = [...new Set([...RITMO.motivo.filter((m) => m.t >= T_CHL - 0.01 && m.t < T_CHL + 2).map((m) => m.t), ...entre(BOMBOS, T_CHL + 2, S("adn"))])].sort((a, b) => a - b);const N_ARENA = 100000;const fChl = (n: number, m: number, x: number, y: number) => Math.cos(n * Math.PI * x) * Math.cos(m * Math.PI * y) - Math.cos(m * Math.PI * x) * Math.cos(n * Math.PI * y);
Cada grano baja por |f|² hasta la línea nodal más cercana.Each grain slides down |f|² to the nearest nodal line.
for (let it = 0; it < 22; it++) { const e = 1e-3; const f = fChl(n, m, x, y); const gx = (fChl(n, m, x + e, y) - fChl(n, m, x - e, y)) / (2 * e); const gy = (fChl(n, m, x, y + e) - fChl(n, m, x, y - e)) / (2 * e); const g2 = gx * gx + gy * gy + 1e-3; x = cl(x - ((f * gx) / g2) * 0.65, 0, 1); y = cl(y - ((f * gy) / g2) * 0.65, 0, 1); }
// 04RecrearloRecreate it
Con Node 20 y Chrome alcanza para sacar los cuadros de esta escena. El video completo, con la canción y todas las simulaciones, se arma con los pasos del README.
Node 20 and Chrome are enough to render the frames of this scene. The full video, with the song and every simulation, is built with the steps in the README.
# 1 · clonar e instalar · clone and install $ git clone https://github.com/4mser/bn-lectures-teaser.git $ cd bn-lectures-teaser $ npm ci # la arena nace del último cuadro de Gray-Scott · sand is seeded from Gray-Scott $ pip install -r requirements.txt && FORMATO=169 python herramientas/grayscott.py # 2 · cuadros sueltos de esta escena (16:9) · frames of this scene $ node herramientas/cuadros.mjs out/chladni 1930,1975 ClaseYT # 3 · o recorrerla en Remotion Studio · or scrub it in Remotion Studio $ npm run dev