Paper tubes that look round on the table and square in the mirror behind them.
A recreation of Kokichi Sugihara's ambiguous cylinders, solved from scratch. Both the peephole eye and its mirror image sit on one horizontal line, so every plane through that line holds a ray from each eye: one aimed at the shape you want to see directly, one at the shape you want to see in the mirror. The two rays meet in a single 3D point, and sweeping the plane across the object traces the rim, a closed space curve that projects to a circle from one eye and a square from the other. The tube is that curve dropped straight down to the table, rendered with sorted, flat shaded polygons and a mirrored copy of the whole scene clipped to the glass. Step off the peephole and the rims turn into wavy bands threaded by the sight lines that made them.
Try it. Pick any two shapes for the selected tube (Direct and Mirror rows, or keys 1 to 7 and Shift with 1 to 7) and the solver builds a new impossible object. Click a tube to select it, drag to orbit away from the peephole, press Space or Spin 180 to turn the tubes around, and P to jump back to the peephole.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build Kokichi Sugihara's ambiguous cylinder illusion with JavaScript and the HTML canvas element: a paper tube that looks circular when you view it directly and square when you see it in a mirror behind it. 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:
- Write a tiny perspective camera with a project(x, y, z) function. The table is the plane y = 0 and a vertical mirror stands at z = -1.5.
- Put the eye E1 above and in front of the table. Its mirror image E2 is the same point with z reflected across the mirror plane, so seeing the object in the mirror is the same as seeing it from E2.
- The trick: E1 and E2 have the same height, so for a vertical line x = c on a reference plane y = h0, the ray from E1 through a point on target shape A and the ray from E2 through a point on target shape B lie in one plane and meet. Solve for the meeting point.
- Sweep c across the shape. For each c take the near and far points of a circle (seen from E1) and of a square (seen from E2), pair near with far, and intersect. That gives a closed rim curve.
- Draw the tube as quads from each rim point straight down to the table, sorted back to front, and draw the reflected tube inside the mirror rectangle using ctx.clip().
Once that works, make it beautiful:
- Flat shade the quads from a light direction, with a colored band at the rim, a soft contact shadow and a framed, faintly tinted mirror.
- Let the mouse drag the camera away from E1 so the rim turns into a wavy curve, and ease it back afterwards.
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 letting me pick other shape pairs like a heart and a circle, rotating the object 180 degrees to swap the two views, or drawing the sight lines from both eyes.