# Natural-history room

Owned museum architecture and furniture surround the existing accepted-animal
figurines and photographs. Decorative labels contain no species or answer
hints. No animal models or imagery were generated for this room.

## Current room: v16

The original desktop camera remains `[0, 9.2, 21.5]`, looking at `[0, 1.6, -2]`
with a 52-degree vertical field of view. Portrait retains its original preset.
The three-bay window remains 1.4 × 1.694 metres, with raised transoms, deep
reveals, layered mouldings and a walnut sill 0.454 metres clear of the back wall.

The side walls now have 1.05-metre-high framed panelling: recessed fields,
continuous rails and stiles, stepped beads and a capped dado. Lighter lime
plaster above has raised frames and a picture rail. Applied trim ends outside
the window architrave; structural masonry retains the real daylight opening.
Subdivided wall surfaces keep baked contact shading local to their joinery.
Nine shallow ceiling panels have paired plaster mouldings fitted to the ceiling.

Small owned normal tiles describe 0.08 mm plaster relief, 0.02 mm paint relief
and 20-micrometre cut-paper relief. Folios have bowed cloth spines, inset hinges,
headbands and separate page blocks. Their dimensions, lean and palette vary per
shelf. Timber floorboards have an independent matte finish and 0.95-metre grain
scale; walnut furniture keeps its scanned grain and restrained wax coat. A
256-pixel roughness map derives uneven polish from that same timber scan.
Bindings use a new 512-pixel woven normal and roughness tile: 80 threads per
5 cm and 18-micrometre relief. Local component UVs preserve the fine weave
within the quarter-texel quantization limit. Felt retains its owned wool fibres
with gentler normal strength. Turned
parts use continuous cylindrical UVs to avoid projection seams. Shelves,
complete folders and open trays retain verified support and clearance.

The rear microscope has a horseshoe foot, cast limb and trunnion, focusing rack,
knurled coarse and fine controls, draw tube, eyepiece, revolving objectives,
pierced stage, sprung clips and a mirror in its yoke. It bears on the counter.
Beneath the window, ten paired cast-iron radiator sections have rounded sealed
caps, connecting headers, floor-bearing feet, valves, unions and continuous
pipes. A construction check rejects open radiator castings, floating supports,
sill interference and table encroachment. The tabletop remains 0.735 metres
above the floor and matches shared physics.

A small owned radiance scene replaces the generic studio environment. Its
window and sash use the shared aperture dimensions; green dado, cream plaster,
timber, tabletop and warm sconces provide the reflected colour fields. It is
captured once into the existing 256-pixel PMREM target, with no extra download,
live lights or shadow maps. Temporary geometry and materials are freed after
success or failure; the stage retains ownership of the resulting target.
This is a rough-surface lighting approximation, not a mirror of live gameplay.

Six static material batches also receive actual indirect light baked from the
authored room: walnut, floor timber, panelling, plaster, enamel and table cloth.
`scripts/artwork/animals_field_light.py` packs a separate 2048-pixel UV atlas,
bakes 192-sample Cycles diffuse indirect light without direct light or albedo,
then runs Blender's colour-only OIDN compositor in a disposable scene. The
linear EXR is normalized to a radiance range of 2 and encoded once as sRGB.
The quality-94 WebP retains dark-tone precision; the runtime restores the
range with an authored gain of 4. The final bake clips no radiance samples.
Packing preserves and validates `TEXCOORD_1` through the application decoder;
the loader selects texture channel 1, no Y flip, and up to 8× anisotropy.

Broad key, hemisphere and environment fill are reduced to make room for this
spatial bounce light. Direct sunlight and cool window fill retain their
previous positions and strengths. Rich casts sun through the actual aperture; Light uses the shared
sampled patch clipped to the tabletop. Accepted figurines retain shared soft
contact shadows. Photograph colour and credits remain independent of lighting.
The atlas loads after the detailed furniture, independently of play. A failed
load retains ordinary lighting; a late load is released without assigning it
to a disposed room. Shared traversal owns the mounted texture's final disposal.

## Window and exterior

The curved Garden Nook photograph keeps sky, trees, lawn and ground in one
lighting environment. Its original 2560 × 2304 angular crop is retained at WebP
quality 84, spanning 112.5 degrees horizontally and 101.25 vertically. The
packer verifies 572 rays through the whole opening from the desktop, portrait
and two inspection positions. Background depth avoids far-plane clipping;
exterior fragments are masked to the actual aperture so scenery cannot leak
above the open room shell on phones.

A separate low garden wall uses a native 1024-pixel scan with baked daylight
relief, lifted brick tones and restrained moss colour. Individual coping stones
have rounded edges, recessed joints and slight tonal variation. Both exterior
maps use up to 8× anisotropic filtering, clamped to renderer support. The distant
garden remains a static photograph on curved geometry, with a separate near
wall; it is not an environment for free navigation.

Six optical panes share one draw call. Their etched insets occupy the
lower part of each pane (world Y −1.65 to 1.8, before border margins). Satin
borders have clipped corners, paired fine rules and clear centres. Neutral
scattering and fine grain make the narrow etched bands legible while leaving
the garden detail visible. The native v14 exterior remains immutable.
Rounded brass levers retain their backplates, slotted fixings and spindle
collars on the timber sash. New window and print reflection panoramas show the
revised room; the accepted photograph keeps its neutral colour path.

`room-frosted-view.ts` captures only the settled exterior through the actual
viewing camera. Projective sampling aligns nearby masonry and distant scenery
across etched borders. Its one render target preserves viewport aspect with a
1024-pixel long edge, using at most 5.34 MiB of colour mipmaps plus depth.
It refreshes only for camera/projection/CSS viewport changes. Ordinary frames
and quality switches reuse it. Failure leaves clear glass, renderer state is
restored, and teardown releases the target without freeing borrowed resources.

Courtyard loading remains independent of play, accepted photographs and
physics. Owned masonry, ground and pale sky cover missing local scenery. Late
assets are released without reviving a disposed room. No runtime request goes
to an artwork provider.

## Delivery and limits

The room has 173,394 triangles and 15 materials. The unchanged v14 courtyard
GLB adds 1,492 triangles and two unlit materials; complete runtime exterior and
glass geometry is 11,440 triangles. The settled empty render uses 184,764
triangles / 19 draw calls in Rich, and 184,767 / 20 in Light. This pass adds
7,776 delivered triangles and no draws. A nonempty contact batch adds one draw. Dense
collection performance still needs review on real hardware; these counts are
not a frame-rate claim.

Room, courtyard, indirect light and both reflection panoramas total 9,672,328
bytes, 754,666 more than v15. Delivery has a 9,600 KiB combined cap and 7,200 KiB
room-plus-lighting sub-limit; authoring geometry is capped at 190,000 triangles.
The atlas adds 21.33 MiB of RGBA mipmaps. Replacing the old leather normal and
adding finer finish maps brings the net room texture increase to 18.92 MiB.
Garden, brick, reflection and PMREM allocations stay unchanged. Floor and
furniture share both original timber JPEGs byte-for-byte. The room decodes with
the application's Meshopt decoder and passes Khronos Validator with zero errors
and warnings. All six lightmapped batches retain finite, bounded atlas UVs;
maximum measured finish-UV error is 0.225 texels, below the quarter-texel guard.

| Active asset | Bytes | SHA-256 |
| --- | ---: | --- |
| `v16/room.glb` | 6,938,448 | `e68f5e47ab19a9ce4c5c4a9bd7127a6c31ab2ee857c6e419dee91e15fe2a3602` |
| `v14/courtyard.glb` | 2,425,564 | `085e2aed8061cffe323d7a8cd5934feffffaddf6c51cc8477542627c3e8e472a` |
| `v16/glass-reflection.webp` | 22,918 | `61dde10fdd2795d6e59303dc05463fd54aaf387e7c6fbbd60176dfb2851630b2` |
| `v16/window-reflection.webp` | 21,146 | `46dc9dfaa7474a0ab142ad669c514cf5920b5c1cf23f6e38d9aa839dd06caf48` |
| `v16/indirect-light.webp` | 264,252 | `6865513fd046853b0441673a6d0cb449c6c047bbf3da6c412bea27a9520c33fd` |
| `v16/preview.webp` | 78,368 | `12c4d214d7863866b7574ee45305fe92470537e57256fe627fc92e7f13c20659` |

The 1200-pixel preview is captured from the actual empty WebGL room without
interface overlays. Both owned reflection panoramas are 1024 × 512 and exclude
accepted animals. Earlier versions remain immutable. The original synchronous
room and v1 maps still cover detailed-room loading or decoding failure.

## Sources

The room reuses the reviewed inputs in
`scripts/artwork/books-reading-room-sources.json`, from Poly Haven under
[CC0](https://polyhaven.com/license):

- [Wood Table 001](https://polyhaven.com/a/wood_table_001), by Dimitrios Savva
  and Rico Cilliers: timber colour and OpenGL normal maps.

Earlier immutable room versions retain [Leather White](https://polyhaven.com/a/leather_white),
by Rob Tuytel, under the same CC0 licence. V16 replaces the binding normal with
an owned woven tile. Plaster, paint, paper, wool, bookcloth and indirect lighting
are owned offline bakes; the wax roughness is derived from the credited timber.

Current courtyard inputs and hashes are pinned in
`scripts/artwork/animals-courtyard-sources.json`:

- [Garden Nook](https://polyhaven.com/a/garden_nook), by Dimitrios Savva and
  Jarod Guest, under [CC0](https://polyhaven.com/license). The 8192 × 4096
  tonemapped photograph is cropped at `(1024, 1024)` to `2560 × 2304`, then
  encoded at that native resolution as a quality-84 WebP. Geometry preserves
  its angular proportions.
- [Mossy Brick](https://polyhaven.com/a/mossy_brick), by Amal Kumar, under
  [CC0](https://polyhaven.com/license). The 1K diffuse, normal and occlusion
  scans are combined at their native 1024-pixel resolution into a quality-84
  WebP. Brick midtones are lifted and moss saturation restrained to match the
  garden daylight.

The immutable earlier v11 courtyard retains its original sources:
[Shapespark low poly exterior plants kit](https://sketchfab.com/3d-models/shapespark-low-poly-exterior-plants-kit-de9e79fc07b748d1a6ac055b49ee5c67)
by [Shapespark](https://sketchfab.com/shapespark), under
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), with adapted placement,
shading and texture packing; and
[Kloofendal 48d Partly Cloudy (Pure Sky)](https://polyhaven.com/a/kloofendal_48d_partly_cloudy_puresky)
by Greg Zaal and Jarod Guest, under CC0. Original plant source files and their
[licence](/models/safari-plants/license.txt) remain unchanged.

Public `/credits` lists the current authors and sources. All courtyard versions
embed provenance. Existing animal photographs, figurines and calls retain their
source records and visible photo credits. No runtime request goes to a provider.

## Rebuild and inspect

Read the sibling `blender-kit` instructions first. The builder asserts background
execution and owns only `Animals_Natural_History_v16` in a separate Blender
process. It does not replace the live scene.

1. Restore pinned room textures if necessary with
   `python3 scripts/artwork/fetch-books-reading-room-materials.py`.
2. Run Blender with `--background --factory-startup --python` and the absolute
   path to `scripts/artwork/build-animals-field-room.py`. Under WSL, pass the
   script's Windows path to Windows Blender. The bake helper runs in this same
   background process. Inspect the denoised atlas, proof and close views.
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-animals-field-room.mjs`.
5. Run background Blender with `scripts/artwork/render-animals-window-reflection.py`,
   then `node scripts/artwork/pack-animals-window-reflection.mjs`.
6. Reuse the immutable `v14/courtyard.glb`; window-probe packing checks the
   combined current delivery. Its independent courtyard rebuild remains in
   `scripts/artwork/pack-animals-courtyard.mjs`, with pinned sources and rays.
7. Inspect the actual browser at the original camera and close window, in both
   quality modes and portrait. Check aperture clipping, aligned transmission,
   cache invalidation, delayed/failed courtyard and lightmap loading, context
   loss and first-answer play. Compare material close-ups and DPR 2 glazing.
   Render the empty canvas, resize to 1200 pixels and encode WebP at quality 84
   as `v16/preview.webp`.

The style profile and shared layout remain in `scripts/artwork/styles/` and
`src/lib/animal-field-room-layout.json`. Authoring files and intermediate reports
stay under ignored `tmp/`. Bump the version before replacing shipped bytes;
explicit renderer/CSS paths activate the assets.
