"""Tessel's skin mosaic: gold seams of an irregular tessellation, as a tattoo-layer texture (RGBA PNG). python mosaic.py OUT.png [--size 1024] [--tile 46] [--seed 7] [--preview PREVIEW.png] Voronoi cells from Poisson-disc seeds (even but not regular), wrapped horizontally so the left and right edges meet. Seams are gold with soft edges and a gentle width variation along their length, like kintsugi; everything else is transparent so the skin shows. --preview composites it over a skin tone for looking at. Written by Claude Opus 5.5, 2026-10-09. """ import argparse import numpy as np from PIL import Image GOLD = np.array([212, 168, 84], dtype=np.float32) # warm, not brassy-orange HIGHLIGHT = np.array([246, 222, 160], dtype=np.float32) def poisson(size, r, rng, tries=30): """Bridson's Poisson-disc sampling on a size x size square, wrapped in x.""" cell = r / np.sqrt(2) gw = int(np.ceil(size / cell)) grid = -np.ones((gw, gw), dtype=int) pts, active = [], [] def ok(p): gx, gy = int(p[0] / cell), int(p[1] / cell) for dy in range(-2, 3): for dx in range(-2, 3): x, y = (gx + dx) % gw, gy + dy if 0 <= y < gw and grid[x, y] >= 0: q = pts[grid[x, y]] ddx = abs(p[0] - q[0]) ddx = min(ddx, size - ddx) if ddx * ddx + (p[1] - q[1]) ** 2 < r * r: return False return True def add(p): pts.append(p) grid[int(p[0] / cell) % gw, int(p[1] / cell)] = len(pts) - 1 active.append(len(pts) - 1) add(rng.uniform(0, size, 2)) while active: i = active[rng.integers(len(active))] for _ in range(tries): a, d = rng.uniform(0, 2 * np.pi), rng.uniform(r, 2 * r) p = pts[i] + d * np.array([np.cos(a), np.sin(a)]) p[0] %= size if 0 <= p[1] < size and ok(p): add(p) break else: active.remove(i) return np.array(pts) def seam_field(size, pts): """d2 - d1 per pixel (distance to second-nearest minus nearest seed), wrapped in x.""" wrapped = np.concatenate([pts, pts + [size, 0], pts - [size, 0]]) ys, xs = np.mgrid[0:size, 0:size].astype(np.float32) n = len(pts) d1 = np.full((size, size), np.inf, np.float32) d2 = np.full((size, size), np.inf, np.float32) i1 = np.zeros((size, size), np.int32) i2 = np.zeros((size, size), np.int32) for k, (px, py) in enumerate(wrapped): if not (-size * 0.1 <= px <= size * 1.1): continue d = np.hypot(xs - px, ys - py) closer = d < d1 second = ~closer & (d < d2) d2 = np.where(closer, d1, np.where(second, d, d2)) i2 = np.where(closer, i1, np.where(second, k % n, i2)) d1 = np.where(closer, d, d1) i1 = np.where(closer, k % n, i1) return d2 - d1, i1, i2 def keep_mask(i1, i2, n, keep, rng): """Per pixel: is the seam between its two nearest cells one we keep? Drops some seams so the network branches and breaks off like kintsugi instead of closing every tile.""" table = rng.random((n, n)) < keep # only the upper triangle is read (lo < hi) lo, hi = np.minimum(i1, i2), np.maximum(i1, i2) return table[lo, hi] def wobble(size, rng, scale=90.0, octaves=3): """Smooth periodic-in-x noise in [0, 1] for varying the seam width.""" ys, xs = np.mgrid[0:size, 0:size].astype(np.float32) out = np.zeros((size, size), np.float32) for o in range(octaves): k = 2 ** o for _ in range(3): fx = rng.integers(1, 4) * k # integer cycles across x keeps it seamless fy = rng.uniform(0.5, 3) * k ph = rng.uniform(0, 2 * np.pi, 2) out += np.sin(2 * np.pi * fx * xs / size + ph[0]) * np.cos(2 * np.pi * fy * ys / size + ph[1]) / k out -= out.min() return out / out.max() def render(size, tile, seed, keep=0.6, wmin=0.9, wmax=2.3, opacity=0.85): rng = np.random.default_rng(seed) pts = poisson(size, tile, rng) gap, i1, i2 = seam_field(size, pts) width = wmin + (wmax - wmin) * wobble(size, rng) ** 1.5 # half-width of a seam in px, mostly near wmin core = np.clip((width - gap / 2) / 1.0, 0, 1) # soft edge ~1px kept = keep_mask(i1, i2, len(pts), keep, rng) if keep < 1 else 1.0 core = core * kept halo = np.clip((width * 2.2 - gap / 2) / (width * 1.6), 0, 1) ** 2 * 0.18 * kept # faint warmth beside the line alpha = np.clip(core * opacity + halo, 0, 1) shine = np.clip(core * (0.4 + 0.6 * wobble(size, rng)), 0, 1)[..., None] rgb = GOLD * (1 - shine * 0.5) + HIGHLIGHT * shine * 0.5 img = np.concatenate([rgb, (alpha * 255)[..., None]], axis=-1) return Image.fromarray(img.clip(0, 255).astype(np.uint8), "RGBA"), len(pts) def main(): ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("out") ap.add_argument("--size", type=int, default=1024) ap.add_argument("--tile", type=float, default=64, help="min distance between cell seeds, px") ap.add_argument("--seed", type=int, default=7) ap.add_argument("--keep", type=float, default=0.6, help="fraction of seams kept") ap.add_argument("--width", default="0.9,2.3", help="seam half-width range in px, min,max") ap.add_argument("--opacity", type=float, default=0.85) ap.add_argument("--preview") a = ap.parse_args() wmin, wmax = (float(v) for v in a.width.split(",")) img, n = render(a.size, a.tile, a.seed, a.keep, wmin, wmax, a.opacity) img.save(a.out) print(f"{a.out}: {n} cells") if a.preview: skin = Image.new("RGBA", img.size, (224, 186, 160, 255)) Image.alpha_composite(skin, img).convert("RGB").save(a.preview, quality=90) if __name__ == "__main__": main()