Points bouncing in boxes, joined in array order.
There are n points. Each one moves inside the frame at a constant base speed, so the only state is a position and a unit direction. Every frame each point advances by speed × dt and the frame edge is checked for a crossing.
When a point reaches a wall it is reflected about the wall's inward normal, then the reflected direction is rotated by a random angle. That is the whole collision model — no mass, no restitution, no gravity. The random rotation is what keeps the figure from settling into a repeating orbit.
A pure reflection plus a random angle can still leave the point sliding almost parallel to the wall, which looks like a stuck point. So after the rotation the inward component is clamped to a minimum fraction of the speed: the direction is split into a normal part and a tangential part, the normal part is raised to the floor, and the tangential part is rescaled so the total length stays 1. The point always leaves the wall at a real angle.
The polygon is the closed path through the points in array order: 0 → 1 → 2 → … → n−1 → 0. With two points that is a single segment; with more it is a closed figure that folds over itself as the points drift out of phase.
Edge gravity is not a force. It scales the time delta for each point by a function of its distance to the nearest wall. Inside the buffer band the delta is multiplied up, quadratically, so the point accelerates into the wall and leaves it fast; outside the band the delta is multiplied down, so the middle of the frame is crossed slowly. The curve is continuous at the band edge and flattens out at twice the band width, so there is no seam and no runaway. At 0 the multiplier is 1 everywhere and the speed is exactly constant. Edge buffer sets the band width as a fraction of the frame, so it scales with the viewport.
The colour of each edge is a function you can edit. It runs in a sandboxed iframe with no access to this page, its storage, or the network. Return a CSS colour, or { color, width } to override the stroke width for that edge.