# Full Circle recipe

How one picture becomes 25 camera angles you can walk around, on location and with no background. Everything generative runs on [Scenario](https://www.scenario.com/?referral=experiments-full-circle&utm_source=scenario.com&utm_medium=experiment&utm_campaign=full-circle&utm_content=making-of-recipe) (here driven from an agent through [Scenario MCP](https://mcp.scenario.com/?referral=experiments-full-circle&utm_source=scenario.com&utm_medium=experiment&utm_campaign=full-circle&utm_content=scenario-mcp)); the 3D layout work runs locally in Blender.

What you need: a Scenario account, Blender 5.x, Python 3.11+ with Pillow and NumPy. The kit ships the source pictures, the panoramas, the meshes that fit in the archive, earlier workflow scripts and recorded prompts (`prompts.json`).

The ZIP and Agent Skill preserve the earlier cutout workflow. The final site uses a second studio repaint instead. The original `studio_layouts.py` and `studio_prompts.py` scripts and full job ledgers are referenced in the build journal but are not included here; this is a starter kit, not an exact rebuild of the final assets.

## 1. One picture

Generate the subject with **GPT Image 2.5 Sunburst** at 1024 x 1024, quality high: the whole subject centered with margin, plain light background, seen slightly above eye level and turned about 30 degrees. Say the camera in the prompt: it is what the 3D cameras line up with later. The exact prompts are in `prompts.json`.

## 2. Shape only

Run **Hitem3D 3.0** on the picture: mesh only (`requestType: 1`), `resolution: 2048quality`, `face: 1000000`, no texture. The look comes back from the picture in step 6, so the mesh only has to be right about silhouette and proportion.

## 3. A world

Generate one 360 panorama per subject with **Scenario Skybox GPT** at 3840 x 1920, quality high, in the same art style as the picture. Ask for an open, empty patch of floor around the viewpoint at eye level (prompts in `prompts.json`).

## 4. Find camera zero

`scripts/match_view.py` renders clay silhouettes over a sweep of azimuths and elevations and scores them against the picture's silhouette (IoU). Pick the best match, and check it by eye: symmetric subjects can fool the score. The result is `az0` and `elev` below.

## 5. Grounded clay renders (Blender)

`scripts/render_grounded.py` normalizes the mesh (largest side = 2 units, standing on z = 0), wraps the panorama on a sphere of radius R centered at eye height H, flattens the lower half of that sphere into a floor, adds a shadow catcher and a world-fixed sun, then renders 25 cameras:

- 16 at eye level, one every 22.5 degrees starting at `az0`
- 4 high at 35 degrees (azimuths 0, 90, 180, 270 relative to `az0`)
- 4 low at `lowel` (below the subject center, looking up)
- 1 straight down at 88 degrees

```sh
blender -b --factory-startup --python scripts/render_grounded.py -- \
  --glb meshes/scooter.glb --pano panoramas/scooter.jpg --out Renders/scooter/grounded \
  --az0 30 --elev 10 --zoom 1.55 --height 1.6 --radius 14 --yaw 90 \
  --lowel -8.7 --sun 3.0 --sunel 50 --passes bg,clay
python3 scripts/v2_layouts.py scooter      # bg + clay -> layout_<key>.jpg
```

It writes `bg_<key>.png` (dome only), `clay_<key>.png` (clay and its cast shadow over transparency) and `grounded.json`. `layout_<key>.jpg` is the clay standing in its world: the frame the repaint follows. Per-subject settings used here are in `params/`. Tune `height` (eye height of the panorama) and `radius` until the floor meets the subject naturally, and `yaw` so a good part of the world sits behind camera zero.

## 6. Repaint every view

For each of the 25 cameras run **GPT Image 2.5 Sunburst** at 1024 x 1024, quality high, background opaque, with reference images:

1. the grounded layout of that camera,
2. the original picture,
3. optionally, an earlier painted view of the same camera (only if it is correct: the model copies its mistakes).

The prompt template (`scripts/v2_prompts.py`, filled per subject) tells the model that Image 1 is the exact final frame, to follow the clay silhouette, pose, size and ground contact, to keep the background and the cast shadow, and to take identity, colors, materials and style from Image 2. Use `--two` for the two-reference version.

## 7. No background

For the final site, place each camera’s clay render and real Blender shadow on a neutral studio floor, then repaint it with **GPT Image 2.5 Sunburst**, using that studio layout and the original picture as references. Keep the clay camera, silhouette, pose and size, with soft, even studio lighting. The two modes are separate paintings, so small surface details can differ. The original studio layout and prompt scripts are not included in this kit.

Earlier alternative, supported by the included scripts: run **BiRefNet** background removal on each scene repaint (parameter `image`), then use `scripts/studio_shadow.py` to remove edge color spill and restore its Blender shadow. That cutout method is documented by the bundled Agent Skill; it is not the final site’s No background mode.

## 8. The viewer

`scripts/build_site_assets.py` converts everything to WebP: `scene/`, `studio/`, `clay/` (compare layer for No background) and `guide/` (the layouts, compare layer for On location). The viewer is plain HTML, CSS and JavaScript: it cuts between neighboring camera images while you drag, and the compare slider reveals the clay under the render.

## Review tips

- Look at all 25 views of a subject side by side before shipping; one wrong detail repeats around the orbit.
- If a view invents an object, regenerate it with the two-reference prompt and name the object you do not want.
- Thin parts of a mesh (tails, straps) can be painted as something else from behind; that comes from the mesh, not the prompt.
