Breakout walk
inspired by Georg Nees, Achsenparalleler Irrweg1
A line of horizontal and vertical steps tangles inside a square, fainter the older it is, then escapes through one wall to a filled square.
Made with Claude Opus 5.5
- Technique
- line art
- Inspired by
- early computer art
- Shape
- Any screen
- Added
- 27 September 2026
Colours
- #1C1B1Abackground
- #DAD8CEforeground
- #CF6A4Caccent
Export
Notes
The walk comes from Georg Nees’ early plotter drawing Achsenparalleler Irrweg (axis-parallel maze): steps that alternate between horizontal and vertical, each of random length, inside a square. This one takes longer strides and fades with age, so its oldest steps are barely there and the last few before it leaves stand out. After about 500 steps it breaks out by the far wall.
Sources
- Georg Nees, Achsenparalleler Irrweg, 1964. ↑
Source code
wallpapers/polygonzug/design.py, 63 lines
"""A walk of alternating horizontal and vertical steps tangles inside a square, fading with age, until its last steps break out through one wall to a filled square."""
from itertools import count
from walldye import ACCENT, BG, UI, UI_HI, Canvas, P, design, mix
from walldye.geom import Affine
HALF = 340 # the walk stays inside a square of side 2 * HALF around the frame's origin
MIN_STEPS = 470
EXIT_LO, EXIT_HI = -100, 60 # where on the far wall the walk may break out
# tail: hesitant jogs off the far wall, then one confident run into the square
JOGS, DROPS, RUN = (10, 18, 30, 50), (54, 30, 16, 8), 260
# the knot's steps in age bands, oldest first, each a step stronger
AGES = ((0.0, 0.35), (0.35, 0.7), (0.7, 0.9), (0.9, 1.0))
TONES = (mix(BG, UI, 0.35), mix(BG, UI, 0.65), UI, UI_HI)
REACH = 0.66 # the run ends at least this far along the long side, so wide screens get a longer run
def step(v: float, n: float) -> float:
"""v moved by n; a step that would leave the square stops on the wall, or turns back if v is
already on it."""
if -HALF <= v + n <= HALF:
return v + n
if v in (-HALF, HALF):
return min(HALF, max(-HALF, v - n))
return min(HALF, max(-HALF, v + n))
@design(aspects="any")
def draw(s: Canvas) -> None:
# local +x is the break-out direction: rightwards on landscape, down on portrait
c = s.pick(landscape=(7 / 24, 0.5), portrait=(0.5, 0.33))
frame = Affine.frame(c, deg=0 if s.landscape else 90)
along = c.x if s.landscape else c.y
r = s.rng(1969)
x, y = r.uniform(-HALF + 100, HALF - 100), r.uniform(-HALF + 100, HALF - 100)
knot = [(x, y)]
# break out at the first horizontal step onto the far wall near mid-height, once the knot is dense
for i in count():
n = min(320, 24 + r.expovariate(1 / 110)) * r.choice((-1, 1))
if i % 2 == 0:
x = step(x, n)
else:
y = step(y, n)
knot.append((x, y))
if i % 2 == 0 and i + 1 >= MIN_STEPS and x == HALF and EXIT_LO <= y <= EXIT_HI:
break
tail = [(x, y)]
for h, v in zip(JOGS, DROPS, strict=True):
x += h
tail.append((x, y))
y += v
tail.append((x, y))
x = max(x + RUN, REACH * max(s.w, s.h) - along)
tail.append((x, y))
end = frame((x, y))
pts = frame.apply(knot)
for (a, b), tone in zip(AGES, TONES, strict=True):
s.stroke(
P().poly(pts[round(a * len(pts)) : round(b * len(pts)) + 1]), tone, 1.4, join="miter"
)
s.stroke(P().poly(frame.apply(tail)), ACCENT, 2.4, join="miter")
s.fill(P().rect(end.x - 6, end.y - 6, 12, 12), ACCENT)"""A walk of alternating horizontal and vertical steps tangles inside a square, fading with age, until its last steps break out through one wall to a filled square."""
from itertools import count
from walldye import ACCENT, BG, UI, UI_HI, Canvas, P, design, mix
from walldye.geom import Affine
HALF = 340 # the walk stays inside a square of side 2 * HALF around the frame's origin
MIN_STEPS = 470
EXIT_LO, EXIT_HI = -100, 60 # where on the far wall the walk may break out
# tail: hesitant jogs off the far wall, then one confident run into the square
JOGS, DROPS, RUN = (10, 18, 30, 50), (54, 30, 16, 8), 260
# the knot's steps in age bands, oldest first, each a step stronger
AGES = ((0.0, 0.35), (0.35, 0.7), (0.7, 0.9), (0.9, 1.0))
TONES = (mix(BG, UI, 0.35), mix(BG, UI, 0.65), UI, UI_HI)
REACH = 0.66 # the run ends at least this far along the long side, so wide screens get a longer run
def step(v: float, n: float) -> float:
"""v moved by n; a step that would leave the square stops on the wall, or turns back if v is
already on it."""
if -HALF <= v + n <= HALF:
return v + n
if v in (-HALF, HALF):
return min(HALF, max(-HALF, v - n))
return min(HALF, max(-HALF, v + n))
@design(aspects="any")
def draw(s: Canvas) -> None:
# local +x is the break-out direction: rightwards on landscape, down on portrait
c = s.pick(landscape=(7 / 24, 0.5), portrait=(0.5, 0.33))
frame = Affine.frame(c, deg=0 if s.landscape else 90)
along = c.x if s.landscape else c.y
r = s.rng(1969)
x, y = r.uniform(-HALF + 100, HALF - 100), r.uniform(-HALF + 100, HALF - 100)
knot = [(x, y)]
# break out at the first horizontal step onto the far wall near mid-height, once the knot is dense
for i in count():
n = min(320, 24 + r.expovariate(1 / 110)) * r.choice((-1, 1))
if i % 2 == 0:
x = step(x, n)
else:
y = step(y, n)
knot.append((x, y))
if i % 2 == 0 and i + 1 >= MIN_STEPS and x == HALF and EXIT_LO <= y <= EXIT_HI:
break
tail = [(x, y)]
for h, v in zip(JOGS, DROPS, strict=True):
x += h
tail.append((x, y))
y += v
tail.append((x, y))
x = max(x + RUN, REACH * max(s.w, s.h) - along)
tail.append((x, y))
end = frame((x, y))
pts = frame.apply(knot)
for (a, b), tone in zip(AGES, TONES, strict=True):
s.stroke(
P().poly(pts[round(a * len(pts)) : round(b * len(pts)) + 1]), tone, 1.4, join="miter"
)
s.stroke(P().poly(frame.apply(tail)), ACCENT, 2.4, join="miter")
s.fill(P().rect(end.x - 6, end.y - 6, 12, 12), ACCENT)
Run it yourself
$ git clone https://github.com/nickolaj-jepsen/walldye && cd walldye$ uv run walldye render polygonzug --theme fireproof -o polygonzug-fireproof-16x9.svg