Falling Grid, toxiclibs.js
A cloth hanging from pins and falling under gravity. toxiclibs.js simulates a grid of particles connected by springs with Verlet integration, and Charming draws the springs as links.
js
const replay = Inputs.button("Replay");js
replay;
const {Vec2D} = toxi.geom;
const {VerletPhysics2D, VerletParticle2D, VerletSpring2D} = toxi.physics2d;
const {GravityBehavior} = toxi.physics2d.behaviors;
const width = 640;
const height = 240;
const cols = 65;
const rows = 20;
const w = width / (cols - 1);
const world = new VerletPhysics2D();
world.addBehavior(new GravityBehavior(new Vec2D(0, 1)));
// A row of particles, pinned every four columns at the top.
const particles = Array.from({length: cols * rows}, (_, i) => {
const particle = new VerletParticle2D((i % cols) * w, 0);
if ((i % cols) % 4 === 0 && i < cols) particle.lock();
world.addParticle(particle);
return particle;
});
// Springs to the right and below neighbors.
const springs = particles.flatMap((particle, i) => {
const neighbors = [];
if (i % cols !== cols - 1) neighbors.push(particles[i + 1]);
if (i + cols < particles.length) neighbors.push(particles[i + cols]);
return neighbors.map((neighbor) => {
const spring = new VerletSpring2D(particle, neighbor, w, 0.25);
world.addSpring(spring);
return spring;
});
});
const renderer = cm.canvas({width, height});
const root = cm.flow().renderer(renderer);
requestAnimationFrame(function frame() {
world.update();
root.append(cm.clear, {fill: "white"});
root.data(springs).append(cm.link, {
x: (d) => d.a.x,
y: (d) => d.a.y,
x1: (d) => d.b.x,
y1: (d) => d.b.y,
stroke: "black",
strokeWidth: 2,
});
root.render();
requestAnimationFrame(frame);
});
document.body.append(renderer.node());