Ollin

DifferentialGrowth

a closed ring relaxed under attraction, alignment, and repulsion, with long edges splitting, so it folds live into meanders like brain coral (DifferentialGrowth)

Run
swift run --package-path Examples Example-Patterns-DifferentialGrowth
Source
Examples/Patterns/DifferentialGrowth/Sketch.swift
import Ollin

/// Differential growth: a closed ring of nodes that grows and folds into
/// brain-coral line-work. Every step each node is pulled toward its path-
/// neighbors (attraction) and their midpoint (alignment) and pushed away from
/// every nearby node (repulsion); when an edge stretches past a threshold a new
/// node splits it, so the boundary lengthens and buckles as it expands.
///
/// It's a stateful stepper held across frames, seeded once so the same seed
/// grows the same form. The evolving line is ordinary geometry (`growth.nodes` /
/// `growth.contour`), so it feeds stroking, filling, the shape booleans,
/// hatching, and SVG export for the pen plotter.
@main
final class DifferentialGrowthSketch: Sketch {
    private let growth = DifferentialGrowth.ring(
        center: Vector2(540, 540), radius: 70, count: 40, seed: 7,
        maxSegmentLength: 8, repulsionRadius: 16,
        attraction: 0.18, repulsion: 0.6, alignment: 0.25,
        jitter: 0.4, growthRate: 0.9, maxNodes: 4500,
        bounds: Rectangle(x: 40, y: 40, width: 1000, height: 1000))

    override func draw() {
        growth.step(4)

        background(Color(hex: 0x0F1012))
        noFill()
        strokeWeight(1.6 * scale)
        strokeCap(.round)
        strokeJoin(.round)

        // Tint the line by how far each node has drifted from the center, so the
        // folds read as depth without the geometry jumping.
        let center = center
        let nodes = growth.nodes
        for i in nodes.indices {
            let a = nodes[i], b = nodes[(i + 1) % nodes.count]
            let d = a.distance(to: center) / 500
            stroke(Color.mix(Color(hex: 0x6FD3C7), Color(hex: 0xF2B705), min(d, 1)))
            drawLine(a, b)
        }
    }
}

↑↓ move ↩ open