Foliage look-dev
One look: leaf depth. Warm lit tops, cooler tucked faces and quieter leaf rims give the existing foliage more depth. A small warm transmission term catches backlit leaves. Grass keeps its density, with green bases and lighter tips. Forest stays woodland; farm stays bright and pastel.
Lane 3 · 4 November 2026 · Scratch stills for design sign-off; draft builds follow · gap audit


The real Home and offline table, with the audit's viewports and camera conditions. Today removes only this lane's shader body and leaf-rim adjustment from the same running scene. Actor poses, wind and clouds can advance between stills. Geometry, layout, lights, ground, AO and grading stay fixed.
Where it changes
Forest · canopy
Lit tops hold warm green. Undersides shift cooler and darker, so the crown reads before its individual leaf scales.
Forest · grass
The existing rosettes and blades keep their placement. Darker green bases and lighter tips improve separation. No density or layout change.
Farm · canopy
The same foliage 1 shapes keep their pale tops. Lower rim strength quiets the many fine leaf lips; shaded faces retain green.
Farm · grass
The existing tufts gain green bases and warm tips. They still stand over bright painted grass; matching that painting belongs to lane 2.
Reference crops are copied from the audit. They compare visible leaf hierarchy and selective planting. No tracing, sampled textures, or claims about either game's rendering implementation.
Cost against the audit
The same Apple M1, Chromium and ANGLE Metal renderer as the audit. GPU and CPU columns are median / p95 in milliseconds. Draw columns are triangles / calls for the real settled board.
| Field and shot | Audit draws | After draws | Audit GPU | After GPU | Audit CPU | After CPU |
|---|---|---|---|---|---|---|
| Forest · Board 1440×900 | 2,143,577 / 40 | 2,143,917 / 42 | 3.46 / 4.34 | 4.24 / 5.08 | 1.80 / 2.70 | 2.30 / 3.40 |
| Forest · Board 1920×1080 | 2,143,577 / 40 | 2,143,985 / 43 | 3.55 / 4.20 | 5.20 / 6.20 | 1.70 / 2.60 | 1.70 / 3.90 |
| Forest · Phone board | 2,143,577 / 40 | 2,144,807 / 44 | 3.93 / 4.47 | 4.68 / 5.93 | 1.90 / 2.70 | 1.90 / 4.00 |
| Forest · Phone board low | 2,143,577 / 40 | 2,143,671 / 44 | 3.33 / 3.63 | 3.38 / 3.52 | 2.60 / 3.80 | 4.95 / 6.60 |
| Farm · Board 1440×900 | 693,140 / 43 | 691,388 / 37 | 2.22 / 2.37 | 2.39 / 2.53 | 2.80 / 3.70 | 1.70 / 3.20 |
| Farm · Board 1920×1080 | 691,456 / 39 | 691,388 / 37 | 2.23 / 3.20 | 2.96 / 3.08 | 2.40 / 3.00 | 1.70 / 2.80 |
| Farm · Phone board | 691,476 / 38 | 692,470 / 43 | 2.21 / 2.35 | 2.42 / 2.48 | 1.90 / 2.60 | 3.10 / 4.20 |
| Farm · Phone board low | 480,246 / 41 | 480,008 / 41 | 1.01 / 1.04 | 1.08 / 1.14 | 5.90 / 7.40 | 3.85 / 5.20 |
Real offline games can have different settled status props. Their small draw-count differences against the audit are preserved above. The matched control below compares the shaders in the same live game. Timed character emotes can still add or remove a tiny quad between samples; no field geometry or draw is added.
Matched shader cost
Pale green: Today. Dark green: After. Full track = 16.67 ms, the entire 60 fps frame allowance. 30 fps allows 33.33 ms. These are phone-sized Mac renders, not phone GPU certification.
| Field and shot | Today GPU | After GPU | GPU delta | Today CPU | After CPU | Draw delta |
|---|---|---|---|---|---|---|
| Forest · Board 1440×900 | 4.43 / 5.08 | 4.24 / 5.08 | -0.19 / +0.01 | 2.10 / 2.70 | 2.30 / 3.40 | +0 / +0 |
| Forest · Board 1920×1080 | 4.30 / 5.35 | 5.20 / 6.20 | +0.90 / +0.86 | 1.60 / 3.80 | 1.70 / 3.90 | +0 / +0 |
| Forest · Phone board | 4.35 / 5.64 | 4.68 / 5.93 | +0.33 / +0.29 | 2.50 / 4.00 | 1.90 / 4.00 | +0 / +0 |
| Forest · Phone board low | 3.27 / 3.37 | 3.38 / 3.52 | +0.11 / +0.15 | 4.85 / 6.30 | 4.95 / 6.60 | +2 / +1 |
| Farm · Board 1440×900 | 2.25 / 2.36 | 2.39 / 2.53 | +0.14 / +0.17 | 2.10 / 3.20 | 1.70 / 3.20 | +0 / +0 |
| Farm · Board 1920×1080 | 2.71 / 2.92 | 2.96 / 3.08 | +0.25 / +0.16 | 1.60 / 2.60 | 1.70 / 2.80 | +0 / +0 |
| Farm · Phone board | 2.17 / 2.30 | 2.42 / 2.48 | +0.25 / +0.19 | 3.00 / 3.80 | 3.10 / 4.20 | +0 / +0 |
| Farm · Phone board low | 1.04 / 1.31 | 1.08 / 1.14 | +0.04 / -0.17 | 3.65 / 4.70 | 3.85 / 5.20 | +0 / +0 |
Assets and texture memory
| Field / tier | Field GLB bytes, Today → After | Texture bytes, Today → After | Added triangles |
|---|---|---|---|
| Forest · high | 13,959,800 → 13,959,800 | 60,205,724 → 60,205,724 | 0 |
| Forest · low | 13,959,800 → 13,959,800 | 60,205,724 → 60,205,724 | 0 |
| Farm · high | 2,365,516 → 2,365,516 | 44,848,464 → 44,848,464 | 0 |
| Farm · low | 2,365,516 → 2,365,516 | 11,212,112 → 11,212,112 | 0 |
Texture memory estimates unique field material textures at RGBA8 plus mip levels, excluding driver padding. This lane adds no textures or vertex attributes. Farm also retains the audit's 497,643 bytes of full-resolution ground and pollen maps. The additional shader code is part of the shared app JavaScript, not a new field download.
Measurement method and evidence
Reuses the audit capture harness. Each shot opens a fresh context. The board waits for a settled auction turn, no moving camera or active effect, then records four seconds of rendered requestAnimationFrame callback work with the existing scheduler held awake. GPU timers wrap 24 static re-renders of that scene and camera, with the first four excluded and disjoint results rejected. CPU and GPU overlap and must not be added.
After is measured first. Today then removes only the foliage shading block and its leaf-rim adjustment, recompiles, warms for 700 ms and repeats. No gameplay state or field geometry is reset. Character poses and timed emote quads can advance between samples. This is a short sample on a shared Mac. Small positive and negative differences are timing noise; they do not establish a speed-up.
Measured data · audit baselines · reference register. Every screenshot has a sibling JSON with counters, texture dimensions, resources and samples. Hardware renderer checks rejected software rendering.
What a build would touch
One foliage shader helper plus its hooks in scene/fields/forest.js and farm.js, and the existing shader cache-key assertion. No GLB rebake, density change, placement change, new texture, renderer pass or shared kit change.
The look renders under today's lights. Lane 1 still owns real overlap AO, root contact and shared colour balance. This orientation-based shading does not replace occlusion. Lane 2 owns the painted turf beneath the tufts. No separate low-tier look is proposed: keep this shading on the existing reduced meshes. Forest low still submits the audit's roughly 2.14 million board triangles. Phone hardware testing is still needed before a build decision.
Decision for Kyle: use this leaf-depth treatment as the direction for both fields?









