Serpent Ski

2026-10-15

Sierpiński Triangle via Chaos

Short one today, as my new job is keeping me busy. Here’s something fun:

  1. Start with an equilateral triangle.
  2. Pick a random point inside that triangle.
  3. Pick one of the three vertices and move halfway towards it.
  4. Make a mark.
  5. Repeat 3 & 4.

You end up with the Sierpiński Triangle by way of the awesomely-named Chaos Game.

Demo

Borrowing how to calculate a random point inside a triangle from this reference (remember when people used StackOverflow instead of LLMs?), here’s a demo. Hit Start/Stop to, well, start or stop, then Reset to start over. It’ll probably slow down once there are a lot of points, so caveat emptor.

Code plz

My Javascript code is short enough to include here; even unminified, it’s only 43 lines after formatting with biome.[1]

const [S, A, B, C] = ["serpent_ski", "ss_a", "ss_b", "ss_c"].map((i) =>
	document.getElementById(i),
);
const FILL = A.getAttribute("fill");
const XS = [A, B, C].map((c) => c.cx.baseVal.value);
const YS = [A, B, C].map((c) => c.cy.baseVal.value);
let [X, Y, ON] = [0, 0, null];
const new_xy = () => {
	const [u, v] = [Math.sqrt(Math.random()), Math.random()];
	X = (1 - u) * XS[0] + u * (1 - v) * XS[1] + u * v * XS[2];
	Y = (1 - u) * YS[0] + u * (1 - v) * YS[1] + u * v * YS[2];
};
document.getElementById("reset").addEventListener("click", () => {
	ON = clearInterval(ON);
	S.replaceChildren(A, B, C);
	new_xy();
});
document.getElementById("start_stop").addEventListener("click", () => {
	if (!ON) {
		new_xy();
		ON = setInterval(() => {
			const p = document.createElementNS(
				"http://www.w3.org/2000/svg",
				"circle",
			);
			const i = Math.floor(XS.length * Math.random());
			X += 0.5 * (XS[i] - X);
			Y += 0.5 * (YS[i] - Y);
			[
				["cx", X],
				["cy", Y],
				["r", 0.5],
				["fill", FILL],
				["opacity", 1],
			].forEach(([k, v]) => {
				p.setAttribute(k, v);
			});
			S.appendChild(p);
		});
	} else {
		ON = clearInterval(ON);
	}
});
  1. There are also some lines of HTML needed to set up the buttons and SVG to begin with. ↩