Chapter 16: Watching the trees grow Frozen 25 September 2026. Original development excerpts; these contain internal terminology. SOURCE: docs/visual-handoff.md (frozen copy) 1: # Visual development handoff 2: 3: ## Start here 4: 5: **Owner request: a smaller fullscreen UI, and a part tray that hides (25 September 2026, after the entry below).** The owner wrote: "the current scale of the UI is too large when in full screen, it should be about 20% smaller. Once the item is selected the UI should auto hide, currently it blocks a lot of the view, i only want to see the UI when I am selecting a new item to place ideally". Opus 5.5 made both changes. 6: 7: - **Scale.** `main.gd` has a new `UI_GROWTH = 0.8`. `resize_viewport` now sets the UI scale to `max(1, min(width/1440, height/900) × 0.8)` and derives `content_scale_size` as the window size ÷ that scale. At 2880 wide the UI is 1.6× instead of 2× (20% smaller). At 1920×1080 it is 1.0× instead of 1.2×. Below about 1800×1125 it is 1:1, which is how it looked before this morning. 8: - **Tray.** `EditorUI.tray_open` controls the part tray. It starts open. Picking a card closes it, and the part stays chosen. A category button in the dock opens that category's tray; clicking the same category again closes it and the button stays marked. Choosing the Select tool (the button or V) closes it. A selection made by clicking in the world leaves it closed. Photo mode and Scenery hide the tray as before. The settings panel on the right is unchanged: it keeps its own show/hide button. 9: - **Test fix found on the way.** `tests/test_ui.gd` runs `EditorUI` without `Main`. Since this morning's project stretch setting, its root scaled the UI to 0.76, so its window-pixel clicks missed. The test now sets `root.content_scale_mode = DISABLED`, matching what `Main` does below 1440×900. The morning's run did not include `test_ui`; whether it failed after that change alone was not confirmed. New checks cover opening, picking, reopening, closing on the same category, switching category, Select, and world selection. 10: - **Backups.** `backups/ui-autohide-20260925/` has `editor_ui.gd`, `main.gd` and `test_ui.gd` from before this change. 11: - **Tested (macOS, pinned 4.6.3).** `test_ui` 333 checks, 0 failures (`artifacts/ui-scale-0925/test_ui.out`). `test_look` exit 0. `--smoke` at 1440×900, 1920×1080 and 2880×1800 all exit 0 with no script errors (`artifacts/ui-scale-0925/r2//editor.png`). `--verify` at 2880×1800: `PIXELPUNK_INTEGRATION []` (`r2/verify/`). 12: - **Windows export (re-done after this change).** The previous `build/windows/` files (exe `84cb5e4e...`) were copied to `build/backup-ui-scale/windows-before-autohide/`. The earlier Desktop zip was no longer on the Desktop, so it was not backed up. `--export-release Windows` with the pinned engine exited 0 (`artifacts/ui-scale-0925/export-windows-2.{out,log,exit}`); the new exe is `c8533316...`. The zip is `~/Desktop/PixelPunk-Windows.zip`, with the same `PixelPunk/` layout and the `START HERE.txt` from `build/PixelPunk-Windows.zip`. The exe inside the zip has the same hash. It was exported, not run. 13: - **Not tested.** The full suite; hand play of the tray flow in a real window; running the exe on Windows. 14: 15: **Owner request: the UI grows with the window (25 September 2026).** The owner wrote: "when going full screen from the small window the UI is tiny, can we get it to grow in proportion with the window?" Opus 5.5 made the change and verified it. 16: 17: - **Cause.** `project.godot` had no stretch mode, so the UI was drawn at one UI pixel per window pixel. A fullscreen window (especially Retina) got more pixels, and the UI stayed the same pixel size. 18: - **What a person sees.** The layout is designed for 1440×900. A larger or fullscreen window scales the whole UI up by `min(width/1440, height/900)`: 2× at 2880 wide, 1.2× at 1920×1080. A window smaller than 1440×900, down to the 1100×700 minimum, stays at 1× and lays out at its own size, as it did before, so small text stays crisp. The 3D view is unchanged: it still renders at window pixels ÷ the pixel size (for example 1440×862 internal for a 2880×1724 window). 19: - **How.** 20: - `project.godot` `[display]`: `window/stretch/mode="canvas_items"`, `window/stretch/aspect="expand"`. 21: - `main.gd::resize_viewport` (already connected to the root viewport's `size_changed`): sets `get_window().content_scale_size` to the smaller of the design size and the window size on each axis. This stops the UI shrinking below 1×. The pointer mapping (`screen_point`, `replay_press`) already worked in visible-rect units, so it needed no change. 22: - **Backup.** `backups/ui-scale-20260925/project.godot` is the pre-change settings file. The `main.gd` change is the six lines at the top of `resize_viewport`; the backup did not include `main.gd`. 23: - **Tested (macOS, M3 Pro, pinned 4.6.3).** 24: - `--smoke --lighting=day` at 1440×900, 1920×1080, 2880×1800 (clamped to 2880×1724 by the screen) and 1100×700: all exit 0, no script errors. Captures are in `artifacts/ui-scale-0925/floor//editor.png`. The earlier run without the 1× floor is in `artifacts/ui-scale-0925//`; there, 1100×700 shrank the UI to 0.76 and its text was blurry. 25: - `tests/test_look.gd` via `tools/run_tests_mac.sh`: exit 0 (`artifacts/ui-scale-0925/test_look.out`). 26: - `--verify` at 1440×900 and 2880×1800: `PIXELPUNK_INTEGRATION []` both times, 56 captures each (`artifacts/ui-scale-0925/verify-/`). 27: - **Windows export (same day, owner request).** The previous `build/windows/` files were copied to `build/backup-ui-scale/windows-before/`. Then `Godot --headless --export-release Windows build/windows/PixelPunk.exe` ran with the pinned engine and exited 0 (`artifacts/ui-scale-0925/export-windows.{out,log,exit}`). The new exe's SHA-256 is `84cb5e4e...`. It was zipped with README, notices and the old archive's `START HERE.txt` under `PixelPunk/`, and saved to the owner's Desktop as `~/Desktop/PixelPunk-Windows.zip`; the exe inside has the same hash. `build/PixelPunk-Windows.zip` is still the 17 September archive. The exe was exported, not run. 28: - **Not tested.** Windows and Linux builds; a real macOS fullscreen toggle by hand (the runs use `--resolution`); the full suite (`tools/test.sh`); the exported app. 29: 30: **Owner request: trees that grow their branches (T4b, 25 September 2026, after the style pass below).** The owner wrote: "Plan and execute the trees growing organically with branches." Opus 5.5 did the plan and the implementation; Sonnet 5 (`facade-reviewer`, read-only) reviewed it. The plan, and what was built against it, is `docs/tree-growth-animation-plan.md`. 31: 32: - **What a person sees.** A tree, blossom or evergreen placed in the editor grows out of its trunk in about 2.2 s (`BuildAnim.tree_grow`: 1.4 to 4.5 s, as the square root of its height). It starts as a sapling, and the trunk rises. Limbs push out of their parents, thick ones first, each tapering to a growing tip. Leaf clumps bud with a small swell as the growth reaches them. An evergreen's tiers bud from the bottom up. The old 0.35 s scale-in and the sway still run on top. 33: - **How.** 34: - `TreeGrowth.build` (with no obstacles) turns on the new `MeshBatch` growth log. `TreeGrowth.growth_morph` bakes two float4s per `plain` and `leaf` vertex: 35: - a limb: its tube start, and the weighted growth distance from the foot, with the axis times a thinness weight; 36: - a leaf piece: the nearest point on a limb, and the distance there. 37: 38: The bake costs about 1 ms per stage mesh (`growth/probe.gd`). 39: - `Architecture.grown_arrays` and `grown_mesh` write the morph as CUSTOM2 and CUSTOM3. Surfaces shared by every instance (the limbs) wear the new growth copies of leaf and plain (`Architecture.growth_materials`, uniform `growth`); the crowns wear the grown copies. 40: - `grown.gdshaderinc::grown_morph` morphs the vertex by `INSTANCE_CUSTOM.b`, the growth still to come. It runs in `plain_body.gdshaderinc` and `foliage.gdshader`. When settled (b = 0), a vertex is exactly what it was. 41: - WorldView gives a newly planted, non-host tree `deco_anim[id].grow` and writes `.b` each tick (`_set_growth`), and again on a mid-growth rebuild. 42: - The shader warm-up draws the growth copies on a default tree's morphing mesh. 43: - `--tree-grow=` holds every grown tree at `b` for stills. Automation builds settled unless `--animate` is passed. 44: - **Not done (open).** A resize still swells per stage (STAGE_POP); it does not regrow. A host tree, one built round a house or a building it touches, does not grow. The side_blossom sheet's 23.6 m blossom is one of these, since it touches the canal house. 45: - **Tests** (after the review fixes). 46: - Full suite: `bash artifacts/trees/growth/final.sh` → `growth/full2.out` (logs in `growth/suites/`). 40 suites, 18,276 checks. The one failure is the known battery timing check, `test_creature_reactions` "The re-plan is applied after the edits", which failed on both runs. 47: - `--verify`: `PIXELPUNK_INTEGRATION []`. 48: - New or changed: 49: - `test_tree_growth` 161: `growth_checks` covers: 50: - morph sizes and one shared total; 51: - limb vertices on their axis, growth starting at the foot, leaf lobes sharing one anchor on the tree; 52: - determinism, and a bigger tree growing further; 53: - no morph on a host tree or on the stone ring, and evergreen tiers budding from the trunk; 54: - CUSTOM2/3 on the grown limbs and leaves (none on the stone), limbs common with their morph, settled without growth materials, and the growth-copy switches; 55: - the shader order, and the timing curve. 56: - `test_build_anim` 413: a planted tree starts at b > 0.9, is part grown half way, and is exactly settled with its entry gone at the end. The two "props are forgotten" waits now allow for the growth. 57: - `test_warmup` 32: the growth copies are warmed on a surface carrying CUSTOM3. 58: - **Captures.** 59: - `growth/strip-{side_tree,side_blossom,conifers,giants}.png` (`growth/final.sh`, via `strip.sh` and `captures.sh`): the plan's stills at b = 0.9, 0.7, 0.5, 0.3, 0.1 and 0, top to bottom; the frames are in `growth/cap/`. 60: - At b = 0 the trunk and ground band of side_tree matches the style pass's `side_tree-final` at PSNR 48.3 dB. 61: - Real-time planting in the editor (`growth/plant.sh`, `--drag=plant.json` with `--animate`, filmstrip at 0 to 2,400 ms; worst drift 4.7 ms): `growth/film-plant-all.png` (tree, blossom, evergreen). 62: - The place step's one ~210 ms frame is the same before and after (`plant-pre-*`, `plant-live-*`). 63: - Development stills are in `growth/cap-dev/` and `growth/strips-dev/`. 64: - **Frame cost with nothing growing, on battery.** Interleaved against the pre-T4b copy (`growth/setup_pre.sh` → `growth/scratch-pre`), with `--disable-vsync`. 65: - First design (`growth/bench.out`): dense 19.84 → 19.95 ms mean (+0.5%). The forest cost +4.9%. An A/B (`bench/exp-*`) put about 0.4 ms of that on shared surfaces moved into the grown material (CUSTOM1), hence the growth copies. 66: - Final design (`growth/bench2.out`): forest 13.48 → 13.80 ms mean (+2.4%), p95 18.51 → 19.08 ms (+3.1%); giants 10.50 → 10.68 ms (+1.7%), p95 13.97 → 14.09 ms (+0.9%). 67: - The remaining cost is CUSTOM2/CUSTOM3 bandwidth: 32 bytes a vertex on tree stage meshes, also memory. 68: - **Exports** on the final code (`growth/exports.sh` → `growth/exports2.out`). 69: - The builds replaced were kept in `build/backup-trees/growth-exports/{macos,windows}-before/`. `tools/build.sh` and the Windows preset exited 0, and codesign verified. 70: - SHA-256: 71: - Mac binary: `e1957eba4ba241b3830af2eae9d7d896bc60f4f85cf682874bb31cd17d9b3ec1` 72: - `PixelPunk.pck`: `4ae6352939570b03b6c92adead7f0f56930c957e8156b8ee1dfc1dc2e58811ba` 73: - `PixelPunk.exe`: `f4a874300494fc2c7fd07e896a2793de0a77e43e461105a091565135e6bc740a` 74: - Standalone Mac smokes all passed: plaza, giants, the grove held half grown (`growth/standalone-grove`), and the planting film (`growth/standalone-plant`, `growth/film-standalone-plant.png`). 75: - Not run: the Windows build, and the warm-up in the standalone app (smokes skip warm-up). 76: - **Backups.** `build/backup-trees/growth-anim/` holds every touched file before T4b, including the docs. 77: 78: **Owner request: a better tree style, and evergreens (25 September 2026, after the polish pass below).** The owner wrote: "polish this off. however, if you think there is a better visual style for the trees to acheive this please do so. I think they currently look poor, it would be nice to have some evergreens as well." Opus 5.5 did the implementation; Sonnet 5 (`facade-reviewer`, read-only) reviewed the code. Evidence is in `artifacts/trees/style/`. Backups taken before any edit are in `build/backup-trees/style/`. The five one-line list files that were edited without a prior copy are reconstructed in `build/backup-trees/style/reconstructed/`: each differs from the live file by exactly its one edited line. 79: - **Why they looked poor** (lookfix and polish captures): 80: - every lobe was lit as its own ball with its own dark rim, so a crown read as a pile of bubbles; 81: - trunks were pale lavender poles (`BARK` 55505a under the sun); 82: - the default tree was a lollipop: leaves from 2.2 to 3.6 m on a bare 2 m pole. 83: 84: The reference (`artreference.png`) has one dense crown mass, lit on one side and dark underneath, low on a short dark trunk. 85: - **What changed.** 86: - **Crown normals.** 87: - `Architecture.canopy()` takes an optional `crown` [centre, radii, blend]. `Architecture.crown_normals()` then bends every leaf normal it drew towards that ellipsoid's normal, with the downward part capped at `CROWN_DOWN` 0.3 and the field lifted by `CROWN_UP` 0.3. No vertex moves and no random number changes. 88: - The crown then lights as one mass, and the foliage shader's rim outline falls on its silhouette. 89: - Trees and blossoms use a blend of `CROWN_BLEND` 0.75, easing to 0.525 by 18 m so giant crowns keep some variety. Shrubs use 0.7. 90: - The shader is unchanged. 91: - **Broadleaf proportions and bark** (`scripts/tree_growth.gd`). 92: - `BARK` is 4a3a33 and `LIMB` 5a473d. 93: - The crown-line constants are now per kind (`WHORL_Y`, `WHORL_TIP`, `DROP`, `WHORL_CLEAR`, `YOUNG_TINT`, `YOUNG_BASE`). A tree's young crown starts lower: whorl at 0.95–1.4 m, crown base 1.45 m, drop 0.2 m. The blossom keeps its parasol values. 94: - `clear_y` is unchanged, so old trees' limbs and the houses they carry sit where they did. The first attempt lowered it too, which gave a 3.5 m house through a pitched roof two carriers and failed `test_tree_house`; that was reverted. 95: - `_young_depth` sets the shell count on the new default depth, so the default tree keeps its 2,500-triangle budget. 96: - Default tree (`style/probe_default.log`): leaf top 3.83 m, bottom 1.79 m, width 2.00 m. The blossom is 3.43 m, 2.23 m and 2.38 m, unchanged in look. 97: - **Evergreens.** A new kind, `conifer`, titled "Evergreen" in the Garden palette (`data/catalog.tres`). 98: - It is in `TreeGrowth.KINDS`, so it shares `grow_h`/`grow_w`, the stages, the grips, the Height/Spread inspector and validation. 99: - Its band is 0.3 to 0.7 H at 4.2 m, narrowing to 0.45 H at the top (`CONIFER_BAND`). The default spread is 0.42 H, 1.76 m at 4.2 m. 100: - `build_conifer` draws a straight trunk under 3 to 12 stacked tiers (`conifer_tiers`, spacing 0.55 m at 4.2 m to 1.9 m at 23.6 m). Each tier is a 9-sided leaf cone (`MeshBatch.foliage_cone`, the same UV stamp as `foliage()`) that reaches into the next, with scalloped lumps on its hem. 101: - The colour is blue-green `CONIFER_GREEN` 2e5f49, lighter towards the top, and it honours `params.grow` fullness and hue. 102: - `crown_base`, `crown_radius` and `crown()` answer for it, so picking and the plants around it read a cone. 103: - It hosts no house: `TreeGrowth.can_host` is used by `TreeHouse._tree_spots`, `Adapt._perch` and `WorldView.pick_crown_ray` (the last came from the review). 104: - It is registered in `DioramaState.KINDS` and dimensions, the `Architecture.decoration` match, `Composition` (foliage kinds, sky eye, crowns, water planting, and the seeded yaw but no lean), `BuildAnim.SWAYING`, the build and scenery audio, the creature foliage list, and `WorldView.grown_tree_meshes`. 105: - Scene version 2 is unchanged. An old file has no conifer, and a file with one fails only on a build that predates the kind. 106: - **Tests.** 107: - `test_tree_growth` has 116 checks: 108: - `conifer_checks`: kind and catalog; band; a sized conifer validates and an over-wide one is refused; every vertex in the stage box at five heights × three habits; `TRI_CAP` at every stage and for every grown variant at 23.6 m; tier UV stamps; tiers grow with height; default ≤ 2,500 triangles; determinism by seed; the crown narrowing; no house carried. 109: - the crown-normal check; 110: - the default-look checks retargeted to the new tree (the blossom still against its old numbers), and the crown band and crown base checks to the new line. 111: - `test_tree_house` has 160 checks: a ray into a conifer does not perch. 112: - **Tested behaviour, on battery.** 113: - Full suite before the review fixes (`bash artifacts/trees/style/full2.sh all` → `style/full2-prefix.out`, logs in `style/suites/`): 40 suites, 18,225 checks. The one failure is the known battery timing check, `test_creature_reactions` "The re-plan is applied after the edits"; it failed on both its runs. 114: - After the review fixes, the suites that read the changed files were rerun (`style/suites-fix.out`), all with 0 failures: `test_tree_growth` 116, `test_tree_house` 160, `test_tree_grips` 72, `test_adapt` 635, `test_ui` 325, `test_building_tools` 669, `test_owner_0924` 87. 115: - The earlier all-suite run also had `test_foliage` 97, `test_foliage_merge` 80, `test_nature` 259, `test_scene` 588, `test_composition` 155, `test_build_anim` 410 and `test_starters` 176, all with 0 failures. 116: - `--verify` on the final code: `PIXELPUNK_INTEGRATION []` (`style/full2.out`). 117: - **Frame cost** (`style/bench.sh` → `style/bench.out`), on battery. The pre-style scratch copy (`style/setup_pre.sh` → `style/scratch-pre`) was interleaved with live, three rounds each, with `--disable-vsync`. 118: - `dense.json`: mean 19.98 → 19.98 ms, p95 22.36 → 23.06 ms (+3.1%), 1966 draw calls both. 119: - `giants.json`: mean 10.12 → 10.22 ms (+1.0%), p95 12.90 → 13.34 ms (+3.4%), 731 draw calls both. 120: - `style/forest.json` (60 conifers, 26 trees and 14 blossoms, 3–16 m; `style/make_forest.gd`), live only because the pre-style code has no conifer: mean 13.29 / 13.58 / 13.56 ms, p95 about 18.4 ms, 938 draw calls. 121: - All within the 10% p95 budget. The bench ran before the review fixes, which touch picking, a comment and tests, not drawing. 122: - **Captures** (`style/captures.sh final` → `style/cap/*-final/`, with the lookfix, polish and T8 cameras). 123: - `style/before-after.png`: the quarter at 13:00, the plaza and the height sheet; before on the left (lookfix and polish), after on the right. 124: - `style/evergreens.png`: the conifer sheet (`style/conifers.json`, six heights, default and wide habits) and the grove from the exported Mac app. 125: - `style/shrub-compare.png`: plaza shrubs before and after crown normals. 126: - `style/cap/tool-conifer/editor.png`: the palette card and inspector. 127: - Generators: `style/make_scenes.gd` (conifers, grove) and `style/make_forest.gd`. 128: - **Exports** on the final code (`style/exports.sh` → `style/exports2.out`). 129: - The builds replaced were kept first in `build/backup-trees/style-exports/{macos,windows}-before/`. They are the polish-era builds; `build/macos` is also the other session's share build. 130: - `tools/build.sh` and the Windows preset both exited 0, and codesign verified. 131: - SHA-256: 132: - Mac binary: `e2b75b991922a3da2fc1c23d95269798af00be8172ccc89ad500019ca58bf5fe` 133: - `PixelPunk.pck`: `d2e0c2e13c807b5ae4fe5faf2a4ddf60594aac1d6e13687b0df1acaef65400d6` 134: - `PixelPunk.exe`: `d99c5b6ae7f25392c6e5e831f234c345b29b17e0fb7eff28a40f4ae7316af493` 135: 136: These supersede the final round's and the polish pass's hashes below. 137: - Standalone Mac smokes (`style/standalone`, `standalone-giants`, `standalone-grove`) all exited 0 with `capture_failures []`. 138: - **Review** (Sonnet 5): no must-fix correctness bugs. It verified the registrations, the seed-only determinism, the conifer dispatch before any grammar code, the packed-array copy-back and the unchanged shader. Acted on: 139: - `pick_crown_ray` still offered conifers as perch targets. Fixed, with a test. 140: - Grown-variant triangle coverage for conifers. Test added. 141: - A comment explaining that only a conifer's hem lumps are bent. 142: 143: It also flagged the creature failure for confirmation; it is the known battery check (above). 144: - **Not run or not done.** 145: - Windows was exported, not run. 146: - No drag-harness run. 147: - No second-model review of the look itself. 148: - Conifers have no per-tier growth animation; they pop a tier at stage changes, with the overshoot. 149: - House A's far side is still bare (crown-box clamp). 150: - House E's trunk still shows above its roof. That is by design: the collar clearance keeps the lobes off the collar, and with the brown bark it now reads as a trunk rising through the roof. 151: - T4b, the per-limb growth animation for broadleaf trees, was not done at this checkpoint. It was built afterwards; see the "trees that grow their branches" entry above. 152: - **Reproduce.** 153: - `bash artifacts/trees/style/full2.sh all` 154: - `bash artifacts/trees/style/setup_pre.sh && bash artifacts/trees/style/bench.sh` 155: - `bash artifacts/trees/style/captures.sh ` 156: - `bash artifacts/trees/style/exports.sh` 157: - `bash tools/run_tests_mac.sh artifacts/trees/style/make_scenes.gd `, the same for `make_forest.gd`. 158: - Run windowed steps with the sandbox off and nothing else rendering. 159: TREE POLISH (same frozen source) 245: - **Polish pass, big trees** (25 September 2026, after the final round; Opus 5.5, one session, not reviewed by a second model). Three of the known limits below, all in `scripts/tree_growth.gd` (backup of the five tree files before it: `build/backup-trees/polish/`). Evidence: `artifacts/trees/polish/`. 246: - **Dark lower lobes.** An old crown's leaf ramp darkened its lowest leaves by 0.55 at the crown bottom. It now darkens them by `DARK_OLD` 0.3, blended in by `youth()`, so trees up to 5 m keep the old ramp exactly. 247: - **Bare limbs under the crown.** A scaffold limb nothing on which reaches the crown base is now shed from the drawing, like the whorl. This applies only once the crown base is above `WHORL_CLEAR`, so young trees are untouched. `grow()` is unchanged. 248: - **Giants as clumps on sticks.** Under the triangle cap the filling list (leader covers, fills, limb covers) was cut from its tail, so a giant lost every limb cover. `_spread_first` now reorders it before the cut, putting one lobe per free grid cell (`COVER_STEP` lobe radii) first. `LOBE_RX_MAX` went from 1.15 to 1.45 m. That changes lobes only on crowns wider than about 12 m (tree) or 7 m (blossom), and so the envelope and leader heights there. 249: - Probe (`polish/probe_big.gd`; `probe_big-before.txt` against `probe_big-after2.txt`; three seeds per size): 250: - default 4.2 m trees and blossoms are identical in every number; 251: - lowest-fifth leaf luma of trees from 8 m up rose from about 0.19 to about 0.28 (default tree 0.30); blossoms from about 0.35 to about 0.50 (default 0.48); 252: - bare scaffold limbs at 23.6 m fell from 8–17 to 0–3. 253: - Captures (`polish/captures.sh after2` → `polish/cap/*-after2/`, same cameras as `lookfix/sheet`, `lookfix/host` and the final giants smoke). The before/after sheet is `polish/before-after-sheet.png`: giants (the final standalone capture) and the height sheet (`lookfix/sheet/side_tree`) on the left, this pass on the right. 254: - The giants now read as closed crowns. 255: - Host A lost its bare stub and its black lobe under the house. 256: - The first round (`*-after`, cap still 1.15) fixed the tint and the bole but left the giants stringy. 257: - Tests: `test_tree_growth` gains `polish_checks`, making 100 checks: 258: - an old crown's lowest leaves within 15% of the default crown's brightness, at 12 and 23.6 m, both kinds; 259: - no drawn scaffold limb that stays wholly under the crown base at 23.6 m; 260: - the default lobe unchanged and an 18 m crown's lobe past 1.15 m; 261: - `_spread_first`'s order. 262: - Full suite (`bash artifacts/trees/polish/full2.sh all` → `polish/full2.out`, logs in `polish/suites/`), **on battery**: 40 suites, 18,208 checks. The one failure is the known battery timing check `test_creature_reactions` "The re-plan is applied after the edits"; it failed on both its runs. `--verify`: `PIXELPUNK_INTEGRATION []`. 263: - Frame cost (`polish/bench.sh` → `polish/bench.out`), **on battery**. The pre-polish scratch copy (`polish/setup_pre.sh` → `polish/scratch-pre`) was interleaved with live, three rounds each, with the T8 method. Note the report says `vsync enabled`: it names the mode, and `--disable-vsync` was passed. 264: - `dense.json`: mean 19.80 → 19.87 ms (+0.3%), p95 22.75 → 22.21 ms, 1966 draw calls both. 265: - `giants.json`: mean 10.39 → 10.39 ms, p95 13.29 → 13.51 ms (+1.7%), 731 draw calls both. 266: - The absolute numbers are higher than the AC figures below because of battery, not this pass. 267: - Not done: the exports were **not rebuilt**, so the hashes below predate this pass. Not run: the drag harness, and a review by a second model.