# ODEION — asset provenance

(Shown in this portfolio as ODEION, the Greek spelling; file names inside keep the working name `odeon`.)

Downloaded on 9–10 Oct 2026 and processed for this concept. Nothing is hotlinked, nothing is AI-generated, and there
are no people in any image. The theatre is procedural geometry written for this page (`js/odeon.js`): every seat
block, stair step, paving slab, wall course, voussoir, jamb, sill, through-stone, rubble-core lump and footing is
modelled to size in code. It borrows the rhythms of Roman-era theatres with a standing stage wall (the Odeon of
Herodes Atticus in Athens, Aspendos, Orange): a steep semicircle of seats, an orchestra, a raised stage, and a stage
wall of three storeys of arched doors, niches and windows between two towers. It reproduces no real building and no
inscription.

## Code

| File | Source | Licence | Notes |
|---|---|---|---|
| `vendor/three-0.185.1/three.core.min.js`, `three.module.min.js`, `LICENSE` | npm `three@0.185.1`, `build/` (the copy vendored for Marbre and Theatron) | MIT | Pinned. Unmodified. |
| `vendor/three-0.185.1/addons/loaders/HDRLoader.js` | same package, `examples/jsm/loaders/` | MIT | Unmodified. |
| `js/odeon.js` | written for this concept | — | The stone pipeline is Theatron's (seat profiles, joints in the shader, PCSS soft shadows after Marbre's `installPCSS`, print grade, ACES); new here: the ashlar wall builder (courses laid around the openings, voussoirs, sills and lintels as through-stones, a rubble core, robbed facing, a course-by-course ruin line, worn and chipped arrises, settled keystones, brick piers), the Roman cavea, the stage and its footings, the descent and the ensemble on the stage. |

## Textures and light

| File | Source | Author | Licence | What was done |
|---|---|---|---|---|
| `tex/stone-albedo-1k.webp`, `tex/stone-normal-1k.webp` | ambientCG **Concrete012** (https://ambientcg.com/view?id=Concrete012) and **Rock004** (https://ambientcg.com/view?id=Rock004), 2K-JPG | ambientCG (Lennart Demes) | CC0 1.0 | Theatron's limestone pair, unchanged (greyscale relative albedo, mean 0.5; whiteout-blended normal). The seats, steps and paving use it, and half the wall's facing stones. |
| `tex/stone-b-1k.webp` | ambientCG **Rock024** (https://ambientcg.com/view?id=Rock024), 2K-JPG colour map | ambientCG (Lennart Demes) | CC0 1.0 | Linear luminance, contrast 0.85 about its mean, normalised to mean 0.5, greyscale 1024², WebP q84. A paler, cracked bed of stone for 30% of the facing blocks. |
| `tex/stone-c-1k.webp` | ambientCG **Rock020** (https://ambientcg.com/view?id=Rock020), 2K-JPG colour map | ambientCG (Lennart Demes) | CC0 1.0 | As above, contrast 0.8. A darker, streaked bed for 20% of the facing blocks. |
| `tex/rubble-albedo-1k.webp`, `tex/rubble-normal-1k.webp` | Poly Haven **Medieval Blocks 06** (https://polyhaven.com/a/medieval_blocks_06), 2K JPG diffuse, AO and OpenGL normal | Rob Tuytel | CC0 1.0 | Albedo: linear luminance times a little of the scan's own AO, contrast ×1.15, mean 0.5, greyscale 1024², WebP q82. Normal: 1024², WebP q86. Used where the facing has been robbed and the mortared rubble core shows, on the broken crest of the walls, and as the far ground. |
| `tex/sky-hdr.js` | Poly Haven **Syferfontein 18d Clear (Pure Sky)**, 1K HDR (https://polyhaven.com/a/syferfontein_18d_clear_puresky) | Greg Zaal (original), Jarod Guest (sky edits) | CC0 1.0 | Theatron's file, unchanged: luminance only, sun disc removed, lower hemisphere a quiet ground, 256×128 RGBE as base64 (the host does not serve `.hdr`). Sky fill only, turned so its bright side sits with the scene's sun. |

Light: one sun behind the stage wall at azimuth 140° (from the seats' axis), elevation 19°, never moving (its shadow
map is drawn once). It pours through the doors and windows onto the stage and the orchestra and rakes the reveals.
A sky fill from the HDR, and a shadowless bounce from the opposite direction at 12° standing in for the sunlit bowl of
seats lighting the shaded face of the wall.

Generated at runtime (code, no files): per-stone tone, settlement and wear; rain streaks under sills, string courses
and the broken crest; crusts and lichen patches that ignore the joints; soiling near the ground; the brick bond of the
piers; the sky gradient and the aerial haze. The print grain and fall-off are an inline SVG `feTurbulence` and a radial
gradient in CSS, laid once over both the still and the live canvas.

## Fonts (concept only)

| File | Family | Licence | Production face to license |
|---|---|---|---|
| `fonts/archivo-latin.woff2`, `fonts/archivo-latin-ext.woff2` | Archivo v25 (Google Fonts; variable: wdth 62–125, wght 100–900), Omnibus-Type | SIL OFL 1.1 (`fonts/OFL-Archivo.txt`) | GT America Extended / Standard (Grilli Type) |
| `fonts/newsreader-italic-latin.woff2`, `fonts/newsreader-italic-latin-ext.woff2` | Newsreader Italic v26 (Google Fonts; variable opsz, wght), Production Type | SIL OFL 1.1 (`fonts/OFL-Newsreader.txt`) | GT Sectra Fine Italic (Grilli Type) |

Same two families as Theatron, so the two read as one family. The latin-ext files load only for characters such as the
ō in *ōideion* and the ē in *mousikē* (unicode-range).

## The stills (first frame = fallback)

All rendered headless from this scene (`tools/stills.js`: Playwright Chromium, SwiftShader), 2× supersampled without
MSAA, downsampled with Lanczos 3 and encoded with sharp (AVIF q56, WebP q82, mozjpeg q82):

| Files | What | Used for |
|---|---|---|
| `img/odeon-p0-wide-{2560,1280}.{avif,webp,jpg}`, `img/odeon-p0-tall-{1170,780}.{avif,webp,jpg}` | the descent at p = 0 (the top row of seats, looking down at the stage and the wall), desktop and phone reference frames | first paint, no-WebGL, reduced motion |
| `img/odeon-p1-wide-{2560,1280}.{avif,jpg}`, `img/odeon-p1-tall-{1170,780}.{avif,jpg}` | the hold at p = 1 (on the stage, looking up at the arches) | reduced motion (second image), no-WebGL dissolve |
| `img/ens-{trio,quartet,chamber,full}-{1200,600}.webp` | the ensembles plate, four arrangements on the stage | plate first paint, reduced motion, no-WebGL |
| `img/arches-{2360,1200}.{avif,jpg}` | a long view along the wall from the stage, the low sun on the reveals | the print in "Where" |

The live camera re-maps its reference projection exactly the way CSS `object-fit: cover` (anchored at the top) crops
each still, so the still and the first live frame put every stone on the same pixel at any window size.

## Byte budget

Measured with `tools/budget.js` (Playwright, files as served without compression):

| | requests | bytes |
|---|---|---|
| First view, desktop 1440×900 (page, fonts, first-frame still, three.js, scene module, textures, sky, the first plate still) | 17 | 3.66 MB (about 3.2 MB with gzip on the JS) |
| First view, phone 390×844 | 17 | 3.48 MB |
| Scrolled to the end, desktop (adds the print in "Where") | 18 | 3.86 MB |
| Everything in `assets/` and the page (every format and size of every still) | — | 8.74 MB |

Budget: first view ≤ 4 MB, everything ≤ 12 MB. The other three plate stills load only when a visitor picks them (or in
reduced motion); the hold stills load only in reduced motion or without WebGL.

## References studied (kept in `tools/refs/`, never published)

Wikimedia Commons photographs used only to calibrate the realism of the wall, joints, wear, ruin and light: the Odeon of
Herodes Atticus (overview from the Acropolis in black and white; the façade detail of 18 March 2022; the stage wall
from the cavea), the scaenae frons at Aspendos (interior and central part), and the stage wall at Orange. They are not
copied, traced or shipped.
