Palace of Fine Arts, attempt 3 · Phase 6 · 15 to 19 September 2026
The model was finished. Why did the phone version take a week?
On 10 September a photoreal 3D model of the Palace of Fine Arts was delivered as a Blender file. Five days later it started becoming a web page you can walk through on an iPhone. This page tells that week day by day: what was tried, what broke, what the machine and the people were waiting for, and what it cost. The numbers are rounded; the audit carries every caveat.
Prologue: what existed on 10 September
Phases 0 to 5 (6 to 10 September) built the palace in Blenderfree 3D modelling software; the model lives in a single .blend file: the rotunda, the colonnades, the sculpture, trees and water, lit at golden hour, then renderedcomputed into a still picture by simulating light; one 4K frame of this scene takes 25 to 70 minutes on the Mac from the classic viewpoint across the lagoon (the "hero" view). The work was done by AI agents: one lead session that plans, briefs and merges, and specialist agents it dispatches for a task each; a critic agent scored the result against a photograph on a 5-point rubric, where 5 means "hard to tell from a photo". Drag the handle to compare.
Reference photo: Palace of Fine Arts (16794p) by Rhododendrites, Wikimedia Commons, CC BY-SA 4.0, warped into the render's framing for the comparison. Every other photograph this project measured against is listed with author and licence in reference/photos/ATTRIBUTION.md.
Proof: delivery.md (v2 delivery), QA 10b (score 3.61), retrospective.md (Phase 5 costs), usage/summary.md.
On the "weekly budget": the account is a subscription with a weekly usage meter. That meter is not recorded anywhere in the project, so this page shows nominal dollars at list prices and shares of the week's spend instead. The audit explains why the one calibration that exists (a remark on 9 September) cannot be trusted.
Why a finished 3D model is not a finished web page
The render on 10 September is a single picture that took the Mac's graphics chip 70 minutes. A walkthrough must draw sixty pictures a second, on a phone, from any viewpoint. Nothing in the .blend file can do that directly, so the model had to be rebuilt in a second form. The work was split into gates: checkpoints where a critic agent scores the result and reviews it at full zoom before the next step may start. Four steps did most of the work, and each has a plain name:
- Decimation. The model has 30 million triangles (the tiny flat facets every 3D surface is made of). A phone can draw about 3 million per frame, so every object was simplified to a tenth of its detail, with the fine detail transferred into a picture pasted on top (normal mapan image that stores which way the surface bumps, so a flat triangle still catches light like the carved original). Gate 1.
- Baking. The colours, roughness and the golden-hour light and shadow were computed once in Blender and stored as images (lightmapspictures of the light falling on each surface, computed once and pasted on, so the phone does not have to simulate light), so the phone only has to look them up. This is the slow part: the light bake alone ran 6.5 hours overnight. Gates 2 and 3.
- Texture compression. Those baked images added up to 1.4 GB. A phone browser gets about 700 MB, so every image was recompressed into a format the graphics chip reads directly (KTX2a container for GPU-compressed textures; the file stays small in memory, not only on disk) and the first thing you see was cut to 47 MB. Gate 2 and the web step.
- The iPhone memory limit. iOS Safari kills a page that uses too much memory. The desktop viewer sits at 1.9 GB; the phone version got a separate, halved set of everything and a 1.5-megapixel drawing cap, and still had to be tested on the actual phone. The web step.
Which cost the most time here? Not the slow baking, which ran mostly overnight. The expensive part was the hand-offs between the three specialists: what the baker produced, the exporter packed, and the viewer read had to agree on dozens of small conventions (which corner of a texture is up, how coordinates are rounded, which name a tree is filed under), and every mismatch was found one step later, by looking at the pictures, and sent back. The audit counts the loops: four rounds to pass Gate 1, two for Gate 2, two re-bakes, two bake re-runs for the trees, six web deployments.
Who the agents are, and what each one actually does
Every agent is the same kind of thing: one AI conversation that reads files, runs commands and writes files, in a private copy of the project (a "worktree", so agents cannot overwrite each other). The job title only sets what it is briefed to do, which tools it may touch, and which model runs it. The lead is the one conversation you talk to; everything else is dispatched by it with a written brief.
The lead (Fable 5.1; 6 sessions in Phase 6, $176)
- What it does
- Reads status.md and the last reports, writes a brief per task (a text file the agent starts from), dispatches agents, watches the bake queue, rebuilds the Blender master file, takes the six screenshots, merges reviewed branches, and writes the status, decisions and delivery notes. It writes no build code beyond 20-line fixes.
- One real task from the week
- On 17 Sep at 09:28 one request dispatched three agents for the foliage pass (bake, export, viewer), each with a brief pointing at docs/briefs/phase6c_*.md: 2,463 output tokens, most of them the three briefs, $0.34.
- What it leaves behind
- docs/briefs (28 Phase 6 briefs), docs/status.md, docs/decisions.md (81 entries in the week), docs/delivery.md, the merge commits.
Viewer builder (Opus 5, high effort; 10 in Phase 6, $540)
- What it does
- Writes the web application in JavaScript with the three.js library: code that downloads the packed model files, builds materials from the baked images, applies the colour treatment, draws the water reflection, fog and bloom, handles walking and the six camera presets, streams the download tiers, plus a screenshot tool that captures the six viewpoints the same way every time. It also measures: frame times, memory, and pixel boxes against the render.
- One real task from the week
- On 17 Sep at 09:41 one request wrote the foliage module (leaf shader with bent normals and translucency, the near-tree switch, impostor modulation): 12,487 output tokens in a single file write, $0.40.
- What it leaves behind
- web/src/*.js (the viewer), web/tools/*.sh and *.mjs (captures), web/test (207 tests by the foliage pass), renders/web/round*_cam0N.png (captures), web/README.md.
Light baker (Opus 5, extra-high effort; 7 in Phase 6, $286)
- What it does
- Writes and runs the Blender scripts that compute images from the model: lightmaps (light and shadow per surface), material maps (colour, roughness, bumps), the reflection probe, the sky, the tree impostors. Each is a headless Blender job on the graphics chip, run one at a time through a queue script with a status file, and verified afterwards (value ranges, clipped pixels, coverage). It also diagnoses defects in the maps, such as the black ceiling that turned out to be inverted surfaces.
- One real task from the week
- On 16 Sep at 00:19 one request wrote the queue worker script that ran the 65 overnight lightmap jobs: 16,131 output tokens, $0.52. Then it polled the queue for eight hours.
- What it leaves behind
- export/bake_*.py, export/bake_queue.sh, export/out/gate3/*.exr and *.ktx2 (the images, not committed), the manifest entries that say how to decode them, export/README.md.
Exporter (Opus 5, high effort; 8 in Phase 6, $266)
- What it does
- Turns the Blender model into web files: chooses which objects ship, simplifies each mesh to its triangle budget, lays out the texture coordinates the bakes need, writes glTF files, packs them with gltfpack and the textures with toktx, and writes the manifests that tell the viewer what exists (later, the download tiers and the phone variant). It writes the checks that the packed files still carry what was put in.
- One real task from the week
- On 15 Sep at 12:08 one request wrote the Gate 1 export-set builder, 692 lines of Python, in one go: 21,167 output tokens, $0.63: the largest piece of output any request produced in the week (the most expensive requests were something else, see "Inside one request").
- What it leaves behind
- export/export_set.py, gate*_set.py, gltf_pack.sh, tiers.py, verify_glb.py, export/out/*.glb and manifest.json (not committed), docs/briefs/phase6_budget.md.
Critic (Opus 5, extra-high effort; 13 in Phase 6, $102)
- What it does
- Takes the six captured viewpoints, cuts the hero into six full-resolution tiles and looks at each, writes a probe script that measures pixel boxes (brightness, hue, saturation, grain) against the render, runs the name sweep, and writes the round report with a verdict, scores per viewpoint, and one owner per defect. It never runs Blender or the browser.
- One real task from the week
- On 16 Sep at 16:48 one request, right after viewing a tile, wrote the 247-line measurement probe for round 13: 7,451 output tokens, $0.24. The whole round cost $9.59.
- What it leaves behind
- docs/qa_round_11 to 19 (13 reports in Phase 6), scripts/qa_r1N_probe.py, renders/web/round1N_gate.png (the composite).
Code reviewer (Opus 5; 32 in Phase 6, $102)
- What it does
- Reads the difference between a branch and main, runs nothing heavier than a test, and writes a review with numbered findings: fix now, or carry. The lead merges only after the fix-now items are closed. Cheap ($2 to $7 each) and the source of most of the bugs caught in the week.
- One real task from the week
- On 16 Sep at 17:11 one request read the viewer diff for the impostor round and reasoned about it: 7,065 output tokens of which 6,913 were thinking, $0.25. That review found the swapped blend weights.
- What it leaves behind
- docs/reviews/phase6_*_review.md (32 in Phase 6).
Also in the week: one materials agent (the dome cap and coffer material round in Blender, $30) and three Sonnet helpers for mechanical passes ($2).
The week, day by day
table view
| agent working | chip busy, nobody watching | blocked on the user | idle, user away | total | |
|---|---|---|---|---|---|
| Sep 15 | 13.6 h | 0.6 h | 0.1 h | 9.7 h | 24 h |
| Sep 16 | 10.7 h | 0 h | 3.2 h | 10 h | 23.9 h |
| Sep 17 | 6.8 h | 0 h | 6.4 h | 10.8 h | 24 h |
| Sep 18 | 3.3 h | 0 h | 20.2 h | 0.5 h | 24 h |
| Sep 19 | 9.7 h | 0.2 h | 11.2 h | 2.9 h | 24 h |
Priority when things overlap: agent work first, then the graphics chip, then user waits. "Idle" on 15 Sep is the morning before the first prompt. Source: phase6_audit.py, per-day table.
Monday 15 September
Gates 0, 1 and 2 in one day: 12 hours of near-continuous work
- Attempted
- Build the pipeline end to end on one column and one capital (Gate 0); simplify every object and prove the geometry matches (Gate 1); bake colours and surface into images (Gate 2). Three specialists (bake, export, viewer), a critic and a code reviewer per merge.
- Worked
- All three gates passed the same day, each branch merged (folded into the main code) after a code review. The vertical slice matched the render to within one pixel of position. The full scene came in at 2.84 million triangles against a 3 million budget. The user made the three scale-up decisions ("go") within seven minutes of being asked.
- Failed and redone
- Gate 1 failed three times before passing: a backdrop material with an invalid texture slot made 151 000 triangles vanish, three sculpted panels were torn by a bad simplifier, 127 placeholder tree boards hid the building, then 1 379 shrubs were drawn at the world origin. Gate 2 failed once (7 of 12 stone materials shipped without their bump detail), then the replacement detail maps shipped empty, then too faint; three fixes in one evening.
- Waiting
- Graphics chip 11.3 h busy (ornament bake queue 1.6 h at noon, material bakes in the afternoon), always with an agent polling it. The user was needed for 7 minutes. The overnight light bake started at 22:10.
- Cost
- 13.6 agent-hours, $495 nominal (23 % of the week's $2,148), 21 agents dispatched.
Proof: status.md entries of 15 Sep, QA 11 to QA 11d, QA 12, QA 12b, commits 70bfe73, 57addb8, 19412e4.
Tuesday 16 September
The light bake, a forced restart, and the viewer gets its light
- Attempted
- Finish the overnight light bake (65 jobs), review it, wire the baked light into the viewer, score it (Gate 3), then the viewer proper: fog, bloom, water, far trees as flat pictures, walking (Gate 4).
- Worked
- The bake finished before dawn (6.5 hours) with every map usable but one. The critic accepted the lightmaps: the hero frame landed at 97 % of the render's brightness. Gate 4 round one closed the two biggest lighting defects.
- Failed and redone
- The packer had silently stripped the second set of texture coordinates from every file since Gate 1, so the baked light could not attach; found only now and re-packed. The dark hero turned out to be a rounding of those coordinates the viewer had to undo. The rotunda ceiling map was black (its surfaces faced inward) and was re-baked. A merge was blocked because the reflection probe had never been uploaded, so a "closed" defect was reopened and re-measured.
- Waiting
- The lead had passed its own context limit and asked for a restart at 05:34; the user restarted it at 08:48 (3.2 h). The user left twice (09:19 and 17:28) with the next steps written down: 10.0 h idle. Graphics chip 7.7 h.
- Cost
- 10.7 agent-hours, $416 nominal (19 % of the week's $2,148), 22 agents dispatched.
Proof: status.md entries of 16 Sep, QA 13, QA 14, decisions.md entries "Gate 3 hand-off" and "Gate 4 round 5", commits f8c9002, cc14323.
Wednesday 17 September
Parity reached at 01:23; then the foliage pass the user asked for
- Attempted
- Finish Gate 4 (water with real ripples, per-bush lighting), declare the desktop viewer at parity with the render (6a), then a two-round pass on trees and shrubs (6c) because the user found them wrong at close range.
- Worked
- The critic scored every station within 0.5 of its render score, none below 2.5: the viewer was at parity. The foliage pass gave the tree crowns interiors and brought the shrubs down to the reference brightness.
- Failed and redone
- The user opened the delivered viewer and saw the test scene: the page's default settings were still the Gate 0 development ones. The per-bush light bake had to be run twice (the first used an opaque stand-in that brightened everything by 64 %). The tree bake and the tree export anchored trees at different points, up to 3.4 m apart; far trees were placed 300 m off; both redone.
- Waiting
- Blocked on the user 6.4 h (the 01:23 result waited until 07:10 for a reader). User away 10.8 h, including 12:54 to 23:16 with QA 17 finishing on its own.
- Cost
- 6.8 agent-hours, $390 nominal (18 % of the week's $2,148), 24 agents dispatched.
Proof: QA 15, QA 16, QA 17, decisions.md "FINAL JUDGEMENT OF 6a" and "Delivery defect found by the user", commits 212ca27, 5e1fffa, 47a2f7e.
Thursday 18 September
The web deployment, a phone that showed the wrong scene, and a 17-hour question
- Attempted
- Split the 640 MB of assets into three download tiers so the first picture arrives under 50 MB; build a halved set for the iPhone; deploy to a free host; score it on the live address (6b).
- Worked
- Published to the web host ("deployed") at 18:41. First frame 46.8 MB, three tiers stream the rest, no file over the host's 25 MB cap. The phone tier draws the whole scene in 500 MB of memory. The user's iPhone 16 Pro showed the hero scene at 20:59.
- Failed and redone
- The phone version had no building: its seven geometry files were in neither publish list (found by the critic, fixed, redeployed). The phone canvas filled only 70 % of the screen. The bare address drew the test scene on the user's phone because the default asset path pointed at an unpublished folder (fixed, deploy 5). Then a sixth deploy so the phone's water reflects the building.
- Waiting
- Blocked on the user 20.2 h: the lead had asked its three deployment questions (which iPhone, which host, whether a low-resolution first look is acceptable) at 23:24 the night before, ten hours after the user had left, and got the answer at 16:57. Agents worked 3.3 h.
- Cost
- 3.3 agent-hours, $204 nominal (9 % of the week's $2,148), 7 agents dispatched.
Proof: QA 18, QA 18b, decisions.md entries "6b" and "Post-close fix", commits 900a846, 98ab252, 1c4b0f5, d40a125, deploy logs renders/logs/6b_deploy_1..6.log.
Friday 19 September
Phase 7: the trees the user saw on the phone; then the next phase starts
- Attempted
- The user sent two screenshots at 08:47: far trees jagged and black-cored on the desktop, close trees flat on the phone. One viewer round on the live site, then a score.
- Worked
- Both defects closed on the desktop and on the phone by 09:56; the mobile score rose from 2.9 to 3.2 on the hero. Payload unchanged.
- Failed and redone
- Nothing redone inside Phase 7. Phase 8 (five further art items) started at 12:25 the same day and is outside this page, but it is inside the same week and budget: $599 more that day.
- Waiting
- Blocked on the user 11.2 h (overnight until 08:43, then 09:58 to 12:25 after Phase 7 closed).
- Cost
- 9.7 agent-hours, $644 nominal (30 % of the week's $2,148), 33 agents dispatched. Of this, Phase 7 itself: $44.
Proof: QA 19, decisions.md "PHASE 7 APPROVED" and "PHASE 7 DONE WITH RESIDUALS", commits 91f08b4, 6253d32, user screenshots renders/web/user/phase7_*.png.
Each gate: before and after at the hero viewpoint
Every gate ends with a critic's report and a full-resolution tile review. Each slider shows the same viewpoint; the left image is the viewer.
table view
| agent working | chip busy, unwatched | blocked on the user | idle | total | |
|---|---|---|---|---|---|
| Gate 0 | 1.9 h | 0 h | 0.1 h | 0.1 h | 2.1 h |
| Gate 1 | 5.1 h | 0.1 h | 0 h | 0 h | 5.2 h |
| Gate 2 | 4.4 h | 0.6 h | 0 h | 0 h | 5 h |
| Gate 3 | 9.5 h | 0 h | 3.2 h | 4.5 h | 17.2 h |
| Gate 4 | 4.7 h | 0 h | 0 h | 5.5 h | 10.2 h |
| Foliage | 5.2 h | 0 h | 5.8 h | 0.6 h | 11.6 h |
| Web | 3.5 h | 0 h | 20.8 h | 10.8 h | 35.1 h |
| Phase 7 | 1.1 h | 0 h | 8.7 h | 0 h | 9.8 h |
Gate windows run from one verdict commit to the next; "Web" spans 17 Sep 12:56 to 19 Sep 00:00 and holds the 17.6-hour question. Source: phase6_audit.py, per-window table.
Gate 0, the vertical slice (15 Sep 09:43 to 11:50)
Before scaling up, the whole pipeline was run on one column and one capital, and the viewer's picture was compared with a Blender render of the same slice: position matched to the pixel, the sky's brightness to 1 % and the lit column to within 8 %. It was hard because the viewer had to reproduce Blender's exact colour treatment (a 65-step colour cube baked from Blender itself) before any comparison meant anything.
Cost $78. No station scores at this gate. Proof: gate0_pair.png, decisions.md "Gate 0 verdict", commit 70bfe73.
Gate 1, geometry freeze (15 Sep 11:50 to 16:58)
Every object was simplified to a phone budget and drawn in plain grey so the critic could judge shape alone: the silhouette matched the render to 0.075 % of the frame height. It took four critic rounds because each export defect hid the next one: an invalid texture slot, torn panels, placeholder boards in the way, then shrubs drawn at the origin.
Cost $176. Geometry rows only: hero 3.5 (render 3.61). Proof: QA 11, QA 11b, QA 11c, QA 11d, commit 57addb8.
Gate 2, materials (15 Sep 16:58 to 21:55)
Colour, roughness and surface bumps were baked into images for 60 material sets and the viewer drew them under plain sunlight, no shadows yet, so this comparison is deliberately brighter than the render. It was hard because half the stone shipped without its bump detail, and the replacement detail layer arrived empty, then too faint, before the third version passed at 100 % zoom.
Cost $202. Material rows only; no station average. Proof: QA 12, QA 12b, status.md "Detail re-derivation merged", commit 19412e4.
Gate 3, the light bake (15 Sep 21:55 to 16 Sep 15:09)
The golden-hour light and shadow were computed overnight (65 jobs, 6.5 hours) and pasted onto every surface; on the first attempt the hero came out dark and blue-banded, and after the fix it landed at 97 % of the render's brightness. It was hard because the file packer had quietly stripped the coordinates the light needed and rounded the rest, two behaviours nobody had checked at Gate 0.
Cost $259. QA 13 stations: 3.39 / 2.69 / 2.69 / 2.31 / 2.89 / 2.33 (lightmaps alone, not the final look). Proof: QA 13, decisions.md "Gate 3 hand-off" and "Gate 4 round 5 (lead)", commit f8c9002.
Gate 4, the viewer proper (16 Sep 15:09 to 17 Sep 01:23)
Fog, bloom, real water ripples, far trees as picture cards and walking were added; between round 14 and round 15 the water stopped being a mirror and the score reached parity with the render at every station. It was hard because the 45 frames-per-second target could not be met with the water reflection and bloom both on (35.5 fps), so a faster preset was documented instead.
Cost $254. QA 15 stations: 3.72 / 3.00 / 2.56 / 2.88 / 2.94 / 2.83 against the render's 3.67 / 2.94 / 2.56 / 2.81 / 3.06 / 2.67. Proof: QA 14, QA 15, decisions.md "FINAL JUDGEMENT OF 6a", commit 212ca27.
Foliage pass, 6c (17 Sep 01:23 to 12:56)
The user found the trees wrong at close range, so crowns got interiors and translucent leaves, shrubs got a denser near set, and far trees switch to real meshes when you walk up. It was hard because a tree is baked in one place and exported in another, and the two disagreed about where the tree stood, twice.
Cost $322. QA 17: hero 3.78, station 2 up 0.25, the rest unchanged. Proof: QA 16, QA 17, decisions.md "6c CLOSED WITH RESIDUALS", commit 47a2f7e.
Web deployment, 6b (17 Sep 12:56 to 18 Sep 23:35)
The assets were split into three download tiers so the first picture arrives under 50 MB and sharpens as the rest streams in; a halved set was built for the phone; the site went live on a free host. It was hard because the phone list of files and the desktop list of files were built separately, and the deployment trusted one of them: the phone tier had no building until the critic looked.
Cost $209. Desktop unchanged at 3.78; the phone scored for the first time: 2.9 / 3.0 / 2.3 / 2.7 / 2.5 / 2.4. Proof: QA 18, QA 18b, decisions.md "6b DONE WITH RESIDUALS", commits 900a846, 98ab252, 1c4b0f5.
Phase 7, the trees on the live site (19 Sep 08:43 to 09:56)
Far tree edges lost their jagged halo and black cores, and the phone draws real tree meshes within 45 m instead of flat cards. It was cheap because everything needed was already exported; only the viewer changed.
Cost $44. Desktop 3.78; phone 3.2 / 3.3 / 2.3 / 2.7 / 2.8 / 2.4. Proof: QA 19, decisions.md "PHASE 7 DONE WITH RESIDUALS", commit 6253d32.
The result
Live viewer: pfa-walkthrough.3d-render-blender-3rd-attempt-building.workers.dev (keys 1 to 6 jump to the six viewpoints; walk with the W, A, S and D keys; the phone picks its own download tier).
| viewpoint | Blender render (10 Sep) | viewer, desktop (19 Sep) | viewer, phone (19 Sep) | live site today (21 Sep, after Phases 8 and 9) |
|---|---|---|---|---|
| 1 hero, lagoon | 3.67 | 3.78 | 3.2 | 4.05 |
| 2 north-east | 2.94 | 3.25 | 3.3 | 3.51 |
| 3 colonnade | 2.56 | 2.63 | 2.3 | 3.08 |
| 4 ceiling | 2.81 | 2.88 | 2.7 | 3.05 |
| 5 south lawn | 3.06 | 3.06 | 2.8 | 3.24 |
| 6 aerial | 2.67 | 2.83 | 2.4 | 3.07 |
Scores are the critic's per-viewpoint averages on the 5-point rubric. The viewer was scored against Blender renders of the same viewpoints, not against the photograph, so "3.78 versus 3.61" means "as good as the render, plus the water and trees it improved", not "closer to a photo". The 21 Sep column is from QA 25, outside this week.
Was the definition of done met?
Mostly, with two honest gaps. The desktop viewer reached parity with the render at all six viewpoints (met), reflects the rotunda, clamps the walk to the ground, shows a loading bar, and its speed and memory were measured (met), but it runs at 35 not 45 frames per second (target missed, documented). The web version loads under 50 MB, streams the rest, and passed a scoring round on the live address (met). The phone version loads on the user's iPhone 16 Pro (met by the user's screenshot); that it walks on the phone was only tested on the Mac in phone mode (not evidenced). Safari on macOS was tested through a WebKit engine build, not Safari itself (not evidenced). The rule that the critic also scores against the photograph was not followed. Full table: the audit, section 5.
What the week cost, in one picture
$1,505 nominal for Phase 6 (15 to 18 Sep), $2,148 for the whole week including Phase 7 and the start of Phase 8.
table view
| viewer builders | light bakers | exporters | the lead | critics | code reviewers | materials | helpers | total | |
|---|---|---|---|---|---|---|---|---|---|
| Phase 6 | 540 | 286 | 266 | 176 | 102 | 102 | 30 | 2 | 1,504 |
8,068 AI requests by 74 agents and 6 lead sessions; 6.6 million words-worth of output tokens, 1.78 billion re-read from cache. A token is roughly three quarters of a word; the price of re-reading cached context is a tenth or less of new text, which is why 96 % of all tokens are cache reads and only a fifth of the cost.
The detail: by day, by model, by activity, and the limits of this attribution
table view
| nominal USD | total | |
|---|---|---|
| Sep 15 | 495 | 495 |
| Sep 16 | 416 | 416 |
| Sep 17 | 390 | 390 |
| Sep 18 | 204 | 204 |
| Sep 19 | 644 | 644 |
table view
| Opus 5 (builders, critics, reviewers) | Fable 5.1 (the lead) | Sonnet 5 (helpers) | total | |
|---|---|---|---|---|
| Phase 6 | 1,326 | 176 | 2 | 1,504 |
table view
| nominal USD | total | |
|---|---|---|
| running scripts | 434 | 434 |
| reading files and logs | 329 | 329 |
| checking whether jobs finished | 322 | 322 |
| writing code and notes | 246 | 246 |
| thinking and reporting | 74 | 74 |
| looking at pictures | 71 | 71 |
| briefing and messaging agents | 29 | 29 |
One label per request by a fixed priority (pictures > waiting > editing > coordination > reading > running > thinking). A fifth of the money went to turns whose job was to check whether a job had finished.
Limits. These are list-price dollars computed from the transcripts, not an invoice; the subscription's weekly meter is not recorded anywhere. Claude Code's own running tally for the same sessions is 8 to 30 % higher because it prices small side calls the transcripts do not carry. A request that did two things is counted once. Thinking tokens (2.4 million) are inside every bar. See the audit, section 2.
Inside one request: what the tokens are
An agent works in a loop: it sends everything it has seen so far (the brief, every file it read, every result) plus one new instruction, and gets back a reply that ends in either a tool call or a message. Each trip is one request and is billed in tokens (about three quarters of a word each). Three kinds of tokens are in every request:
- Context re-read. The whole conversation so far goes in again, every time. In Phase 6 the typical request re-read 184,676 tokens (about 140 pages). Because it is unchanged, it comes from a cache at a tenth or less of the price of new text.
- Context newly written. Whatever is new since the last request (a file just read, a command result, a picture) is written into the cache once, at a premium.
- Output. What the model produces: its private reasoning ("thinking"), the prose you read, and the arguments of the tool it calls, which is where the code, the shell commands and the briefs live. The typical request produced 391 output tokens and cost $0.13.
table view
| thinking | code, commands and briefs (tool arguments) | prose you read | total | |
|---|---|---|---|---|
| output | 37 % | 61 % | 2 % | 100 % |
Thinking from the API counter; the visible remainder split between tool arguments and prose by character count. Source: phase6_examples.py.
How $1,498 adds up from requests that cost cents. 8,058 requests at a mean of $0.19. 7,036 of them cost under 25 cents and together make $879; the most expensive 1 % carries 15 % of the money, the top 10 % carries 38 %. The eight most expensive requests of the phase were not the productive ones: every one was a context re-write after a cold cache, the top two at $11 and $10, both by the lead on 16 Sep with a 528,000-token context, producing 453 and 1,007 output tokens. The most expensive request on a warm cache cost $2. The request that produced the most (21,167 tokens, a whole 692-line script) cost $0.63.
What those tokens became. Lines added to the project on all branches over the four days (docs/usage/phase6_lines.sh): 19,300 in the export and packing scripts, 11,000 in the viewer JavaScript, 6,100 in the bake scripts, 4,900 in the viewer tools and tests, 3,800 in the critic probes, 1,800 each in reviews and briefs, 1,600 in QA reports, 1,100 in the status, decisions and delivery notes. About 55,000 lines that a person could read, plus 820,000 lines of machine-generated capture metadata.
Almost none of what the agents produce is prose for a person. Three fifths is code, shell commands and briefs; a third is reasoning that nobody reads. Here are real requests from the week, one per kind of work, with their exact counts. The thinking itself cannot be shown: the transcript stores each thinking block as an empty string with a signature, so only its size survives. What can be quoted is the visible reasoning the agent wrote before or after its tool call, and those excerpts are below, unedited apart from length.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 277,295 | 1,069 | 825 | 863 | 280,052 |
- Who, when
- lead on fable-5-1, 15 Sep 11:55; cost $0.18
- What it wrote (first lines)
- My recommendation, taking "impressive but fluid" as the brief: **1. Ornament: option (c), instancing with a 256 px per-instance lightmap slot.** The capitals, maidens and urns are what make the building read as carved rather than extruded, and their sun-to-shade turn is the single strongest depth cue in the hero frame. Option (b) flattens every capital to the sky average; option (a) costs 29 h of GPU and 4.3 GB for no visible gain at hero distance (a capital is 68 px wide at 4K). Option (c) keeps the contrast for 3.3 h of bakes and 451 MB on desktop, and it stays fluid because the geometry is still instanced (198 k unique triangles, ~13 draw calls for all 436 placements). Mobile gets (b) at 1K as its fallback. **2. Trees: impostors beyond 25 m of the walkable area, thinned LOD1 for the ~20 trees you can walk up to.** This is the decision that decides both goals at once. Leaf cards as shipped are 3.3 M triangles of alpha-tested overdraw, which is exactly what makes a fanless M2 stutter at 1440p, and they still look flat because there is no translucency. Impostors are a few hundred qua...
- Thinking
- 825 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 142,376 | 5,179 | 6,106 | 15,061 | 168,722 |
- Who, when
- export engineer on opus-5, 15 Sep 12:08; cost $0.63
- Tool call
Write .claude/worktrees/phase6-export/export/gate1_set.py (692 lines)- What it wrote (first lines)
- Now the main Gate 1 export set builder.
- Thinking
- 6,106 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 54,444 | 7,284 | 6,913 | 152 | 68,793 |
- Who, when
- code reviewer on opus-5, 16 Sep 15:11; cost $0.25
- Tool call
Bash: cd "/Users/dk/Projects/3d render blender 3rd attempt building" && git diff 0b08a6b 08e9262 -- web/src/manifest.js web/src/main.js .gitignore- Thinking
- 6,913 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 138,057 | 12,376 | 3,622 | 765 | 154,820 |
- Who, when
- QA critic on opus-5, 17 Sep 11:01; cost $0.26
- Tool call
Bash: cd "/Users/dk/Projects/3d render blender 3rd attempt building" && python3 - <<'EOF' import json from pathlib import Path V=Path(".claude/worktrees/phase6-viewer/renders/web") d=json.load(open(V/"round16b_perf.json")) pri...- What it wrote (first lines)
- Tiles reviewed. Now the measurements , let me check the sidecars and build the round-16 probe.
- Thinking
- 3,622 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 310,031 | 600 | 0 | 390 | 311,021 |
- Who, when
- bake engineer on opus-5, 15 Sep 17:56; cost $0.17
- Tool call
Bash: cd "/Users/dk/Projects/3d render blender 3rd attempt building/.claude/worktrees/phase6-bake" && until python3 -c " import json,sys d=json.load(open('export/out/bake_queue/status.json')) sys.exit(0 if d['state'] in ('idle...- What it wrote (first lines)
- 31/60, no failures. The ORN bakes confirm the selected-to-active path: cages match Gate 1 exactly (attic figure 0.0098 m, attic panel v1 0.0636 m) and the normal maps carry real relief (std 0.056–0.165 vs 0.009 for the material-bump-only ARCH maps). Roughly 30 minutes left.
- Thinking
- 0 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 285,964 | 7,432 | 0 | 2,463 | 295,859 |
- Who, when
- lead on fable-5-1, 17 Sep 07:28; cost $0.34
- Tool call
Agent: 6c bake: impostor diagnosis, tree AO | brief: You are the Phase 6c bake engineer (Opus 5, xhigh effort) on the Palace of Fine Arts Blender/three.js project. Your brief is `docs/briefs/phase6c_bake.md` in th...- Thinking
- 0 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 204,906 | 2,904 | 6,503 | 456 | 214,769 |
- Who, when
- export engineer on opus-5, 17 Sep 09:40; cost $0.29
- Tool call
Bash: cd "/Users/dk/Projects/3d render blender 3rd attempt building" && python3 -c " import json, math m=json.load(open('export/out/gate3/manifest.json')); imp=m['impostors'] print(f\"{'prototype':34s} {'bboxXY/2 diag':>13s} {...- What it wrote (first lines)
- Confirmed the anchor bug , and I've found a second, subtler problem it creates. Let me verify the correct anchor against the impostor's own recorded geometry first.
- Thinking
- 6,503 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 382,705 | 2,800 | 979 | 388 | 386,872 |
- Who, when
- viewer engineer on opus-5, 17 Sep 09:44; cost $0.24
- What it wrote (first lines)
- Waiting on the two preconditions (bake idle ✓, COLOR_0 in the re-packed `env_trees.glb` , not yet). The blocking wait is running in the background; everything else is done and committed. Progress so far: - **Review blocker fixed and proved**: the mesh/impostor dissolve now partitions `[0,1)` exactly (mesh discards `hash >= vPfaFade`, impostor `hash < 1 - vPfaFade`), checked numerically and against both shader strings in a new node test. - **Items 1–3 coded and unit-tested** (`web/src/foliageLazy.js`, 194 PASS in `npm test`), plus the lead's placement gate, which on the shipped `env_trees.glb` reports **127/127 meshes over tolerance, worst trunk offset 905.1 m** , the export defect the lead warned about, caught automatically, meshes not drawn, impostors kept. - The bake's `instance_irradiance.json` is already proved end to end: 127/127 joined, 16/16 `E_bake`, ratios 0.027–2.048 in `full` mode, nothing on the 4.0 clamp.
- Thinking
- 979 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
The expensive kind of nothing: cache misses
What the cache is. Nothing restarts and no agent loses its memory. The model provider keeps the front part of each conversation (everything already sent) in a short-lived store, so the next request can re-read it at about a tenth of the price of new text instead of sending it as new. Each request that hits the store extends its life. In this project, every specialist agent ran with the five-minute lifetime and the lead ran with the one-hour lifetime (visible in the transcripts: the specialists' cache writes are all five-minute writes, the lead's are all one-hour writes). When the gap between two requests exceeds the lifetime, the store is empty, and the whole conversation is written into it again at the premium rate (1.25 times the price of new text for the five-minute store, 2 times for the one-hour store) before the reply is produced.
What it cost. In Phase 6, 170 requests met an empty store and re-wrote their whole context (a miss = a request that wrote more than 20,000 tokens while reading almost none). Those re-writes cost $349; had the same context been read warm they would have cost about $25, so the premium was $324, 21.5 % of the phase. For the light bakers it was 47 % of everything they cost, because they watched hour-long bakes with ten-minute sleeps and every poll came back to a cold store. Across the whole project the premium is $844 of $4,000, 21.1 %.
What a longer lifetime would have done. Replaying the same conversations with the same gaps: with the one-hour store for every agent the phase would have cost about $1,339 instead of $1,505 (91 misses instead of 170); with the five-minute store for every agent including the lead, about $1,823. Project-wide the one-hour store everywhere comes to about $3,731 against $4,000. The cheaper fix is not to poll: sleep under five minutes, or let the job wake the agent. Source: docs/usage/cache_analysis.py.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 0 | 353,143 | 0 | 267 | 353,410 |
- Who, when
- bake engineer on opus-5, 16 Sep 02:08; cost $2
- Tool call
Bash: cd "/Users/dk/Projects/3d render blender 3rd attempt building/.claude/worktrees/phase6-bake" && end=$(( $(date +%s) + 575 )); until [ "$(python3 -c "import json;print(json.load(open('export/out/bake_queue/status.json'))[...- Thinking
- 0 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
table view
| context re-read from cache | context newly written | thinking | visible output | total | |
|---|---|---|---|---|---|
| tokens | 23,148 | 305,966 | 347 | 727 | 330,188 |
- Who, when
- lead on fable-5-1, 18 Sep 22:59; cost $6
- What it wrote (first lines)
- Nothing is required. The project is delivered against every definition of done you set: the Phase 5 Blender deliverables, the 6a local viewer at parity, 6c closed by the two-round rule, and 6b live with one clean QA round. What remains falls into three groups, in order of value. **Owed evidence, yours, five minutes** 1. A 30 s walk on the iPhone, screen-recorded, ideally in landscape. It confirms the walk controls and the frame rate on the device; the screenshot only proves loading. 2. One Safari screenshot at the hero on the Mac. Every desktop capture so far is headless Chrome, so no Safari claim exists yet. **Residuals worth a small follow-on phase, if you want the phone experience to match the desktop** 3. The mobile water reflects nothing, so the lagoon is a flat gradient and station 6 goes near-black. A reduced reflection set on the mobile Reflector is a small viewer change, then one mobile recapture and a QA look. This is the one I would do. 4. Portrait framing: the building sits small and centred. A portrait sensor fit per station is a design choice more than a fix. 5. Cosmeti...
- Thinking
- 347 tokens, billed as output; the text of thinking is not stored in the transcript, only its size.
This week against the build week
table view
| build week (6 to 10 Sep) | Phase 6 (15 to 18 Sep) | |
|---|---|---|
| wall clock, h | 100 | 96 |
| agent work, h | 42 | 34 |
| chip busy, h | 33 | 25 |
| blocked on user, h | 0 | 30 |
| idle, h | 53 | 31 |
| agents | 114 | 74 |
| cost, $ x 10 | 148 | 150 |
Cost shown in tens of dollars so it fits one axis. The build week lost its hours to renders killed by a watchdog and three flat polish rounds; this week lost them to hand-off defects found one gate late and to questions asked after the user had left.
Both weeks cost about the same nominal money ($1,483 against $1,505) and both took about four working days. The build week bought a score of 3.61 from nothing; this week bought the same score in a medium that runs on a phone. Per point of score gained it was expensive ($254 for the only gate that raised the hero score, +0.33), but a walkthrough is not a score, and the points it did gain came from things a still picture cannot show: rippling water and trees you can walk up to.
So: what took the time, what did it cost, was it worth it?
Time. 86 hours from the first prompt to the last deploy, of which 34 were agents working, 25 the graphics chip baking (mostly under a watching agent), 30 waiting for the user, 21 with the user away and nothing blocked. Of the working hours, the largest slices went to a pipeline whose three halves disagreed about small conventions, each found one gate late.
Cost. $1,505 nominal, 88 % of it Opus 5 builders and critics, 12 % the lead. Whatever the subscription meter said, it was the same order as the build week.
Worth it. The stated goal, a walkthrough at parity with the render that loads on an iPhone in under 50 MB, exists at the link above and was scored on the live address. Two of its promises (a measured walk on the phone itself, Safari proper) were never evidenced, and one rule (score against the photo) was skipped. The user thought it worth continuing: Phases 7, 8 and 9 followed in the same week and lifted the hero to 4.05.
Glossary
- Blender, Cycles
- Free 3D software; Cycles is its light simulator, which produced the reference renders.
- Render
- A still picture computed by simulating light; minutes to hours per frame. A viewer draws sixty frames a second and cannot simulate light, so light is baked.
- Triangle
- The flat facet every 3D surface is built from. Decimation reduces their number.
- Normal map, lightmap, texture
- Images pasted on surfaces: a texture carries colour, a normal map carries the small bumps, a lightmap carries the baked light and shadow.
- Bake
- Computing something once in Blender (light, colour, bumps) and storing it as an image for the viewer to look up.
- KTX2, meshopt, gltfpack
- Compression formats and the tool that applies them so the files stay small on the wire and in the graphics chip's memory. The packer's defaults caused three of the week's loops.
- Gate
- A checkpoint where a critic agent scores the work on a 5-point rubric and reviews it at 100 % zoom; work moves on only on a pass.
- Hero
- The main viewpoint, from across the lagoon, the one the photograph shows.
- Deploy, merge
- Deploy: publish the built site to the web host. Merge: fold a specialist's branch of changes into the main code after review.
- Token
- The unit AI models read and write in, about three quarters of a word. Re-reading cached context is much cheaper than new text.
- Nominal cost
- What the tokens would cost at public list prices. The account is a subscription, so no invoice matches.
- Lead, subagent, critic, reviewer
- The lead (one AI session) plans and merges; it dispatches specialist subagents (bake, export, viewer), a critic per gate, and a code reviewer before every merge.
- Tier
- A download batch: tier 0 is what you get before the first picture (47 MB), tiers 1 and 2 stream afterwards.
Sources: the git history on every branch, docs/status.md, docs/decisions.md, docs/qa_round_11 to 19, docs/reviews, docs/delivery.md, the render and capture folders, and the Claude Code transcripts (token counts, models, tool calls, timestamps) read by docs/usage/usage_from_transcripts.py. Built by docs/usage/make_phase6_story.py from docs/usage/phase6_audit.json. Times are local (Vienna).