Communitygithub.com

dotslashsimran/perspective-illusion

Make a looping illustrated 3D video that plays with perception, the way Japanese illusion artists do (e.g. @garments__): a scene squashed flat by a telephoto lens morphs into deep perspective, things that looked side by side turn out to be at different depths, and objects quietly swap position while the view is flat. Also for recreating a reference illusion video, or a new scene (street, supermarket, station, room) in that style. Use when asked for a perspective/optical-illusion video, a "dolly zoom" or "flat to 3D" effect, or to recreate one of these clips.

What is perspective-illusion?

perspective-illusion is a Claude Code agent skill that make a looping illustrated 3D video that plays with perception, the way Japanese illusion artists do (e.g. @garments__): a scene squashed flat by a telephoto lens morphs into deep perspective, things that looked side by side turn out to be at different depths, and objects quietly swap position while the view is flat. Also for recreating a reference illusion video, or a new scene (street, supermarket, station, room) in that style. Use when asked for a perspective/optical-illusion video, a "dolly zoom" or "flat to 3D" effect, or to recreate one of these clips.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/dotslashsimran/simcraft/tree/HEAD/skills/perspective-illusion

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation


name: perspective-illusion description: Make a looping illustrated 3D video that plays with perception, the way Japanese illusion artists do (e.g. @garments__): a scene squashed flat by a telephoto lens morphs into deep perspective, things that looked side by side turn out to be at different depths, and objects quietly swap position while the view is flat. Also for recreating a reference illusion video, or a new scene (street, supermarket, station, room) in that style. Use when asked for a perspective/optical-illusion video, a "dolly zoom" or "flat to 3D" effect, or to recreate one of these clips.

Perspective illusion

Templates in templates/ are complete, working scenes, so start from one:

  • street.html is a Japanese street with poles, cones, a crossing and a red sky.
  • market.html is a Japanese supermarket with an aisle, end-caps, red baskets and light rows.

Both share the same camera rig, timeline and illustration pass. Only the scene section differs.

Setup (per project folder)

mkdir -p ~/Movies/edits/<date>-<name>/stills && cd $_
printf '{"type":"module"}' > package.json && npm i [email protected] [email protected]
cp ~/simcraft/skills/perspective-illusion/templates/{street.html,render.mjs} .
node render.mjs street.html x --stills=0.2,1,2,4,6     # check frames first (stills/st_<t>.png)
node render.mjs street.html out.mp4                     # 7 s loop, 1920x1080, 4-subframe motion blur (~2.5 min)

The trick, in four parts

  1. Lay the scene out along one long axis (a street or an aisle running away along -z), with things lined up behind each other: poles or columns at the same x, a building or back wall at the end. A 2° telephoto from 400 m flattens it all into one elevation. Lined-up poles stack into one, and long side walls vanish edge-on.
  2. Never tilt or turn the camera. It always faces straight down the axis, level, so verticals stay vertical. For "looking down" or "looking up", use lens shift (H, the horizon position in the frame), like a tilt-shift lens. Each shot is {x, y (camera height), zf, W, fov, H, lay, cs}.
  3. Morph between shots as dolly zooms. W stays framed at the focus plane zf while the fov changes. Every parameter runs on one monotone cubic curve through all the keys, so speed never jumps.
  4. Cheat while flat. Objects (cones, baskets) slide toward or away from the camera only during flat holds, where that movement is invisible. That's how a row becomes a diagonal ("front and back swap"). They can also be drawn bigger in the flat view (cs).

Matching a reference video (do this, don't eyeball it)

  • Pull its frames at each shot. Then, for each shot, measure:
    • where the vanishing point and horizon sit (giving H),
    • where two known-width things land (giving x and W),
    • the near and far edge of something of known length, such as a crossing (giving camera height y, distance and fov). The solved numbers are in the template comments.
  • Cluster its frames into a palette (k-means over 4 frames) and use those exact colours.
  • Compare its frames side by side with yours at the same timestamps after every change.

The illustration pass (why it looks drawn, not rendered)

The page renders three passes: colour (two-tone cel shading), view-space normals with depth, and a sun-only shadow mask. A final shader then does three jobs:

  • Ink lines wherever depth (second difference, so flat ground seen edge-on isn't inked) or normals change. Weight varies by noise and the lookup wobbles slightly, so lines aren't ruler-straight. The depth threshold grows with distance.
  • Hatching in cast shadow only: cooled tone and fine diagonal strokes, faded on surfaces seen nearly edge-on.
  • Sky (or ceiling) painted flat wherever there's no geometry.

Problems hit, so you don't repeat them

  • A // comment added on a one-line statement swallowed scene.add(sun), which left the mask black and everything hatched. Use /* */, or a new line.
  • Overlapping coplanar floors flicker far away. Make floor pieces meet edge to edge instead.
  • A light skimming walls at a shallow angle gives blotchy self-shadowing. Keep the key light about 45° from the front, and stop full-height columns and ceiling fittings from casting.
  • Text never goes in generated images or on signs. Signage is shapes only.
  • Check stills before every full render, and run the motion check (vox-explainer's motion_check.py).

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Related Skills