• Options

The Arrowhead Curve is a curve that is tracing out the exact same shape as the Sierpinski Triangle. As such it has many of the awesome properties of the Sierpinski Triangle as well -> such as an area of 0.

Which to me is mindbending. Here we have a space-filling curve, that yet, not like the Hilbert Curve or the Sierpinski Curve has no area. Because it is "filling" the space taken up by a shape that does not take up space...

This back-and-forth of ideas to me is mind-bending. If you were to paint a Sierpinski Arrowhead Curve that would mean that you would need no paint. The same is true for the Sierpinski Carpet btw. as well.

To construct the Arrowhead Curve, you start with a line and then replace the line with 3 new lines connecting at $120°$ angles. Then repeat for each of the new lines created this way, and so on – recursively.

What you see here is an L-System Implementation, which is generated by the L-System Algorithm with the following settings:

const sierpinskiArrowhead: Ruleset = {
maxIterations: 11,
minIterations: 1,
color: "#FCD227",
axiom: "YF",
replace: {
X: "YF+XF+Y",
Y: "XF-YF-X",
},
angle: 60,
initLength: (sizes) => Math.min(sizes.width, sizes.height),
initTranslation: (sizes, initialLength) => {
const totalHeight = (initialLength * Math.sqrt(3)) / 2;
return [
sizes.width / 2 - initialLength / 2,
sizes.height - (sizes.height - totalHeight) / 2,
];
},
initRotation: (ctx, config) => {
if (config && config.iterations % 2 === 0) ctx.rotate(radians(60));
if (config && config.iterations < 5) ctx.lineWidth = 2;
},
divideFactor: 2,
};


This fractal, by its nature as an L-System, is also related to all the other L-System Fractals. A few you can check out: Sierpinski Curve, Fern 1, and the Lévy Curve.

The alphabet to instructions set used to draw this fractal are the same as for the other L-Systems:

const drawRules: Record<string, () => void> = {
V: () => {},
W: () => {},
X: () => {},
Y: () => {},
Z: () => {},
G: drawForward,
F: drawForward,
f: () => ctx.translate(0, -len),
"+": () => ctx.rotate(angle * rotationDirection),
"-": () => ctx.rotate(angle * -rotationDirection),
"|": () => ctx.rotate(180),
"[": () => ctx.push(),
"]": () => ctx.pop(),
"#": () => (ctx.lineWidth = weight += weightIncrement) ,
"!": () => (ctx.lineWidth = weight -= weightIncrement) ,
">": () => (len *= scale),
"<": () => (len /= scale),
"&": () => (rotationDirection = -rotationDirection),
"(": () => (angle += angleIncrement),
")": () => (angle -= angleIncrement),
};