Attractor
a rotating de Jong–style chaotic attractor sampled into ~98k fine dots a frame, which blur together into a soft radial bloom: the main example of drawPoint at volume (SDF)
- Run
swift run --package-path Examples Example-Motion-Attractor- Source
- Examples/Motion/Attractor/Sketch.swift
// Ported from @eaviles's sketch 2025.003. Reworked for Ollin's API.
import Foundation
import Ollin
/// A rotating de Jong–style attractor: a chaotic `(x, y)` recurrence whose state
/// carries over from one step to the next (and across frames), sampled into a
/// bloom of fine dots. The whole field spins with `time`, and each of the 512
/// spokes adds another turn, so the orbit smears into a soft radial flower.
///
/// This is the headline for `drawPoint`: ~98k dots a frame (512 × 191), each a
/// single SDF instance — per-point CPU work is one struct write. The dots are
/// small on purpose; the more of them, the denser and softer the bloom, and at
/// these sizes the disk fades by area so the field stays smooth rather than
/// aliasing into hard speckle.
@main
final class Attractor: Sketch {
let pointCount = 512
let iterations = 192
// The recurrence state persists across frames (the orbit keeps evolving),
// so it lives on the sketch, not in `draw()`.
var x = 0.0
var y = 0.0
override func setup() {
noStroke()
}
override func draw() {
background(.black)
fill(.white)
pointSize(3 * scale)
translate(center)
let t = time * 0.002
rotate(t * 1000 * .pi / 180) // a slow overall spin
let step = Double.tau / Double(pointCount)
let reach = 200 * scale
for n in 0..<pointCount {
rotate(step) // one more turn per spoke
let nn = Double(n)
for _ in 1..<iterations {
let a = sin(.tau * t + nn - y) + cos(.tau * t + .tau * nn / 100 - x)
let b = cos(.tau * t + nn + y) + sin(.tau * t + .tau * nn / 100 + x)
x = a
y = b
drawPoint(reach * x, reach * y)
}
}
}
}