# Casting room

Can You Name architecture and furniture surround the portrait cards a player
calls aloud. No actor artwork, portrait provider or catalog is part of this
room, and nothing in it is a face: the folios are blank paper and the director's
chairs are blank canvas.

## Current room: v6

An upper-floor casting office at real proportions: 7.2 m wide, 7.9 m deep and
3.5 m to the ceiling, with the 0.756 m casting table 1.2 m in front of the back
wall. Three tall double casements with fanlights, 1.27 × 2.10 m in 0.4 m
reveals, look out over old-city rooftops. Dusty-rose linen curtains hang from
walnut poles on either side of each window, over walnut wainscot to the height
of the travertine stools. The walls are limewashed plaster under walnut ceiling
beams, and the floor is terracotta tile under a plum rug.

v5 was the same table in a 4.9 × 3.0 m room: two windows and a pair of French
doors onto a balcony, all looking out on a flat sky gradient, with a studio
camera, a coat stand with a trench coat and hat, valances, radiators, a lighting
grid, two desk lamps and a dozen table props. The owner found it a mess whose
windows led nowhere. v6 rebuilt the base rather than adding to it. The room is
at real scale, its light is baked, and the windows show a real place. What stands
in the room is the table, two director's chairs behind it, a low sideboard under
the left window, and the studio camera on its sticks in front of the right-hand
pier. The table carries a telephone, an inkstand, a script stack and a clapper
board in its back margin.

The shared construction boundary is `src/lib/actor-casting-room-layout.json`.
Colliders, the collection surface, card scale, both cameras, the view, the
runtime lights, the primitive room and this authored room all read it, in scene
units of 0.127 m. Desktop composition is position `[0, 12, 25]`, target
`[0, 1, -8]`, vertical field of view 46 degrees. Portrait is `[0, 14, 40]`,
`[0, 1.5, -6]`, 54 degrees. At real scale the table would read small from the
back of the room, so the cameras keep it about the size v5 showed. The window
heads crop just out of frame.

Nothing stands across the view. The builder projects every vertex of the studio
camera, the chairs, the sideboard and the table props into the desktop camera
and fails if any lands inside a window. The heading covers the left third of the
desktop frame on the ready screen, so the one tall prop stands on the right,
and the windows sit at ±16.5 units so the pier beside the right window is wide
enough for it. On the common 2:1 stage it sits entirely in frame. At 16:9 only
its pan-bar handle meets the frame edge.

The builder also fails if a table prop enters the collection footprint or
overhangs the table, if the visible top is not the physics top within a
millimetre, if the camera, chairs or curtains pass through the table or each
other, if the sideboard rises above the window stools, or if the runtime
daylight does not follow the baked sun.

## Light

The room's light is baked in Cycles into one owned 2048-pixel atlas: the sun
through the windows at 38 degrees elevation from the back left, the sky, a broad
soft panel standing in for windows behind the viewer, and every bounce between
them. The atlas is denoised, range-checked against 8.0 and encoded as sRGB. The
runtime restores its radiance range. Backdrop batches show the bake exactly and
ignore the lights the portraits need. The table walnut, its hide and the brass
stay physically lit over just over half of their bake, and take the portraits'
shadows from a daylight that follows the baked sun. One daylight shadow map
runs in Rich; Light disables it.

Two things came from the browser rather than the proof. Baked batches render
as pure diffuse, so walnut that read in a Cycles proof by its highlights came
out near-black and red. The walnut texture is now the scan's figure normalised
onto a palette colour, not a tint multiplied into an already-coloured scan.
And the shared camera stops at 100 units: the first view plane stood 145 units
out and was clipped without an error. The view now stands at z = −55, sized to
the same angle.

The view beyond the glass belongs to the renderer, not the asset: the reviewed
CC0 Belvedere backplate on a plane outside the back wall. It is a place, never a
face or a name. A stage test holds every window, from both cameras, inside that
plane.

| Active asset | Bytes | SHA-256 |
| --- | ---: | --- |
| `v6/room.glb` | 1,286,952 | `d68c8a115c0a36b9f7b785aa2e91003c280f42a1639fec9a3f2a8b76ec3f377e` |
| `v6/lightmap.webp` | 354,882 | `4593af42dfdadbeadaeaac6dc0a68c9a2ee60289b8c0e8e63fa4e19b6717533e` |
| `v6/view.webp` | 539,946 | `d415ce3b39f219601d83f0cfa877dd44ae11328650f1e7a4543ff3030f0ebfaf` |
| `v6/preview.webp` | 94,052 | `3d4dcb9cd06a2b3912252848a893340d68ed4bf6816dffd822eb9c11b7070dfa` |

The room has 49,224 triangles in 14 materials. It packs with 16-bit positions
and UVs and 12-bit normals, and restores repeated texture scale through texture
transforms within the quarter-texel guard. It decodes with the application's own
Meshopt decoder, keeps in-range lightmap coordinates in every baked batch, and
passes Khronos Validator with zero errors and warnings. These are asset counts,
not a frame-rate claim on real hardware.

The 1200-pixel still is captured from the real empty WebGL room without
interface overlays. It backs the no-WebGL collection fallback and the
homepage's rooms section. The synchronous primitive room still covers loading or
decoding failure, and play never waits for the asset. Earlier versions stay
immutable under `v1`–`v5`. Pruning superseded room assets is an owner decision,
and one that belongs to every room at once.

## Sources

Inputs are verified by hash against
`scripts/artwork/books-reading-room-sources.json`, all
[CC0](https://polyhaven.com/license) from Poly Haven:

- [Wood Table 001](https://polyhaven.com/a/wood_table_001), by Dimitrios Savva
  and Rico Cilliers: the walnut figure, recoloured, and its OpenGL normal map.
- [Leather White](https://polyhaven.com/a/leather_white), by Rob Tuytel: the
  leather and linen normal map.
- [Belvedere](https://polyhaven.com/a/belvedere), by Greg Zaal, backplate by Rico
  Cilliers: the view beyond the windows, backplate `DSC07991` reduced to
  2560 pixels.

The limewash, terracotta tile and rug are owned images painted by the builder.
No image provider is called during play.

## Rebuild and inspect

Read the sibling `blender-kit` instructions first. The builder owns only
`Actors_Casting_Room_v6`, in a separate background Blender process.

1. Restore pinned sources if necessary with
   `python3 scripts/artwork/fetch-books-reading-room-materials.py`.
2. Run Blender with `--background --factory-startup --python-exit-code 1
   --python` and the absolute path to
   `scripts/artwork/build-actors-casting-room.py`. Under WSL, pass the script's
   Windows path from `wslpath -w` to Windows Blender. Append `-- --proof` to
   render the game cameras without baking or exporting, `--details` for close
   review views, `--dry` to run only the construction checks, and
   `--report-overlaps` to let a layout in progress render despite a prop across
   a window. Ship only a build that passes without that flag.
3. Restore build-only tools if necessary:
   `npm install --prefix tmp/books-reading-room/tools --no-audit --no-fund @gltf-transform/core@4.5.0 @gltf-transform/functions@4.5.0 @gltf-transform/extensions@4.5.0 meshoptimizer@1.2.0 gltf-validator@2.0.0-dev.3.10`.
4. Run `node scripts/artwork/pack-actors-casting-room.mjs`.
5. Inspect the actual browser views: desktop and portrait, Rich and Light, an
   empty table and a full cast, and the room blocked at the network so the
   primitive room renders. Capture the empty canvas with the interface hidden,
   resize to 1200 pixels and encode WebP at quality 84 as `v6/preview.webp`.

Authoring scenes, proofs and reports stay under ignored `tmp/actors-casting-room/`.
Bump the version before replacing shipped bytes. The stage paths and
`casting-room.css` activate the assets together, and a test holds them to one
version.
