ParquetDeformation
one tiling whose tile changes shape as you read across it, a soft pinwheel on one side and an interlocking key on the other, with the run between them sliding back and forth as a moving front (ParquetDeformation)
- Run
swift run --package-path Examples Example-Patterns-ParquetDeformation- Source
- Examples/Patterns/ParquetDeformation/Sketch.swift
import Ollin
/// A parquet deformation: one tiling whose tile changes shape as you read
/// across it, every piece still meeting its neighbors exactly. The trick is
/// that the geometry lives on the lattice's edges rather than on the tiles, so
/// the two tiles beside any edge are built from the same curve and the tiling
/// cannot come apart however far the shape drifts.
///
/// The run here is a front that travels. Behind it the tile is a soft
/// four-lobed pinwheel, ahead of it an interlocking square key, and the band
/// between holds every shape in between. The front slides back and forth, so
/// the sheet keeps turning one tile into the other and back, which is the
/// whole point of the form, laid out in space in the drawn original and in
/// time here.
///
/// The closure form of the builder is what moves it: it is handed a point and
/// answers how far along the run that point sits, so the front is one
/// `smoothstep` rather than anything the tiling has to know about.
///
/// Both faces draw: the tiles filled by the amount they were built at, and the
/// line-work over them, which visits each lattice edge exactly once.
@main
final class ParquetRun: Sketch {
override func draw() {
background(Color(hex: 0x14110F)) // near-black ground
let field = bounds.inset(by: .all(70 * scale))
let front = 0.5 + sin(time * 0.25) * 0.55 // where the run sits, now
let band = 0.55 // how wide the run is
let sheet = ParquetDeformation(
grid: Grid(in: field, columns: 15, rows: 15),
from: .wave(count: 1, depth: 0.22),
to: .tooth(depth: 0.2, width: 0.42)
) { point in
let u = (point.x - field.x) / field.width
return smoothstep(front - band / 2, front + band / 2, u)
}
let cool = Color(hex: 0x2E5E6B) // the wave end
let warm = Color(hex: 0xE0A33C) // the tooth end
noStroke()
for tile in sheet.tiles {
fill(Color.mix(cool, warm, tile.amount))
drawShape(tile.shape)
}
stroke(Color(hex: 0xF4EFE6)) // one pass over every edge
strokeWeight(1.6 * scale)
strokeJoin(.round)
for edge in sheet.edges {
drawPolyline(edge.points, closed: false)
}
}
}