📄 shapes-and-geometry.md

← Vault

Shapes and Geometry

2D Primitives

`javascript

point(x, y);

line(x1, y1, x2, y2);

rect(x, y, w, h); // default: corner mode

rect(x, y, w, h, r); // rounded corners

rect(x, y, w, h, tl, tr, br, bl); // per-corner radius

square(x, y, size);

ellipse(x, y, w, h);

circle(x, y, d); // diameter, not radius

triangle(x1, y1, x2, y2, x3, y3);

quad(x1, y1, x2, y2, x3, y3, x4, y4);

arc(x, y, w, h, start, stop, mode); // mode: OPEN, CHORD, PIE

`

Drawing Modes

`javascript

rectMode(CENTER); // x,y is center (default: CORNER)

rectMode(CORNERS); // x1,y1 to x2,y2

ellipseMode(CORNER); // x,y is top-left corner

ellipseMode(CENTER); // default — x,y is center

`

Stroke and Fill

`javascript

fill(r, g, b, a); // or fill(gray), fill('#hex'), fill(h, s, b) in HSB mode

noFill();

stroke(r, g, b, a);

noStroke();

strokeWeight(2);

strokeCap(ROUND); // ROUND, SQUARE, PROJECT

strokeJoin(ROUND); // ROUND, MITER, BEVEL

`

Custom Shapes with Vertices

Basic vertex shape

`javascript

beginShape();

vertex(100, 100);

vertex(200, 50);

vertex(300, 100);

vertex(250, 200);

vertex(150, 200);

endShape(CLOSE); // CLOSE connects last vertex to first

`

Shape modes

`javascript

beginShape(); // default: polygon connecting all vertices

beginShape(POINTS); // individual points

beginShape(LINES); // pairs of vertices as lines

beginShape(TRIANGLES); // triplets as triangles

beginShape(TRIANGLE_FAN);

beginShape(TRIANGLE_STRIP);

beginShape(QUADS); // groups of 4

beginShape(QUAD_STRIP);

`

Contours (holes in shapes)

`javascript

beginShape();

// outer shape

vertex(100, 100);

vertex(300, 100);

vertex(300, 300);

vertex(100, 300);

// inner hole

beginContour();

vertex(150, 150);

vertex(150, 250);

vertex(250, 250);

vertex(250, 150);

endContour();

endShape(CLOSE);

`

Bezier Curves

Cubic Bezier

`javascript

bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2);

// x1,y1 = start point

// cx1,cy1 = first control point

// cx2,cy2 = second control point

// x2,y2 = end point

`

Bezier in custom shapes

`javascript

beginShape();

vertex(100, 200);

bezierVertex(150, 50, 250, 50, 300, 200);

// control1, control2, endpoint

endShape();

`

Quadratic Bezier

`javascript

beginShape();

vertex(100, 200);

quadraticVertex(200, 50, 300, 200);

// single control point + endpoint

endShape();

`

Interpolation along Bezier

`javascript

let x = bezierPoint(x1, cx1, cx2, x2, t); // t = 0..1

let y = bezierPoint(y1, cy1, cy2, y2, t);

let tx = bezierTangent(x1, cx1, cx2, x2, t); // tangent

`

Catmull-Rom Splines

`javascript

curve(cpx1, cpy1, x1, y1, x2, y2, cpx2, cpy2);

// cpx1,cpy1 = control point before start

// x1,y1 = start point (visible)

// x2,y2 = end point (visible)

// cpx2,cpy2 = control point after end

curveVertex(x, y); // in beginShape() — smooth curve through all points

curveTightness(0); // 0 = Catmull-Rom, 1 = straight lines, -1 = loose

`

Smooth curve through points

`javascript

let points = [/ array of {x, y} /];

beginShape();

curveVertex(points[0].x, points[0].y); // repeat first for tangent

for (let p of points) {

curveVertex(p.x, p.y);

}

curveVertex(points[points.length-1].x, points[points.length-1].y); // repeat last

endShape();

`

p5.Vector

Essential for physics, particle systems, and geometric computation.

`javascript

let v = createVector(x, y);

// Arithmetic (modifies in place)

v.add(other); // vector addition

v.sub(other); // subtraction

v.mult(scalar); // scale

v.div(scalar); // inverse scale

v.normalize(); // unit vector (length 1)

v.limit(max); // cap magnitude

v.setMag(len); // set exact magnitude

// Queries (non-destructive)

v.mag(); // magnitude (length)

v.magSq(); // squared magnitude (faster, no sqrt)

v.heading(); // angle in radians

v.dist(other); // distance to other vector

v.dot(other); // dot product

v.cross(other); // cross product (3D)

v.angleBetween(other); // angle between vectors

// Static methods (return new vector)

p5.Vector.add(a, b); // a + b → new vector

p5.Vector.sub(a, b); // a - b → new vector

p5.Vector.fromAngle(a); // unit vector at angle

p5.Vector.random2D(); // random unit vector

p5.Vector.lerp(a, b, t); // interpolate

// Copy

let copy = v.copy();

`

Signed Distance Fields (2D)

SDFs return the distance from a point to the nearest edge of a shape. Negative inside, positive outside. Useful for smooth shapes, glow effects, boolean operations.

`javascript

// Circle SDF

function sdCircle(px, py, cx, cy, r) {

return dist(px, py, cx, cy) - r;

}

// Box SDF

function sdBox(px, py, cx, cy, hw, hh) {

let dx = abs(px - cx) - hw;

let dy = abs(py - cy) - hh;

return sqrt(max(dx, 0) 2 + max(dy, 0) 2) + min(max(dx, dy), 0);

}

// Line segment SDF

function sdSegment(px, py, ax, ay, bx, by) {

let pa = createVector(px - ax, py - ay);

let ba = createVector(bx - ax, by - ay);

let t = constrain(pa.dot(ba) / ba.dot(ba), 0, 1);

let closest = p5.Vector.add(createVector(ax, ay), p5.Vector.mult(ba, t));

return dist(px, py, closest.x, closest.y);

}

// Smooth boolean union

function opSmoothUnion(d1, d2, k) {

let h = constrain(0.5 + 0.5 * (d2 - d1) / k, 0, 1);

return lerp(d2, d1, h) - k h (1 - h);

}

// Rendering SDF as glow

let d = sdCircle(x, y, width/2, height/2, 200);

let glow = exp(-abs(d) * 0.02); // exponential falloff

fill(glow * 255);

`

Useful Geometry Patterns

Regular Polygon

`javascript

function regularPolygon(cx, cy, r, sides) {

beginShape();

for (let i = 0; i < sides; i++) {

let a = TWO_PI * i / sides - HALF_PI;

vertex(cx + cos(a) r, cy + sin(a) r);

}

endShape(CLOSE);

}

`

Star Shape

`javascript

function star(cx, cy, r1, r2, npoints) {

beginShape();

let angle = TWO_PI / npoints;

let halfAngle = angle / 2;

for (let a = -HALF_PI; a < TWO_PI - HALF_PI; a += angle) {

vertex(cx + cos(a) r2, cy + sin(a) r2);

vertex(cx + cos(a + halfAngle) r1, cy + sin(a + halfAngle) r1);

}

endShape(CLOSE);

}

`

Rounded Line (Capsule)

`javascript

function capsule(x1, y1, x2, y2, weight) {

strokeWeight(weight);

strokeCap(ROUND);

line(x1, y1, x2, y2);

}

`

Soft Body / Blob

`javascript

function blob(cx, cy, baseR, noiseScale, noiseOffset, detail = 64) {

beginShape();

for (let i = 0; i < detail; i++) {

let a = TWO_PI * i / detail;

let r = baseR + noise(cos(a) * noiseScale + noiseOffset,

sin(a) noiseScale + noiseOffset) baseR * 0.4;

vertex(cx + cos(a) r, cy + sin(a) r);

}

endShape(CLOSE);

}

`

Clipping and Masking

`javascript

// Clip shape — everything drawn after is masked by the clip shape

beginClip();

circle(width/2, height/2, 400);

endClip();

// Only content inside the circle is visible

image(myImage, 0, 0);

// Or functional form

clip(() => {

circle(width/2, height/2, 400);

});

// Erase mode — cut holes

erase();

circle(mouseX, mouseY, 100); // this area becomes transparent

noErase();

`