An endless koi garden of {p,q} ponds tiling the Poincare disk, with fish circling.
A regular {p,q} tiling of the hyperbolic plane, where q p-sided ponds meet at every corner and the ponds shrink forever toward the rim. Nothing is drawn tile by tile: every pixel is folded into one small triangle with angles pi/p, pi/q and pi/2 by repeated reflections in a line, a second line and a circle orthogonal to the rim, then shaded from a single motif of koi, lily pads, stone rims and lotus flowers. Replaying the reflections backwards tells each pixel which fish it belongs to, which picks its colors. The view glides with true Mobius isometries of the disk, and the same picture can be pulled back to the band and upper half-plane models.
Try it. Drag to glide through the hyperbolic plane. Click to show the mirror lines. Use the chips (or M, P and Q, with Shift to go down, and T for presets) to switch models and change p and q. Arrow keys glide too.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an interactive hyperbolic tiling in the Poincare disk with JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a canvas that fills the window and draw a disk of radius R in the middle. Render the inside per pixel into a small ImageData buffer (about a third of the screen resolution) and scale it up with drawImage.
- Pick p = 5 and q = 4 (any p, q with 1/p + 1/q < 1/2 works). The fundamental triangle has angles pi/p at the origin, pi/2 and pi/q. Its three mirrors are the x axis, the line through the origin at angle pi/p, and a circle centered at (c, 0) with c = cos(pi/q) / sqrt(cos(pi/q)^2 - sin(pi/p)^2) and radius sqrt(c^2 - 1). That circle is orthogonal to the rim, so it is a hyperbolic straight line.
- For each pixel, repeat until nothing changes: if y < 0 flip y; if the point is past the angled line, reflect it across that line; if it is inside the circle, invert it in the circle. Count the reflections.
- Color the pixel by whether the count is even or odd. You should see the classic black and white triangle tiling crowding toward the rim.
Once that works, make it beautiful:
- Draw a motif inside the folded triangle (a ring around the origin, a flower at the corner) and soften its edges by the pixel's size, which shrinks by (1 - |w|^2) / (1 - |z|^2) as you fold.
- Let the mouse glide: keep a Mobius map z -> (a z + b) / (conj(b) z + conj(a)) and on drag compose it with the hyperbolic translation that takes the old pointer point to the new one.
- Add a slow autopilot glide so it moves on its own.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as the upper half-plane model, an Escher-style fish motif that only uses rotations, or animating p and q.