#### <sup>[Ollin](../../index.md) → [Documentation](../index.md) → [Drawing](index.md) → `Aperiodic tilings`</sup>

---

## Aperiodic tilings

This page covers four families of tilings. The tilings in each family either never repeat, or they turn a few local rules into one connected pattern.

- **Penrose tilings**, kites and darts, thick and thin rhombs.
- **Wang tiles**, edge-matching squares, where aperiodicity was first discovered.
- **Girih star patterns**, the polygons-in-contact strapwork of Islamic geometric art.
- **The spectre**, the einstein, a single tile that can only ever tile aperiodically.

All four return geometry, not draw calls. Each one returns typed tiles or contours, and those feed the same drawing, boolean, hatching, and SVG paths as every other shape. So all four work as plotter-ready line work too.

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="../../Guide/Images/07-Tiles/AperiodicTiles-dark.jpg">
  <img src="../../Guide/Images/07-Tiles/AperiodicTiles.jpg" alt="Four panels: Penrose kites and darts with colored arcs, Penrose rhombs, a teal star pattern woven over a honeycomb, and curved spectre tiles with a few orange ones" width="680">
</picture>

Penrose and spectre generation uses no random numbers, so the same call always lays the same patch. Girih is a pure function of its polygons. Wang tiling uses the seeded `random`, so a [`seed`](../generators/random.md#seed) reproduces the quilt. The periodic families are on the [tiling & layout](tiling.md) page. Every polygon on this page also composes with [`girihPattern`](#girihPattern), which decorates any edge-to-edge tiling.

### Contents

- [penroseTiling / Penrose](#penroseTiling)
- [wangTiling / WangTile / WangTiling](#wangTiling)
- [girihPattern / Girih](#girihPattern)
- [spectreTiling / Spectre](#spectreTiling)

<a name="penroseTiling"></a>

#### penroseTiling / Penrose

```swift
penroseTiling(_ variant: Penrose.Variant = .rhombs,
              in bounds: Rectangle? = nil,
              tileEdge: Double = 48,
              center: Vector2? = nil) -> [Penrose.Tile]
```

Returns the tiles of a Penrose tiling that covers `bounds`, which defaults to the whole canvas. There are two variants: `.kitesAndDarts` is P2, and `.rhombs` is P3, a thick 72° rhomb and a thin 36° one. The tiles are generated by substitution. A wheel of first-generation tiles at `center` is deflated until every edge is at most `tileEdge` long. The result is then merged into whole tiles and clipped to the bounds. `center` is where the five-fold "sun" sits, and it defaults to the bounds center.

Each `Penrose.Tile` carries:

| Member | Meaning |
| --- | --- |
| `kind` | `.kite` / `.dart` or `.thick` / `.thin`, the per-kind color hook. |
| `points: [Vector2]` | The four corners. The first is the head of the symmetry axis (the kite's nose, the dart's reflex corner, a rhomb's apex). |
| `shape` / `contour` | Fillable `Shape` / closed `Contour`. |
| `arcs: [Contour]` | The two matching-rule arcs. Their ends meet across every edge. |

```swift
for tile in penroseTiling(.rhombs, tileEdge: 36) {
    fill(tile.kind == .thick ? .indigo : .navy)
    drawShape(tile.shape)
}
```

The `arcs` are the classic decoration. Each tile carries two circular arcs, and their ends meet each edge at its golden section. That point is the same from both sides of the edge, so the whole tiling reads as a weave of continuous curves. Stroke only the arcs for the line-work look:

```swift
noFill(); strokeWeight(3)
for tile in penroseTiling(.kitesAndDarts, tileEdge: 60) {
    stroke(tile.kind == .kite ? .coral : .teal)
    for arc in tile.arcs { drawPolyline(arc.points, closed: false) }
}
```

The result is deterministic, because no randomness is involved. The same bounds and edge always lay the same tiles. Generation is capped at two million half-tiles. If `tileEdge` is far below what that cap allows, Ollin clamps it.

<a name="wangTiling"></a>

#### wangTiling / WangTile / WangTiling

```swift
wangTiling(_ tiles: [WangTile], columns: Int, rows: Int,
           attempts: Int = 20) -> WangTiling?
drawWangTiling(_ tiling: WangTiling, colors: [Color], in bounds: Rectangle? = nil)
```

Wang tiles are squares with a color on each edge. They are placed without rotation under one rule: touching edges must carry the same color. The colors in `WangTile(top:right:bottom:left:weight:)` are plain integers. These tiles are where aperiodicity was first found. Creative coding uses the same idea for the opposite purpose, as the classic texture-generation trick. In that use, a seeded scanline fill turns independent random picks into one connected, maze-like pattern.

`wangTiling` fills a `columns × rows` grid in scanline order, driven by the seeded `random`. Each cell is chosen from the tiles that match its west and north neighbors, and the choice is weighted by `weight`. `WangTiling.completeSet(colors: n)` builds the full set of `n⁴` tiles, which can never dead-end. A hand-built set can dead-end, so the fill is retried up to `attempts` times. A `nil` result means no attempt succeeded.

The result carries `tiles`, `columns`/`rows`, row-major `indices`, `tile(column:row:)`, and `tileIndex(column:row:)` for the index alone. `drawWangTiling` renders each cell as four triangles that meet at the center, one per edge in that edge's color (the classic picture). The `colors` array is indexed by edge color id:

```swift
seed(7)
if let quilt = wangTiling(WangTiling.completeSet(colors: 2), columns: 15, rows: 15) {
    drawWangTiling(quilt, colors: [.navy, .orange])
}
```

For roads, dungeons, or texture patches, read `tile(column:row:)` and draw your own cell content for each edge color. Neighbors are guaranteed to agree, which is what makes the pieces connect.

<a name="girihPattern"></a>

#### girihPattern / Girih

```swift
girihPattern(over polygons: [[Vector2]], angle: Double = 54) -> [Contour]
girihPattern(in polygon: [Vector2], angle: Double = 54) -> [Contour]
drawGirih(over polygons: [[Vector2]], angle: Double = 54)
```

`girihPattern` builds Islamic star patterns by the polygons-in-contact method, which is Hankin's technique in Kaplan's formulation. Lay any edge-to-edge tiling of polygons. Then start a pair of rays from the midpoint of each edge at the contact `angle`, in degrees. Grow every ray until it meets another, and the matched pairs become the strapwork strands. Remove the tiling, and the crossings that remain are the star pattern. The strands join seamlessly across tiles because both sides start from the same midpoints.

It works over any polygons: `Grid` squares, `HexGrid` cells, Penrose tiles, or the five classic girih tiles. The contact angle is the one main control. As it changes, the same tiling reads spiky, star-like, or woven:

```swift
let cells = hexGrid(columns: 9, rows: 8).cells.map(\.corners)
stroke(.white); strokeWeight(3); noFill()
drawGirih(over: cells, angle: 60)
```

`Girih.Tile` is the tile set of the medieval decagonal system. The five tiles are `.decagon`, `.pentagon`, the elongated `.hexagon`, `.bowtie`, and `.rhombus`. All five share an edge length, so any two compose edge to edge. Each offers unit `points`, a scaled and placed `points(edge:at:rotation:)`, and the composing form `points(onEdge:_:)`. That last form lays the tile's first edge exactly along a segment. Pass an existing tile's edge in reverse order, and the new tile lands against that edge on the other side:

```swift
let decagon = Girih.Tile.decagon.points(edge: 56, at: uv(0.5, 0.5))
var patch = [decagon]
for i in decagon.indices {
    let p = decagon[i], q = decagon[(i + 1) % decagon.count]
    patch.append(Girih.Tile.pentagon.points(onEdge: q, p))   // a flower
}
drawGirih(over: patch, angle: 54)   // 54° is the classic girih angle
```

The result is pure geometry with no randomness. The strands are open `Contour`s, so you can stroke them, hatch them, thicken them through the [shape booleans](geometry.md), or export them.

<a name="spectreTiling"></a>

#### spectreTiling / Spectre

```swift
spectreTiling(in bounds: Rectangle? = nil,
              tileEdge: Double = 26,
              curve: Double = 0) -> [Spectre.Tile]
```

The spectre is the einstein: one shape that tiles the plane and can never repeat. `curve: 0` gives Tile(1,1), the 14-sided polygon with unit edges on the 30° grid. Any nonzero `curve` bends every edge into the same alternating bump. That removes the tile's mirror symmetry and makes it strictly chiral, so it tiles only without reflections. Useful values run up to about 1, and 0.5 is close to the published look. A patch grows by the substitution system from the discovery paper until it covers `bounds`, with edges close to `tileEdge`.

Every tile in a patch is congruent with the others and has the same handedness. Each `Spectre.Tile` carries:

| Member | Meaning |
| --- | --- |
| `points` | The outline (14 corners straight, more when curved). |
| `metatile` | Which of the nine substitution types the tile descends from, as a `Spectre.Metatile`: `.gamma`, `.delta`, `.theta`, `.lambda`, `.xi`, `.pi`, `.sigma`, `.phi`, or `.psi`, after the Greek letters the paper names them by. This is the natural coloring key. |
| `isOdd` | Whether the tile is one of the rare mystic partners, which are rotated 30° from every other tile. |
| `shape` / `contour` | Fillable `Shape` / closed `Contour`. |

```swift
for tile in spectreTiling(tileEdge: 26, curve: 0.5) {
    fill(tile.isOdd ? .tomato : .ivory)
    drawShape(tile.shape)
}
```

The result is deterministic, so the same call always lays the same patch.

---

Also see [tiling & layout](tiling.md) for the periodic families (hex and triangle grids, subdivision, mazes). See [Truchet tiles](truchet.md) for the related family, where each tile's orientation is seeded, and [Wave Function Collapse](../generators/wavefunctioncollapse.md) for constraint solving beyond the scanline.
