A readable, browser-based lava lamp simulation for learning how a small computational fluid model is assembled.
Live simulator: https://laval.val.run/
Open src/simulation/step.js. It contains the complete authoritative frame:
export function stepLavaLamp(state, settings) {
const deltaTime = settings.timeStep / settings.substeps;
for (let substep = 0; substep < settings.substeps; substep++) {
updateParticleTemperatures(state, settings, deltaTime);
applyParticleVolumePressure(state, settings, deltaTime);
applyParticleForces(state, settings, deltaTime);
projectParticleMotion(state, settings);
moveParticles(state, deltaTime);
rasterizeParticles(state);
}
return measureSimulation(state);
}
Every operation accepts ordinary simulation data. Physics modules do not read sliders, draw the canvas, change buttons, or know which UI is running them.
config.js— choose a grid width, height, and cell size.grid.js— map two-dimensional coordinates to flat arrays.settings.js— define plain numerical model parameters.state.js— create particles and the grid fields.geometry.js— define the tapered vessel and particle collisions.temperature.js— heat particles at the bottom and cool them elsewhere.particles.js— add buoyancy, cohesion, volume pressure, motion, and rasterization.projection.js— deposit particle velocity to the grid, reduce divergence, and sample it back.diagnostics.js— measure the result without changing it.step.js— compose those operations into one frame.renderer.jsandapp.js— connect the core to a canvas and controls.
src/ browser/ app.js thin DOM and animation controller renderer.js canvas output config.js grid dimensions grid.js coordinate helpers simulation/ settings.js state.js geometry.js temperature.js particles.js projection.js diagnostics.js step.js ui/ document.ts styles.ts contracts.ts TypeScript description of the model
state contains values that evolve: particle positions, velocities, temperatures, grid velocity, pressure, and time.
settings contains inputs selected before or during a run: heater strength, cooling, cohesion, pressure strength, target density, and timestep controls.
The UI changes settings. The simulation changes state.
Wax is a fixed collection of particles. Each particle stores position, velocity, and normalized temperature. Heating changes buoyancy. Pairwise cohesion attracts nearby particles. Neighbor-density pressure prevents them from collapsing into one point.
Particle velocity is deposited bilinearly onto an Eulerian grid. Pressure projection reduces divergence on that grid, then the corrected velocity is sampled back to the particles. Analytic collisions keep particles inside the tapered vessel.
The model is deterministic and educational. Its normalized coefficients are not calibrated material constants, and its pressure calculation is an SPH-style teaching approximation rather than a production CFD solver.