# Image → Procedural Three.js Scene

A single-file web app (`index.html`, no build step) that takes a reference image, analyses it, and rebuilds the object as a procedural Three.js scene. Three.js r169 loads from the jsDelivr CDN through an import map, and rendering uses `WebGLRenderer` (WebGPU is not required).

Three reference images are drawn procedurally on a 2D canvas, so the app needs no external files: **a teapot on a table**, **a lighthouse on rocks** and **a red sports car**.

## Running

Serve the folder and open the page:

```sh
python3 -m http.server 8000   # then open http://localhost:8000/
```

## Controls

| Control | Action |
|---|---|
| **Reference buttons** (top bar) | Switch reference image. The scene is rebuilt and the morph replays. |
| **Pixel cloud ↔ 3D model slider** | Scrub the morph by hand. At 0 % the reference appears as a flat cloud of 128×128 coloured points; at 100 % you see the finished model. |
| **▶ Replay morph** | Animate the morph from the pixel cloud to the model again. |
| **Auto-play: on/off** | Turn idle auto-play on or off. |
| **⬇ Export GLB** | Download the current model plus a ground disc as a `.glb` file (uses `GLTFExporter`). |
| **analysis overlay** checkbox | Draw the analysis on the reference: silhouette outline, bounding box, horizon, lathe profile, colour bands, spout/handle centre-lines, wheel circles and window polygons. |
| **3D view** | Left-drag to orbit, mouse wheel to zoom, right-drag to pan. |

### Idle auto-play
Auto-play runs from page load. Each reference is shown for **8 seconds**:
1. the flat pixel cloud appears;
2. the points fly onto the model's surfaces while the solid model grows upward behind them;
3. the camera orbits slowly the whole time.

Then the app moves to the next reference. Any input pauses auto-play: dragging, zooming, using the slider, clicking a button, or pressing a key. It resumes with the next reference after **12 seconds** without input. The badge in the top-right corner shows the countdown.

## How it works

1. **Analysis** (at 256²):
   - Each row's background colour is estimated from the image's left and right borders.
   - Pixels far from that colour are marked as foreground, then cleaned with a morphological closing and a largest-connected-component pass. The result is the **silhouette**.
   - k-means (k=6) on the silhouette pixels gives the **dominant colours**.
   - The border colours also give the sky gradient, horizon row and ground colour.
2. **Reconstruction from primitives**, driven by the silhouette measurements:
   - *Teapot*: rows that are almost fully filled become the table, made of `BoxGeometry` slab, apron and legs with a procedural wood texture. The symmetric radius profile is split into colour bands, each a `LatheGeometry` (ceramic, with a metallic gold band). Pixels outside the profile become a tapered `TubeGeometry` spout and a C-shaped `TubeGeometry` handle, found by polar binning around the handle's hole.
   - *Lighthouse*: the profile becomes a stack of `LatheGeometry` stripes. The brightest saturated band becomes an emissive lantern with a `PointLight`. The rocks become a low-poly island made of a lathe core plus about 350 icosahedra coloured from the local pixels. The ground becomes a water plane.
   - *Sports car*: the side outline (with arches cut where the wheels were detected) becomes a bevelled `ExtrudeGeometry`, narrowed toward the roof and nose. Cool-hued pixels become glass `ShapeGeometry` windows plus windshield strips. `CylinderGeometry` tires and rims are sized by fitting circles to the tire chords. Bright warm pixels at the front become emissive headlights.
3. **Lighting**: the scene background, fog, hemisphere-light colours, sun colour and ground colour all come from the reference image, with a RoomEnvironment IBL added.
4. **Pixel cloud**: the model is rendered once into an image-aligned orthographic depth target. This gives every silhouette pixel its 3D destination on the model's front surface. Sky pixels drift away, floor pixels lie down onto the ground plane, and a clipping plane reveals the solid model from the bottom up.

## Notes
- Software GL (SwiftShader or llvmpipe) is detected automatically. The app then turns off MSAA, uses hard shadows and adapts the resolution to keep the frame rate usable. URL options for testing: `?ref=0|1|2`, `?morph=0..1`, `?auto=0`, `?overlay=1`, `?scale=1` (fixed pixel ratio), and `?az=`/`?el=` (initial camera angles in radians).
