Ollin

Totem

a symmetric "computer totem" after the figures of the book's "Circles" chapter. It is assembled from Ollin's analytic SDF primitives. Around the core circle/ring/moon set it adds a horseshoe crown and ears, a parabola finial, a tunnel torso, a blobby-cross heart, cool-S ornaments, tapered-capsule legs, and a stairs pedestal.

Run
swift run --package-path Examples Example-Recreations-OsamuSato-Totem
Source
Examples/Recreations/OsamuSato/Totem/Sketch.swift
//  Recreation after Osamu Sato — "The Art of Computer Designing: A Black and
//  White Approach" (1993, Graphic-Sha), a book of designs built entirely from
//  basic vector shapes. This is a homage to the totemic figures of its Chapter 4
//  ("Circles"), where a deity is assembled from circles, crescents, and eyes in
//  bold black with a single red accent. An original Ollin interpretation built
//  from the book's vocabulary — not ported from its disk. A homage, not a
//  reproduction, and not affiliated with or endorsed by the artist.

import Foundation
import Ollin

/// A symmetric "computer totem" after Osamu Sato — the whole figure is assembled
/// from Ollin's analytic SDF primitives, leaning on the newer novelty shapes as
/// totem parts: a `horseshoe` crown and ears, a `parabola` finial cap, a
/// `tunnel` torso, a `blobbyCross` heart, a `roundedX` brow, `coolS` arm
/// ornaments, tapered `unevenCapsule` legs, and a `stairs` pedestal — around the
/// core `circle`/`ring`/`moon`/`triangle` set.
///
/// Sato's prints are still; Ollin's default is motion, so the totem comes alive:
/// it *breathes* (a slow scale pulse), its eyes pulse, and its bead-chain arms
/// lift and *wave*. Everything is mirrored about the vertical axis — the left and
/// right halves are drawn once and reflected — so it waves with both arms at once
/// and stays symmetric. Tune the motion with the `breath` / `gaze` / `wave` parameters.
@main
final class Totem: Sketch {
    @Param(0...1) var breath = 0.5     // how much the figure breathes
    @Param(0...1) var gaze = 0.5       // how much the eyes pulse
    @Param(0...1) var wave = 0.7       // how big the arms' wave is

    /// Sato's accent — a warm scarlet against black and white.
    let sato = Color(red: 0.85, green: 0.09, blue: 0.16)
    let ink = Color.black

    override func setup() {
        noStroke()
    }

    override func draw() {
        background(Color(white: 0.96))
        let s = scale
        let cx = width / 2
        let cy = height / 2
        // Local length unit: canvas-relative, so the totem holds at any size.
        func u(_ v: Double) -> Double { v * s }

        // Breathe about the figure's center.
        let pulse = 1 + 0.02 * breath * sin(time * 1.4)

        withState {
            translate(cx, cy)
            scale(pulse, pulse)
            // From here the origin is the figure center; +x right, +y down. Y runs
            // roughly -430 (crown) … +430 (pedestal).

            pedestal(u)
            legs(u)
            torso(u)
            arms(u)
            crown(u)
            head(u)
        }
    }

    // MARK: Parts (top to bottom in the figure; drawn back-to-front)

    /// The crown: a wide red crescent opening up, finial eye on a bead stalk above
    /// it, and a small black horseshoe "ear" on each side.
    private func crown(_ u: (Double) -> Double) {
        // Horseshoe ears, flanking the head, opening outward.
        fill(ink)
        for side in [-1.0, 1.0] {
            withState {
                translate(side * u(208), u(-250))
                rotate(side * .pi / 2)        // open toward the sides
                drawHorseshoe(0, 0, u(46), u(30), gap: 1.5)
            }
        }

        // Red crescent crown (concave side up), with dot horns and a center eye.
        fill(sato)
        withState {
            translate(0, u(-300))
            rotate(-.pi / 2)                  // moon opens +x by default → rotate up
            drawMoon(0, 0, u(150), u(140), u(58))
        }
        for side in [-1.0, 1.0] { drawCircle(side * u(132), u(-322), u(26)) }
        eye(u, 0, -262, 34, red: true)

        // Finial: a little parabola cap over an eye on a short bead stalk.
        fill(ink)
        beadColumn(u, x: 0, y0: -360, y1: -402, count: 3, r: 9)
        eye(u, 0, -420, 16)
        fill(sato)
        drawParabola(u(0), u(-446), u(46), u(30))
    }

    /// The face: a three-eyed mask — two black eyes flanking a red rounded-X
    /// "third eye".
    private func head(_ u: (Double) -> Double) {
        let p = 1 + 0.12 * gaze * sin(time * 2.0)   // eye pulse
        for side in [-1.0, 1.0] { eye(u, side * 78, -130, 38 * p) }
        fill(sato)
        drawRoundedX(u(0), u(-130), u(46), u(15))
    }

    /// The torso: a bold black tunnel (archway) body with a red blobby-cross heart,
    /// joined to the head by a short bead neck.
    private func torso(_ u: (Double) -> Double) {
        fill(ink)
        beadColumn(u, x: 0, y0: -40, y1: 8, count: 3, r: 13)
        drawTunnel(u(0), u(70), u(240), u(300))
        fill(sato)
        drawBlobbyCross(u(0), u(60), u(52))
        // Cool-S ornaments, cut in white inside the torso below the heart (mirrored).
        fill(.white)
        for side in [-1.0, 1.0] {
            withState {
                translate(side * u(58), u(140))
                scale(side, 1)                // mirror the asymmetric S
                drawCoolS(0, 0, u(66))
            }
        }
    }

    /// Arms: each one a bead chain raised from the shoulder that *waves* — the
    /// forearm sweeps from the elbow on a loop, ending in a ring "hand". Both arms
    /// move in mirror, so the figure stays symmetric.
    private func arms(_ u: (Double) -> Double) {
        fill(ink)
        // Forearm angle from straight up, swinging side to side over time.
        let theta = 0.3 + 0.6 * wave * sin(time * 3.0)
        let reach = 120.0
        for side in [-1.0, 1.0] {
            let shoulder = Vector2(side * 96, -30)
            let elbow = Vector2(side * 232, -40)          // raised out to the side
            let hand = Vector2(elbow.x + side * reach * sin(theta),
                               elbow.y - reach * cos(theta))
            wavingArm(u, shoulder: shoulder, elbow: elbow, hand: hand)
            eye(u, hand.x, hand.y, 28)
        }
    }

    /// Beads along the quadratic curve shoulder → elbow → hand, a ripple traveling
    /// down the chain and the radius easing from a fat shoulder to a slim wrist.
    private func wavingArm(_ u: (Double) -> Double, shoulder: Vector2, elbow: Vector2, hand: Vector2) {
        let count = 7
        for i in 0...count {
            let t = Double(i) / Double(count)
            let mt = 1 - t
            let p = shoulder * (mt * mt) + elbow * (2 * mt * t) + hand * (t * t)
            let shimmer = 1 + 0.1 * sin(time * 4 + t * 7)
            let r = (22 + (12 - 22) * t) * shimmer
            drawCircle(u(p.x), u(p.y), u(r))
        }
    }

    /// Legs: tapered capsules from the hips to ring "feet".
    private func legs(_ u: (Double) -> Double) {
        fill(ink)
        for side in [-1.0, 1.0] {
            drawUnevenCapsule(Vector2(side * u(70), u(210)),
                              Vector2(side * u(120), u(372)), u(40), u(26))
            eye(u, side * 120, 380, 46)
        }
    }

    /// A stepped pyramid pedestal: a staircase ascending toward the center on each
    /// side (mirrored), so they meet in a peak.
    private func pedestal(_ u: (Double) -> Double) {
        fill(ink)
        for side in [-1.0, 1.0] {
            withState {
                translate(0, u(404))
                scale(side, 1)
                drawStairs(u(-68), 0, u(34), u(22), steps: 4)   // meet flush at center
            }
        }
    }

    // MARK: Building blocks

    /// A concentric "Sato eye": filled disk, white iris, ink pupil.
    private func eye(_ u: (Double) -> Double, _ dx: Double, _ dy: Double, _ r: Double, red: Bool = false) {
        fill(red ? sato : ink); drawCircle(u(dx), u(dy), u(r))
        fill(.white);           drawCircle(u(dx), u(dy), u(r * 0.55))
        fill(ink);              drawCircle(u(dx), u(dy), u(r * 0.24))
    }

    /// A vertical stack of equal dots (a bead "stalk").
    private func beadColumn(_ u: (Double) -> Double, x: Double, y0: Double, y1: Double, count: Int, r: Double) {
        for i in 0..<count {
            let t = count > 1 ? Double(i) / Double(count - 1) : 0
            drawCircle(u(x), u(y0 + (y1 - y0) * t), u(r))
        }
    }

}

↑↓ move ↩ open