Guide · Site 02 of 25
How RELIC was made
The Ptolemy Engine is not a photograph. It is a real, rotating 3D object in your browser — and it started as a sentence.
The pipeline: sentence → image → mesh → museum
- Wrote the artifact into existence. A text prompt ("an impossible astrolabe of blackened bronze, floating rings, a glowing celestial core…") generated a studio photograph via Higgsfield nano_banana — deliberately framed like product photography: single object, dark seamless background, full margin. That framing is what makes step 2 possible.
- Lifted it to 3D. The image went through Higgsfield's
image_to_3d(textured) and came back a 10MB GLB mesh — real geometry with baked textures, for 30 credits. - Built the museum around it. The GLB loads into a hand-written three.js scene; every word of fiction on the page (the misaligned rings, the dead-star spectrography) was written after looking at what the mesh actually looked like.
Technique 1 — museum lighting
Three.js, but lit like an exhibit case, not a tech demo: a warm key spotlight from upper right, a cool rim spotlight from behind-left (that's what carves the silhouette), a faint verdigris uplight from below the plinth-line, and low amber ambient. ACES filmic tone mapping keeps the highlights from clipping. 220 gold dust motes on a slowly rotating THREE.Points cloud sell the vitrine air.
Technique 2 — the scroll-driven camera
The stage section is 520vh tall with a sticky viewport. Scroll progress maps onto four camera keyframes — [rotation, distance, height] tuples — smoothstepped between: title view, into the rings, close on the core, then pulling up and away for the verdict. The museum plaques crossfade at fixed progress thresholds, and dots on the right show which station you're at. The visitor never "controls" a 3D viewer; they walk past the case, and the case performs.
const KF = [ // rotY, camZ, camY, lookY
[0.0, 6.4, 0.60, 0.00], // title
[1.9, 4.2, 0.40, 0.10], // the rings
[3.6, 2.9, 0.15, 0.05], // the core
[5.8, 5.2, 1.50, 0.00]]; // the verdict
const e = f*f*(3-2*f); // smoothstep between stations
On top of the choreography: a slow constant rotation (the object never sleeps), a pointer-following lean of ±0.22 radians, and a gentle vertical bob — the "impossible" part of the fiction, done with three sine waves.
Technique 3 — resilience
- A loading vault-door screen tracks real GLB download progress from the loader's progress events.
- If WebGL fails or the model can't load, the stage swaps to the original source photograph — the museum quietly falls back to its own "photo of the exhibit."
- The render loop stops when the tab is hidden or the stage is scrolled away;
prefers-reduced-motionpins the camera to the title keyframe. - The GLB is centered and normalized from its bounding box at load, so a different model could be dropped in without touching the camera math.
Worth admitting
Image-to-3D reconstructs what it can see, so the mesh's hidden faces are the model's best guess, and up close the geometry is softer than the source photo. The camera keyframes were chosen to flatter what the reconstruction does well — which is exactly how real museums light real objects with bad sides.
How it was made
Written by Claude (Fable 5) — one HTML file, vanilla CSS/JS plus three.js (the only library on the page, loaded from CDN via import map). Part of the Fable 25, a 25-site showcase deployed on Cloudflare Pages.
Steal this
- Generate images like product shots (single object, clean background, full margin) if you plan to lift them to 3D — the reconstruction quality depends on the framing.
- Choreograph, don't hand over controls. Scroll-keyframed cameras give everyone the good angles; orbit controls give most people the bad ones.
- Rim light before key light. On dark scenes the silhouette does more than the fill.
- Write fiction after the render. Describing what's actually there beats forcing assets to match copy.
- Ship the fallback photo. A 3D scene that can quietly become an image has no bad browsers.