Skip to content

A garden: the flowers piece grows a field, in one wind on one ground - #44

Open
aj-dev-smith wants to merge 83 commits into
mainfrom
flowers-garden
Open

A garden: the flowers piece grows a field, in one wind on one ground#44
aj-dev-smith wants to merge 83 commits into
mainfrom
flowers-garden

Conversation

@aj-dev-smith

@aj-dev-smith aj-dev-smith commented Aug 12, 2026

Copy link
Copy Markdown
Owner

A garden, in the flowers piece

?garden=N (2..12) grows a whole flowering field in flowers.html: N specimens, dealt
without replacement from the eight flowering species, each rotating its own floral form off
its own seed, germinating on a stagger, standing in one wind on one ground, shot by a
five-shot director. The URL still fully decides the field.

flowers.html?garden=7&seed=21
flowers.html?garden=7&seed=21&shot=wide      # pin one shot, for stills

Nothing about a plant's shape is drawn here either. Placement, camera, ground and air are
the environment category the project already allows — "where a plant stands was never a
simulation result"
— and this branch adds no growth code and no organ geometry.

What it cost, measured

before after
minimum spacing 2.5 units, set by eye against one corolla 12, measured over 160 species x form x seed cells
field radius fixed 7 for any N 0.83 s sqrt(N) — constant areal density
capture, garden=7 120.9 ms 38.0 ms (56.0 ms at the establishing distance)
stream floats, garden=7 tri 8.64M / petal 14.63M tri 4.63M / petal 12.94M (veins identical by construction)
pollen hero only — 1 of 7 plants shedding 6 of 7, one population over the field
sky the hero's palette over every species a field blend, chroma-restored, hero leads 0.35

Live, 30 s of real growth at garden=7: gap median 8.7 ms, p95 66.4, worst 117.6, 56.9 fps
measured. Gates: flowers/build.js exits 0, flowers/parity.test.mjs 20/20,
test/smoke.mjs 73/73, test/views.mjs 23/23, both artifacts rebuilt and not stale.

Three findings that outlive the feature

Capture cost was FLORAL, not leaf — and that corrects the shipped app's own diagnosis.
70% of a field capture is floral organs (petal 45.9 ms, sepal 28.2, leaf 25.3, stamen 13.1)
because 20_draw.js pins detL = 1.0 for every floral organ — the microscope permanently
on, so a 0.1-unit filament was built as a 75x75 grid for 70 pixels. flowers/28_lod.js caps
mesh resolution at one quad per pixel: a cap, never a raise, no taste constant in it
(pxHeight is the drawing buffer, fov is the camera's, one quad per pixel is Nyquist).
Do not lower it to buy frames — it is Nyquist, not a dial. ?lod=0 is the pre-LOD page.

Reach is a statement about a SEED, not a species. Ember Creeper columbine measures maxR
7.4 at seed 21 and 65.9 at seed 31697 — same species, same form, 9x apart — and that
specimen is still climbing linearly at step 3200 (11.9 -> 28.8 -> 44.4 -> 70.9): a creeper
whose axes never arrest. A one-seed table got the middle right and the tail 3x wrong, and
the tail is what collides. No fixed spacing can keep a creeper off its neighbours and none
should try — that is organBudget's business, not placement's. So 12 is a stated fraction
(full clearance of two median bodies, 62% of two median arms), not a clearance guarantee.

A plain palette mean is mud, measurably. Blending seven species' atmospheres gives fog
saturation 0.261 against a member mean of 0.598, and keyCol 0.090 against 0.328 — near-grey.
The shipped blend preserves luminance and restores chroma. The hero still leads at 0.35
because a pure field mean gives every garden the same violet sky: mean pairwise fog-hue angle
across 40 fields is 84 deg at lead 1.0, 64 at 0.35, 27 at 0.0.

Also here

  • flowers/45_director.js — wide (establishing, solved from the field's plant bounds and the
    live frame equation), bank (the thicket mid-shot), dolly, close, low. flowerScore() picks a
    subject across the whole field; a drag suspends the director for 25 s in a garden.
  • flowers/25_ground.js — the project's first ground geometry. One shared FL_SKY so the
    ground and the background are the same sky rather than two that resemble each other, plus a
    ground-hugging haze whose optical depth is closed-form. No hard horizon at any camera height
    the director reaches (tools/flowers_horizon.mjs is the check).
  • Harness: tools/flowers_shot.mjs, tools/flowers_perf.mjs, tools/flowers_horizon.mjs,
    test/flowers_capture.mjs (a headless field profiler), test/flowers_pollen.mjs (a census
    that asserts the population balances). The headless profiler caught the shot tool
    double-counting the hero — 998 organs reported for 771.
  • Docs: a GARDEN section in flowers/README.md, the numbers in TUNING, the reasoning and the
    negative results in JOURNAL 2026-08-12, the traps in PITFALLS, a ranked debt list in ROADMAP.

What needs your eye, not mine

  1. Nobody has watched this at framerate. Every judgement here is from stills, which this
    project's own record ranks as its weakest evidence. That is the first thing to do.
  2. The solo page inherits the ground — the Nightglass Parasol's signature shot goes from
    moon-in-black to moon-over-indigo-soil. Taste call. Dials: soil0/soil1 and the melt
    start in 25_ground.js, not the fog.
  3. The mote field barely reaches the screen. Grains drawn larger than 2 px: 0 (wide),
    5 (dolly), 7 (close), 23 (low). The mechanism is right and what a viewer gets is a scatter
    of single pixels. The honest lever is the drawn size — the vein width floor's own
    argument applied to a mote, since a real grain is sub-pixel at every distance.
    ?pol=0.05,12,0.07 is the 3.2x A/B, built and shot but not shipped, because looks on
    this project are decided by watching.
  4. The establishing shot has no visible ground — at 88 units the melt has taken it
    entirely, so the field floats. Correct per the melt's design, and arguably the piece's
    signature void, but it means the frame cannot show you where the floor is.

One bug found and NOT fixed, because it is outside this piece

src/40_plant.js samples the wind at each plant's own this.time, so in a garden a
member germinated at world step 900 bends to the air of 900 steps ago. One field, evaluated
at N different times. The pollen deliberately does not copy it (grains drift on the world
clock). Worth its own branch.

Housekeeping

A phase-1 agent ran ln -s .../node_modules node_modules from the repo root rather than its
worktree, replacing the real directory with a self-referential broken symlink — and committed
it, because .gitignore's node_modules/ matches a directory. Every Playwright tool then
failed with ERR_MODULE_NOT_FOUND. Untracked here, the bare form ignored, incident in
PITFALLS.


Round 4 (2026-08-12/13): the film, and the two artifacts

49 further commits, unattended overnight, seven Opus agents across four staged workflows
plus integration and verification between each. The brief: "make this garden as awesome
and aesthetic and amazing to watch as possible... there's these glitchy flashes on
flowers that seem unintentional."

The glitchy flashes: two defects, one cause, both convicted

The flashes were real, caught on camera by a new probe (tools/flowers_glitch.mjs
snapshots the canvas the exact frame a tile spikes, excluding camera-motion frames), and
they turned out to be the same null geometry reaching the screen two ways. blade()
(src/50_geom.js) emits ~7% zero-area triangles at every leaf base, whose vertices also
carry exactly-zero normals.

The bright gridded square: a zero-area triangle has no barycentric denominator, so
the rasteriser hands its odd fragment varyings outside the hull of its own vertex values
vC*vE*3 measured at 710 against a legitimate ceiling near 3, one HDR texel at 8,863
against a frame median of 2.38 — and the bloom chain's sparse blur renders that delta as
a comb: the "grid" was the blur kernel seen naked. Fixed at two causes: 10_capture.js
drops no-area triangles (scale-free test, counted and reconciled exactly by the parity
gate, extended 20→24 checks
), and the tri/petal shaders enforce the interpolation
contract (|vN| ≤ 1 is a theorem for unit normals under convex interpolation; the spike
held 56.10 of the shaded colour above that test and 0.69 below it).

The one-frame black square (found while gating the fix): normalize(vN) where
|vN| == 0 makes a NaN the bloom smears into a 112 px square — 112 derived from the
blur support, not a GPU tile. The first guard couldn't see it because every comparison
against NaN is false
; rewritten as the negation of the valid band. Headless: 14,485 of
629,364 tri vertices carry an exactly-zero normal, matching the no-area census species
for species, with nothing between 0 and 1−1e-7.

After both: zero events — 0 flash spikes, 0 holes, 0 non-finite texels across all
probe runs at seeds 21, 1337, 4242, 8888 (tens of thousands of frames). Scene-peak p99
369.5 → 5.2. The look is measurably unchanged (close shot mean pixel −0.4%; controlled
same-frame A/B: 0 finite blocks changed). Twelve purpose-built instruments carry the
diagnosis in tools/.

And canalisation.html was measured, not assumed: it has the same unguarded
normalize on 3× the zero normals (7.38%) and does not fire — 133,731 frames, 0
hits — because there the zero-normal edges live only on triangles with identically
zero area, which are never rasterised. Positive controls prove its chain would draw the
square if fed a NaN. src/ untouched; ROADMAP 0g books the deliberate decision:
fix blade() at the source for both pages, or port the (provably no-op) guard.

One air, one clock

Plant sampled windAt at its own life clock, so garden members bent to moments of the
wind up to 2,600 steps apart — a gust could never cross the stand as one event, in
either page's garden. Plant.windPhase (default 0; solo pages and every harness
bit-identical) anchors each member to the scene's wall clock; a regrown hero inherits it
("the weather outlives the specimen"). Gates: smoke 73/73, stem 82/82, wind 27/27.

The film

The director is now a cinematographer rather than a slideshow:

  • Nothing stops moving. Every shot carries a perpetual drift at one screen-referred
    rate (FL_DRIFT = 0.75% frame width/s — by eye, the uRef category); stationary samples
    15.1% → 0.0%.
  • A sixth shot goes through. glide traverses the stand's widest clear lane
    (derived from the drawn points' projection), at 3× the drift rate = ~5 cm/s, rack
    focus resolving flowers as they pass. Its entrance frame is the best picture this
    piece has produced.
  • The frame goes where the field is. The establishing heading comes off the field's
    plan-hull diameter (covariance weighted a seedling like a frond): drawn NDC span
    1.17 → 1.53. The low shot is solved from the skyline with closed-form clearance — its
    old pose had the eye inside an Ember Creeper (clearance −4.1 units) and 54% of its
    ink in the top half; now sky over the bank (0.29).
  • Transitions are paced and clear. Peak speed is the law (FL_DIR_VPEAK = 26 u/s,
    derived — it reproduces both old hand constants to 0.4 s); the eye blends in the
    field's polar coordinates (no chording through the stand); headings freeze per shot
    (a diameter is not continuous in a growing stand — the teleport this killed measured
    239 u/s); and where a path would brush foliage the camera cranes over the canopy,
    amplitude solved closed-form against the drawn surface, engaged only when needed
    (4-5 of 6 moves untouched; worst path clearance 0.07 → 2.54 units; foreground-cover
    frames halved). One pre-existing bug found on film: the polar blend re-derived
    "short way round" per frame, so near-antipodal poses teleported 80 units in one frame
    (434 u/s at seed 1337 → 42).
  • Rack focus: shots enter with the subject soft and resolve onto it, amplitude 1.2
    depths of field off the DOF pass's own uRange.
  • tools/flowers_clip.mjs records the film (webm + a 4 Hz camera track) and
    tools/flowers_trans.mjs measures every transition's clearance — both re-runnable.

The field is legible now

  • Pollen reaches the screen. Every grain sat at the point pass's 1 px clamp
    (p50 = p99 = 1.00 — "a channel drawn at the rasteriser's clamp is invisible in a way
    no screenshot reports", now in PITFALLS). A mote is a glare spot, so its size is an
    angle (minAng = 0.004, by eye off a measured 4-point ladder), fogged at 0.45
    (0.80, the tissue's number, extinguishes — a mix toward a colour is not a fade to
    black). Wide shot: 0 → 320 grains above 2 px.
  • The establishing shot has a floor. Not the melt — the glow pool was a 5-unit pool
    at the origin, 0.6% where a field's plants stand. Its length scale is now the
    clearing's (rim + spacing — the radius the pollen derives independently), applied as
    airlight riding the melt: the flat-albedo version was built, measured, and rejected
    for turning an overhead shot magenta (JOURNAL). The solo page's void is preserved by
    construction (no plan → no rim; measured 0.00–0.28 before and after).
  • Every flower is its own. The bullseye threshold and spot atlas were scene-wide —
    the hero's pigment program worn by all seven members. Now per-member via split draw
    groups (vertex format untouched, parity untouched): 7 distinct thresholds spanning
    all three Todesco modes, 7 distinct atlases, solo page delta 0.0000/255 at two seeds.
  • The URL-parameter catalogue came off the canvas (it overstruck the HUD in every
    frame); the gesture hint stays, the catalogue prints to the console.

Verification on the assembled branch

flowers/build.js exits 0 · parity 24/24 · smoke 73/73 · views 23/23 · stem
82/82 · wind 27/27 · flash probe 0 spikes · hole probe 0 holes, 0 non-finite ·
flowers_ident 7 distinct/0 collisions · perf unchanged: gap median 8.4 ms,
57.5 fps at garden=7 (was 8.7/56.9 before the round). Docs: JOURNAL ×3, PITFALLS ×3,
TUNING (all round-4 constants labelled derived-vs-eye, with ladders), flowers/README
(six shots), ROADMAP (0f items closed, 0g added), CLAUDE.md.

What still needs a human eye (ranked)

  1. Watch the film. open 'flowers.html?garden=7&seed=21' and let it run two
    rotations (~4 min). Everything below is subordinate to this.
  2. The cranes: 22–32-unit rises over a 40-unit stand where a straight path would
    brush foliage. Every number says better; whether it reads as a camera or a drone is
    yours. Dial: ?brush=2 cranes less.
  3. FL_DRIFT (0.0075) and the ~2 s rack-in on shot entry — "too much / still frozen"
    each move one number.
  4. Fireflies vs motes: fogged motes shipped; both ends shootable from one build
    (?pol=… variants in TUNING).
  5. ROADMAP 0g: fix blade()'s null geometry at the source (both pages, deletes the
    vertices instead of discarding fragments) or port the no-op guard to 60_render for
    shader parity. Booked, argued, not taken autonomously.
  6. The remaining blur-wall at seed 21 is the dolly pose standing where an Ember
    Creeper arm reaches — a poses question, measured and left.
  7. The glide costs 81 ms capture vs the dolly's 71 (the LOD doing its job at a near
    camera) — 27% of the film's runtime; a decision, not a discovery.

🤖 Generated with Claude Code

aj-dev-smith and others added 30 commits August 11, 2026 20:08
tools/flowers_shot.mjs — screenshots flowers.html (flower_shot.mjs targets
canalisation.html). Waits on window.__fl, drains ff via the HUD (&shotstep=
for a step target), settles until the CAMERA is stable rather than for a
fixed time — the fixed wait shot the columbine from inside its own corolla —
prints stream counts off __fl.B (summed over __fl.garden when that lands),
and decodes its own PNG: the documented swiftshader failure is a black frame
WITH a full triangle count, so counts alone prove nothing. &speed=0 is the
reproducible-still recipe.

tools/flowers_perf.mjs — the garden_hitch lesson: a harness that waits cannot
see a freeze. In-page rAF gap sampler over ~30s of live growth (ff dropped
deliberately); prints median/p95/p99/worst and fps beside the HUD's own.
PRINTS, DOES NOT JUDGE — there is no budget yet; this is the baseline.

test/flowers_capture.mjs — headless capture cost, no browser: parity's loader,
a grown specimen, median of 20 flDrawSpecimen calls, stream float counts.
Asserts only structure (the parity organ-range check). n>1 probes for
flGardenPlan and prints 'garden: not built yet' today.

Baseline (this machine, ANGLE-on-Metal): default page 30s live growth —
gap median 8.5ms p95 25.1 p99 33.4 worst 58.3, 66.2 fps measured / 42 HUD.
Headless capture: Ember 21 @1400 9.76ms; Parasol 7 @2600 3.32ms.

Co-Authored-By: Claude Fable 5 <[email protected]>
flowers.html had no ground geometry — plants stood on an implied floor at
y=0 against the void. flowers/25_ground.js adds one: a 140-unit disc at
y=-0.01 with FL_TRI_FS's shading subsetted (hemisphere ambient, key
diffuse at 0.9, the same flFog at 0.80 through the scene's own fog
uniform objects, alpha carrying linear depth so the lens racks over it).
Environment, the same allowed category as the wind — nothing about the
plant is drawn.

Colour is palette mixes only: soil0 = mix(bgBot, stem0, 0.16), soil1 =
mix(ambBot, stem0, 0.40) under a two-octave hash value mottle, a 0.6x
bgGlow pool under the specimen, and a radial melt to mix(bgBot, bgTop,
0.65) so the rim never draws a line. Three of those numbers were
corrected by looking: a darker melt target cut a visible trough between
fogged soil and sky, and one step brighter soil doubled a Parasol
down-shot's field value against the old void.

Two traps hit and written down in the file:
- flowers/*.js sorts 25_ before 30_scene, so a top-level ${FL_FOG}
  template parses clean and dies in the TDZ at load; the shader strings
  are built at construction time instead.
- The framing laws predate the ground and walked the eye to y=-16 on a
  tall specimen — under the new floor that is a screen-filling ceiling
  of soil. The boot now holds the eye just above the plane (40_boot.js),
  which also stops the orbit phasing through it.

node flowers/build.js clean, parity 20/20 before and after. Nothing
under src/ touched.

Co-Authored-By: Claude Fable 5 <[email protected]>
…_garden.js)

flApplyForm is 40_boot.js's inline homeotic block extracted verbatim; a
reference harness sliced the same lines out of git HEAD, wrapped them, and
held both paths to identity -- form name, S.sp, plant.sp, both palettes, and
every captured stream hashed byte for byte at step 1400, across all four
forms and the URL knobs (81/81). parity 20/20. uploadMany concatenates N
FlowerBuffers; upload(B) delegates to it, so the solo upload is unchanged.

Co-Authored-By: Claude Fable 5 <[email protected]>
…g with sqrt(N)

flowers/35_garden.js only.

FL_GARDEN_SPACING 2.5 -> 12, and the 2.5 was set by eye against a single
corolla. Measured headlessly (8 flowering species x 4 forms, 3000 steps,
horizontal reach off the DRAWN streams): max reach min 3.37 / med 9.49 /
max 22.13, body reach r90 min 1.22 / med 5.76 / max 16.77. 12 is full
clearance of two median bodies and a stated 63% of full clearance of two
median arms -- full arm clearance (19.0 median, 44.3 worst) is too sparse
to read as a field. Stated fraction, not a derived one.

Field radius was a FIXED 7 for any N; now 0.83*s*sqrt(N), from RSA disc
capacity, so areal density is constant. ?radius= still overrides.

Placement is dart throwing over the disc, uniform in area, accepting the
first candidate clearing the spacing, with the BEST failed try as the
fallback rather than the LAST. Over seeds 1..64 and N in 2..12 the
achieved minimum gap is >= 12.0 in every case, 0/64 exhaustions.

Stagger 2400 -> 1200 with a first cohort at step 0 (max(2,min(4,ceil(N/3)))):
garden=7 had 2 of 7 germinated at step 1100; it now has 7 of 7 at 1600.

Species deck now deals without replacement ACROSS the reshuffle boundary
too (n>8 could put two of a kind side by side). Seeds were already
injective; the comment now says why.

parity 20/20, solo page unchanged.
…r the garden

PROFILE FIRST (test/flowers_capture.mjs, rewritten as the profiler). A garden
of 7 at seed 21, world step 3000, grown WITH the germination stagger so it is
the page's field and not a different one — and it reproduces the browser float
for float, which is how the double count in tools/flowers_shot.mjs was found
(it added the hero twice: 998 organs for 771, 10.34M tri floats for 8.64M).

Where the 115ms goes, per organ kind:
  petal   45.9   sepal 28.2   leaf 25.3   stamen 13.1   rest 4.4
70% of it is FLORAL organs, and 58% of every float emitted is the petal
stream. That is 20_draw.js handing every floral organ detL = 1.0 — the
microscope, permanently on — so a petal is built at the leaf's own lattice
(~5,600 verts a petal) whether it fills the frame or covers 16 pixels.

1. NEVER FINER THAN THE RASTER (flowers/28_lod.js). bladeMesh is the piece's
   only LOD with no distance term (CLAUDE.md). It gets one: cap mu,mv at one
   quad per pixel, px/unit = pxHeight / (2 d tan(fov/2)), measured to the
   specimen's near face. A cap, never a raise; floor stays 4x2; ceiling stays
   the leaf's lattice. No taste constant and NO HERO EXEMPTION — the subject
   is large on screen by construction, so at the close-up's own framing the
   cap lands above the lattice and does nothing. ?lod=0 is the pre-LOD page.
   Field capture 115.0 -> 67.7ms headless, 100.2 -> 77.7ms in the browser.

2. PAY IN BATCHES, NOT IN SLICES (40_boot). The pool was spent breadth-first —
   one step to every specimen — so every specimen stepped, and a specimen that
   stepped is recaptured: the frame paid the whole field's rebuild to advance
   garden time one step. Depth-first spends the same budget on fewer plants,
   at the same average rate each. How few is Nyquist, not taste: FL_RECAP_HZ =
   1.78 * 4 (four samples per period of the wind's fastest gust, 15_petal.js's
   ripple guard applied to time), so m = nAct * HZ / fps. The hero is exempt
   and always paid first. ?batch=0 is the pre-batching pool.

Live, grown field (flowers_shot, ff=3000 then speed=1, real browser on Metal):
  before  120.9ms capture (7/7)  10 fps
  after    38.0ms capture (3/7)  21 fps   (and 5 more petals — it grew further)

LOOKED AT: shots/g7_ff3000_lodoff.png vs _lodon.png, identical seed and step.
Nothing is deleted — seven plants, every flower, the same picture.

parity 20/20, build clean.
…a maximum it could not miss

A synthesised close-up eye lands INSIDE the specimen's bounding sphere, so the
near-face distance clamps at 0.1 and the corolla check passes at 100% — the
unreachable-maximum trap test/venation.mjs records, arriving in a harness
written twenty minutes earlier. Replaced with a sweep over near-face distance
(2 / 4.51 / 9 / 20 / 45 / 90 units), gated on the row a real browser actually
measured at ?focus=flower:

    d      px/unit   tri kept   petal kept   vein kept
        2      1036      93.6%        99.0%      100.0%
     4.51       459      81.2%        96.6%      100.0%
       20       104      48.8%        92.4%      100.0%
       90        23      22.0%        27.8%      100.0%

Two gates: the corolla keeps >= 95% of the petal stream at the close-up (0.966
measured, floor written first), and the cap touches NO vein, exactly — this law
is about surfaces and must not reach the channel the engine is visible through.

And it corrects 28_lod.js's own comment, which claimed the close-up was
untouched. It is not: -3.4% petal, -18% tri, and NONE of it is leaves. It is
stamens and carpels, because detL = 1.0 is applied by organ IDENTITY, so a
0.1-unit filament is built at the same 75x75 lattice as a petal filling the
frame. The solo page is no longer byte-identical and the difference is
sub-pixel by construction.
Two defects, both found by looking at a garden of seven (seed 21, step 3000)
and both in the atmosphere rather than the plants.

1. THE HORIZON WAS A HARD STRAIGHT LINE. The disc melted over its own RADIUS
   toward one sampled void colour, but the rim was never what a viewer saw:
   a fully fogged ground is uFog and the sky above it is the bg gradient near
   uBot, and on the shipped palettes those differ 3-5x in luminance (Sun
   Coral: fog L 0.041 against bgBot L 0.005). The seam is wherever the plane
   runs out of screen, which from an eye near ground level is a straight line
   across the middle of the frame.

   The ground now melts into THE ACTUAL SKY IN THAT DIRECTION: FL_SKY is the
   background's own gradient extracted as a function (FL_BG_FS now calls it
   too, so there is one sky, not two that resemble each other), sampled at the
   fragment's screen position through a clip-space varying — perspective
   correct, no resolution uniform. Where the melt completes the ground IS the
   void, bit for bit, so the join cannot be seen. Alpha melts to the void's
   3.0 with it so the defocus finds no edge either.

   What drives the melt is a ground-hugging haze: the closed-form optical
   depth of an exponential-height layer along the eye ray, which is uniform
   when the eye is IN the layer and thins as 1/yEye above it. That is the
   whole trick — a Lambertian plane under a directional light has ZERO shading
   variation, so no distance term alone can fade the near ground an eye-level
   camera is mostly looking at. FL_HAZE = [G 2.0, H 3.0, P 1.5, N 5.0], set by
   looking at two shots that pull opposite ways (a garden from y=0.6 needs the
   near ground to go; a solo flower close-up needs a floor under its subject).
   G alone trades one against the other — 1.5 hides the horizon and empties
   the close-up, 0.6 the reverse — and P (the curve's near half) and N (ground
   nearer than 5 units is floor, not air) are what let both be right. Same
   category as the wind's uRef. ?haze=G,H,P,N sweeps.

2. THE WHOLE FIELD WORE THE HERO'S PALETTE. flFieldPal blends the seven
   atmosphere colours across the species actually present. The obvious mean is
   measurably mud — over the eight flowering species the mean fog's saturation
   is 0.295 against a member mean of 0.607, bgGlow 0.337 against 0.770 —
   because averaging in RGB cancels hue against hue. So the blend keeps the
   weighted mean's luminance and hue direction and rescales its chroma back to
   the members' own mean chroma, clamped so no channel goes negative.

   The hero LEADS at 0.35, and that number came from a measurement, not taste:
   a deck of eight dealt seven ways is nearly the whole deck, so at a pure
   field mean every garden gets the SAME sky — mean pairwise fog-hue angle over
   24 base seeds falls to 20.8 degrees, against 85.6 today. 0.35 keeps 64.4
   degrees of field-to-field variety while still moving the air off one
   species (fog saturation 0.714 hero -> 0.574 field, luminance preserved).
   ?sky= overrides; A/B shots at 1 / 0.35 / 0 are on the branch.

The solo page keeps its own palette BY CONSTRUCTION (no plan, or a plan of
one, returns the palette object unchanged) and gains the melt, which it wanted
too: its close-up had the same visible horizon and now has a floor that fades.

parity 20/20, build clean.

Co-Authored-By: Claude Opus 5 <[email protected]>
Comment only, plus the rebuilt artifact. Swept the reach measurement over
the five seeds a garden actually deals (8 species x 4 forms x 5 seeds, 160
cells): maxR p10 3.6 / med 9.7 / p75 14.4 / p90 23.2 / max 70.9, r90 p10
2.2 / med 5.0 / p75 7.5 / p90 12.1 / max 20.4.

The one-seed table got the middle right (9.49 vs 9.7) and the tail wrong.
Two findings recorded in the file:

 - reach is a statement about a SEED as much as a species. Ember Creeper
   columbine is maxR 7.4 at seed 21 and 65.9 at seed 31697.
 - reach is not bounded in TIME for that species. Sampled every 200 steps
   at seed 31697: 11.9 (step 1000) -> 28.8 -> 44.4 -> 70.9 (step 3200),
   still climbing linearly. A creeper whose axes never arrest. No fixed
   spacing can keep that off a neighbour and none should be expected to.

FL_GARDEN_SPACING stays 12 -- full clearance of two median bodies, 62% of
two median arms, and the fraction is now stated against the wider sample.

parity 20/20, smoke 73/73.
scratch/g2_placement/ — new paths only, nothing shared touched. Kept
because the whole argument for FL_GARDEN_SPACING is a measurement, and a
measurement you cannot re-take is just a number somebody chose.

  loader.mjs      the flowers bundle in plain Node (copied from
                  test/flowers_capture.mjs, plus 35_garden.js so
                  flApplyForm and flGardenPlan are reachable)
  reach.mjs       what one specimen occupies: maxR / r90 / r50 off the
                  DRAWN streams, per species x form
  seedsweep.mjs   the same over the five seeds a garden deals — the run
                  that found the one-seed table's tail was wrong
  arc.mjs         reach over a whole life, every 200 steps — the run that
                  found Ember Creeper never arrests
  plan.mjs        statistics of flGardenPlan itself over seeds 1..64:
                  achieved min gap, depth spread, dart exhaustions,
                  adjacent species duplicates, seed collisions
  field.mjs       the plan GROWN on the boot loop's clock: pairwise
                  overlap at maturity, and what a viewer sees at
                  step 600 / 1200 / 2400 / 3600
  seedsweep.out   the 160-cell table quoted in 35_garden.js
…t exist

flowers/README.md: the profile table, both laws stated, the before/after
matrix at 5/7/10, and the tail the batching costs (isolated with ?batch=0:
the LOD improves every column, the batching trades p99 for median).

And the negative result, measured rather than assumed: THERE IS NO FROZEN
TISSUE TO CACHE. An Ember Creeper at step 3000 with zero live axes changes
56.4% of its triangle floats on the next step, deltas to 0.41 world units —
and still 56.4% with the wind at uRef 0. The material shape of a mature
lamina is frozen and already baked; where it IS moves every step forever,
because the axes are cantilevers and the petioles hang off them. So the
answer to 'recapture less' is temporal, not memoised.
…mens rebuilt

A harness reading fps can see that the field got faster and not why. stepN and
capN are the pool's own two numbers, and the HUD already prints capN as (k/N).
…ADME

p99 83.4 -> 108.4ms against median 50.0 -> 34.9. It trades the tail for the
median and the next person to write a hitch gate for this page should read
that in the code that does it.
…tor.js)

The shipped framer frames ONE subject; pointed at a garden it framed the
bound of everything at once — measured on ?garden=7&seed=21&ff=3000:
radius 36.1, camera 84.2 units out, six plants in a column, most of the
frame empty.

45_director.js is a shot list instead: wide field / dolly across it /
close-up on the best flower ANYWHERE in the field / low against the sky,
cycling with eased 5 s transitions and holds of 20/24/16/12 s. Framing
distances are derived from the frame equation (2 d tan(fov/2)) against the
field's own median plant height, not from the bound.

?shot=wide|dolly|close|low pins one, for stills.

Co-Authored-By: Claude Opus 5 <[email protected]>
…laim instead

'the corolla keeps >= 95% of the petal stream' passed at 1600 steps (96.6%) and
FAILED at this harness's own default of 1400 (89.0%) — a younger flower's
organs are smaller and a cap in pixels bites a small organ first. A percentage
of a stream was never the claim 28_lod.js makes. The gate is now the claim,
and it is stage-independent: the LARGEST petal in the close-up is drawn float
for float as it was (110400 == 110400 at both stages). If the biggest thing
the shot is pointed at loses one vertex, 'no hero exemption' is false.
Sampling the director's own state at 4 Hz over a full 92 s cycle: shot
lengths land exactly on the table (dolly 29.0 s, close 21.0, low 16.9,
wide 25.1 = hold + 5 s transition each, so nothing ever cuts mid-move),
but entering the CLOSE-UP peaked at 59-62 units/s against 19 for every
other transition. The close-up is the shipped framer and the shipped
framer is three exponential lerps, which is an ease-OUT — and an ease-out
starts at its fastest. Holding the camera back toward the pose it cut
from, by the same smoothstep the other shots use, takes the peak to
22.7 u/s: 3.9 m/s to 1.4 m/s in WORLD.unitM, a whip to a walk.

Also measured: a drag freezes the shot clock for 25 s (verified: el held
at 23.8 through the whole hold, then restarted at 0 with a full eased
re-entry) and hands autoRotate back to the viewer while it does.

Co-Authored-By: Claude Opus 5 <[email protected]>
Also drops three fields the director never read.

Co-Authored-By: Claude Opus 5 <[email protected]>
The sight-line clearance is specimen 0's alone (heroCull), and in a stand
this dense that clearance is the difference between a photographed corolla
and a wall of leaf: 33.9 ms with the flower visible on the hero, 131 ms of
the subject's own blades across the lens for ?focus=flower two plants over.
The constant is labelled for deletion the day the cull follows the subject.

Co-Authored-By: Claude Opus 5 <[email protected]>
# Conflicts:
#	flowers.html
#	flowers/35_garden.js
# Conflicts:
#	flowers.html
#	flowers/40_boot.js
flowers/README.md gets a GARDEN section in that file's voice — the placement
law and why the spacing is a stated 62% of measured arm clearance, the
germination cohort and stagger, the four-shot director, the ground and the
field palette, the harness. Every number verified against the code or re-taken
here before it was written down.

The three headlines go where this project keeps numbers:

- TUNING: the flower field's knob table, which two are Nyquist and not dials,
  the 160-cell reach sweep behind FL_GARDEN_SPACING, and FL_SKY_LEAD's
  measurement (mean pairwise fog-hue angle 84/64/27 deg at lead 1.0/0.35/0.0,
  reproduced over 40 fields of seven).
- JOURNAL 2026-08-12: capture cost was FLORAL and not leaf (the microscope
  pinned on by organ identity); reach is a statement about a SEED and is not
  bounded in time, so no spacing should try to contain it; a plain palette mean
  is mud (fog saturation 0.261 against a member mean of 0.598).
- PITFALLS: the node_modules symlink incident, and the fact that a field
  profile is a profile of that field's germination schedule.

Two corrections, both from re-taking the measurement rather than copying it:
the per-kind capture table in 28_lod.js and the README's cost section were
measured under the older stagger (2400, uniform startAts), and on the shipped
plan the petal stream is 46.7% of floats and not 58%, with sepals overtaking
petals. The 70%-floral headline survives at 74%. Noted where both are quoted,
not silently overwritten.

CLAUDE.md had no entry for flowers.html at all; it has one now, with the
load-bearing warnings (the LOD cap is Nyquist, the spacing is a stated
fraction, the hero lead is measured, garden time slows with N) and the honest
headline: nobody has watched this at framerate in a real browser.

ROADMAP 0f ranks the debt, watching it first, and books the solo page
inheriting the ground as a taste call rather than a bug.

Docs only — no .js touched, flowers.html rebuilt to a byte-identical file.
Gates: node flowers/build.js OK, parity 20/20, smoke 73/73.

Co-Authored-By: Claude Opus 5 <[email protected]>
18_pollen.js walked the hero's axes only, so in a garden of seven six
flowering plants shed nothing. It walks the boot's `specs` list now — one
population, because a grain is not part of a plant: once shed its only
inputs are the wind field and gravity, both scene-wide, and the cap and the
upload are scene-wide resources too. The alternative (one FlPollen per
specimen) is argued down in the file.

Three things came with it:

- TWO CLOCKS, and they are not the same in a garden. A specimen sheds on
  the plant time IT was paid this frame (`spec.stepped`), because
  dehiscence is a plant process and the step pool is spent depth-first;
  every grain drifts on the WORLD clock, because the air is one field over
  the clearing and windAt's `t` is a wall clock. The shipped call passed
  the hero's age and got the right number by accident — the hero is exempt
  from the pool and paid first out of it, so its age IS the world step.
- A MOTE'S COLOUR IS THE KEY LIGHT'S, and in a field the key light is the
  FIELD's (flFieldPal, 25_ground.js), not the hero's. Unchanged on a solo
  page, where flFieldPal returns the hero's palette itself.
- test/flowers_pollen.mjs, a headless census: anthers, grains, where they
  are, where they die, and what a population step costs. It asserts only
  that the census balances (emit - died - alive == 0), because a swap-with-
  last removal loop is exactly the kind that drops one silently.

MEASURED, garden=7 seed=21, step 3000 (before = HEAD's file, run through
the same harness with `polfile`):

                       before            after
  shedding plants      1 of 7            6 of 7
  anthers drawn on     16 (hero)         59 (field)
  grains alive         348               326
  ...within 12u of a   67                194
  plant                (r_mean 44.3)     (r_mean 21.3)
  population step      0.031 ms          0.051 ms

THE CAP HAS NEVER BOUND AND NEITHER HAS `life`: 0 refusals at 59 anthers,
and 0% of grains die of old age. The population is ADVECTION-limited, not
cap-limited — a grain drifts 0.32 world units per plant-time unit in the
shipped 2.5 m/s air, so it crosses the whole clearing in 0.65 s. Two
numbers that look like they control the population and neither does.
wide was not wide: it distanced off the median FLOWER height (5.9-13.8 on
garden=7 seed=21) while the plants standing there are 4.4-49.2 tall, so it
framed a thicket with five specimens cropped top and bottom. That pose is
kept whole under the name 'bank'; 'wide' is now solved from the field's own
plant bounds.

- flDirField grows Rout (85th pct of dist-from-centre + that specimen's own
  canopy reach) and hHi (85th pct of plant height). p85 not max: one Ember
  Creeper sprawls 46.7 units and takes the outer radius 30.6 -> 62.4.
- flDirPoseEstab solves the standoff from the frame equation off the LIVE
  camera's fov and aspect: width (2*Rout across fW of frame width) and
  height (hHi across fH of frame height), whichever binds. It swaps inside
  the shipped range -- garden=3 height-bound at 58.0 vs 33.6, garden=12
  width-bound at 117.1 vs 76.4, garden=7 height-bound at 81.8 vs 67.1.
- Composition is two more fractions with closed forms: feet at bF up the
  frame fixes the target, horizon at hz fixes the eye height.
- Five shots, holds re-balanced to 96 s (was 92 s for four). wide takes a
  7.5 s transition of its own: every cut flips the heading, so standing at
  81.8 where bank stands at 47.9 would have peaked at ~39 u/s against the
  other four's 26.

Co-Authored-By: Claude Opus 5 <[email protected]>
A grain is integrated forward-Euler through a 7-octave gust ladder, so the
step has to resolve the fastest thing in that ladder. Derived from the
shipped field rather than chosen: the shortest mode is 8 world units long
and a grain travels uMeanMag + sigmaW per plant-time unit, so space wants
6.2 pt units and the fastest mode's period wants 6.3 — the same
four-samples margin 15_petal.js's ripple guard and 35_garden.js's recapture
rate already keep.

That is exactly the real-time page's per-frame cap, so nSub is 1 in real
time and this touches ?ff= only: at its 40-step chunk a grain jumped 12.8
units per call, further than the shortest gust is long.

⚠ BE HONEST ABOUT WHAT IT BUYS, WHICH IS NOT MUCH. Measured, garden=7 seed
21 at step 3000, chunk 40 (the ff path) against chunk 6 (the watched page):
302 -> 276 grains alive, 168 -> 140 of them near a plant, against the
watched 326/194. The ff'd population was already within ~15% of the watched
one; what the substep fixes is the trajectory each grain takes through the
gusts, not the census. A first version of this note claimed a 15 -> 38 fix
and that number came from a run with a bug in it (rEdge measured from the
origin with the rim unset) — the corrected measurement is above.

Also ?pol=rate,beyond,size, so the three legibility numbers are a shootable
before/after from one build (?lod=0's argument), and the drawn size is now
per-population rather than read off the table at emit.
The comment repeated the retracted 15 -> 38 claim; it says trajectory, not
census, and quotes 302 -> 276 against a watched 326.
Over a full director cycle at ?garden=7 the field holds 330-390 grains and
the number drawn larger than 2 px is 0 (wide) / 5 (dolly) / 7 (close) / 23
(low), never above 4 px — the camera is never within 10 units of a grain,
because the shots stand outside the crowd and a grain only lives within a
plant's room of a plant. The mechanism is right and it barely reaches the
screen; the lever is the drawn size as a constant ANGULAR size (the vein
width floor's argument applied to a mote), ?pol= shows it at 3.2x, and it
is not shipped because that is a look decision and looks are decided by
watching.
rEdge started at where the outermost plant STANDS, and 35_garden.js already
measured why that is not the same thing: median reach 9.7 units, p90 23.2,
and one Ember Creeper columbine at 70.9 — a creeper whose axes never
arrest. On a solo page the rim is 0, so any anther more than one plant's
room from the origin would have shed grains that died on the step they were
born. It grows monotonically with the furthest emission instead. Solo Ember
seed 21: 38 -> 52 grains alive, the 38 near a plant unchanged.
…at it

Three rungs of ?estab= shot at garden=7 and looked at: fH 0.62 (d 103.0)
is the tree_shot lesson, a small clump in a dark frame; fH 0.78 (d 81.8) is
full but the two nearest spires graze the top edge; fH 0.72 (d 88.7) ships.
Verified at all three garden sizes -- the solver reproduces the derivation
exactly: 62.74 against 62.8 predicted at garden=3 (height-bound), 88.7 at
7 (height-bound), 117.12 against 117.1 at 12 (width-bound).

THE HORIZON: tools/flowers_horizon.mjs run at this pose's own eye and
target at 8.0 / 18.4 / 34.0 units of eye height. NO hard horizon at any of
them -- 25_ground.js's melt holds at 88 units, which is what that tool
exists to catch. There is also no ground: the floor is inferred entirely
from where the stems stop. ?haze=2,3,2.5,5 (raising the near shaping P,
the one knob built to keep floor near the camera without bringing a
horizon back) was shot against the default and is indistinguishable. The
limiter is VALUE, not optical depth -- soil albedo 0.03-0.10 by decision
lands within a hair of the void. Nothing in the ground was changed.

Also: a shot with no subject falls back to 'bank', not 'wide'. A field
with nothing flowering is a field of seedlings, where wide is width-bound
at maximum standoff, and three of five shots would be an empty clearing.

Co-Authored-By: Claude Opus 5 <[email protected]>
aj-dev-smith and others added 30 commits August 12, 2026 20:37
The one-frame black square was pre-existing, seed-dependent and only ever seen
under ANGLE-on-Metal, and ~128 px is a plausible TBDR tile — so the standing
hypothesis was a driver dropping a tile. It is not. It is ours, and each of
these exists because the previous one could not answer the next question.

flowers_black.mjs proved the hole is in the drawing buffer, but its collapse
test is not specific: at seed 1337 it flags 232 tiles in 2,613 frames, in runs
of six consecutive frames falling 60 -> 25, which is a camera cut. flowers_hole
asks for the artefact's own signature instead — near black, still camera, one
frame, recovers — and reduces every post target on the same frame. 8 confirmed
holes in 4,026 frames, with the DEFOCUS target collapsing alongside 7 of 8 and
carrying non-finite texels on all 8, while the scene target's luminance at that
tile does not move at all.

"The scene is clean" was a claim it was not entitled to make — it samples 64
texels per 69x65 tile, and one bad texel in ninety is exactly what it would
miss. flowers_nan has exact coverage and classifies rather than counting, with
no isnan() (GLSL ES 1.0 has none): NaN fails every comparison, +-Inf fails
exactly one. 69 frames of 4,921 carry a NaN in rtScene's COLOUR, one 8x8 block
at a time, never Inf, never in alpha, and never one in the defocus target
without one in the scene. HIDE= bisects it to the tri stream: 0 in 2,155 frames
with triMesh hidden, unchanged with petMesh hidden.

flowers_vn names the term by rewriting FL_TRI_FS at runtime. Its first design
aliased — markers are read per 8x8 block and a degenerate sliver puts several
causes in one block — so it keeps the shipped discard and intercepts only what
that discard cannot see. 83 markers, ALL of them |vN| == 0, and zero
unexplained NaN left over.

flowers_zeron settles it in Node with no GPU at all: 15,560 of 915,792 captured
vertices carry a normal of exactly zero, matching the no-area triangles
10_capture.js drops species for species, and the population is a GAP — a normal
is 0, or it is 1 to within 1e-7, with nothing in between.

Co-Authored-By: Claude Fable 5 <[email protected]>
2.30% of the tri stream's vertex normals are exactly zero — 14,485 of 629,364
at seed 1337, 15,560 of 915,792 counting petals — and the comment above
FL_GUARD opened by asserting the opposite. They come off the same collapsed
blade base that produces the no-area triangles 10_capture.js drops; the counts
match species for species. A triangle carrying one of them still has area, so
it is drawn, and a fragment that lands on that vertex gets |vN| = 0, divides by
it in normalize(), and writes a NaN into the HDR scene target.

From there the post chain does the rest. The bloom's three separable blurs
spread it over 3.2308 x (1 + 2.6 + 4.2) = 25.2 half-res texels each way, and a
separable blur's support is a RECTANGLE, so one texel becomes an axis-aligned
square about 101 px across. The comp adds it, aces() and pow() both pass NaN,
and the frame gets a screen-axis-aligned hole. Measured on the frames the probe
caught: 112 x 112 px in six of eight. It was read off the screen as "~128 px,
suspiciously like a GPU tile" — it is the post chain's own footprint, and the
absent bloom comb is not evidence against that path either, because a comb is
what a finite impulse leaves at sparse taps and a NaN has no magnitude.

The fix is the same guard written as the negation of the valid band. It closes
the zero end with an exact comparison rather than an epsilon — the measured
population is a gap, so 0 is a bit pattern and not a small number — and it is
NaN-safe, which the `> 1.01` form was not: every comparison against a NaN is
false, so the guard phase 1 added could never fire on the fragments that
produced one. For any finite |vN| > 0 the two forms are the same test.

Measured at seed 1337 (garden=7, ff=2200, ANGLE-on-Metal, 1100x780):

  non-finite texels in rtScene   69 frames / 4,921  ->  0 / 4,040
  confirmed one-frame holes       8 frames / 4,026  ->  0 / 4,027
  near-black candidates                          8  ->  0

and flowers_guard.mjs runs both guards against the SAME frame, because a
before/after screenshot cannot answer this — the director drifts perpetually
and the air never stops, so two sessions of the unchanged build differ by a
mean 9.5/255 with 43% of pixels past 8. Over 3,921 frames: 0 blocks where both
guards are finite and disagree, against a control floor of 0, and 38 blocks
where the old one was non-finite and the new one is not. Seeds 21 and 4242 give
0 non-finite under BOTH guards, which is why they never showed the square.

flowers/build.js exits 0, parity.test.mjs stays 24/24.

Co-Authored-By: Claude Fable 5 <[email protected]>
…d it loses

tools/flowers_motes.mjs reports 0 of 320 grains in frame at `close`, and the
diagnosis is neither the grain size that tool was built to measure nor the
framing. On ?garden=7&seed=21 the subject is specimen 2, and the field's plumes
belong to the other six: 320 grains at mean heights 12.7 to 21.5, mean ndc.y
3.3 to 4.9 — four frame-heights above the picture. A close-up cannot show motes
that are not there.

flDirPlume is the term that would fix it: how many live grains are inside the
candidate corolla's own airspace, asked of the POPULATION rather than of the
plant. Re-deriving which organs are dehiscing from whorl/dev/sen would be a
second copy of FlPollen._sources's gates that drifts from it, and it answers a
worse question — what a close-up needs is not that this flower has anthers but
that there is pollen in the air where the camera is about to point. 0.8 to 1.4,
the same 1.75x spread as `rim`.

AND ON THIS SEED IT LOSES, WHICH IS THE HONEST HEADLINE. Subject scores, with
the base term re-implemented in tools/flowers_frame.mjs so the multipliers can
be read against it:

  [2] ax 0   33 petals  r 1.81   base 13.68   plume 0.80   product 9.67
  [5] ax 0    5 petals  r 1.74   base  2.14   plume 1.40   product 2.43
  [4] ax 0    7 petals  r 2.47   base  2.28   plume 1.40   product 1.74

Nothing defensible closes a factor of six and nothing should: a 33-petal corolla
really is the best flower in that field. What it cannot do is shed, and the
reason is structural rather than accidental — Sulphur Rosette has
`whorlBands: false`, so every one of its 33 floral organs carries the `petal`
flag and FlPollen._sources, which skips petals, finds no anther on it at all.
Measured across the stand: 33/33 organs petal there, against 23 stamens of 76
on the Abyssal Frond. The showiest corolla and the shedding corollas are
different flowers for a reason.

The framing half of the suggestion was measured and rejected on the
measurement, not on taste: at seed 31 the subject's OWN plume sits at mean
height 26.8 against a corolla at 17.2 — nine units above a frame about five
units tall — so no headroom this shot could give would reach it. A grain drifts
~0.32 units per unit of plant time and lives a long time; by the time there are
grains, they are gone. `low` is where motes read (5 of them over 2 px against
`close`'s 7 and `wide`'s 0), and `low` is now a better shot than it was.

inFrame at `close` is still 0 of 320. Reported, not softened.

flowers/build.js exits 0, parity 24/24.

Co-Authored-By: Claude Fable 5 <[email protected]>
It still described an open mystery and a GPU tile. The hole is ours and it is
fixed, but two of the sentences that shaped the search were wrong and are worth
leaving visible rather than deleting: 128 px was an eyeball (the square is
112 x 112, which is the post chain's own impulse support), and its collapse
test counts camera cuts, not events. What it was built to settle — both reads
of the canvas agree, so the hole is in the drawing buffer — still stands.

Co-Authored-By: Claude Fable 5 <[email protected]>
Five poses stand outside the stand and look in, and this file says twice why —
an eye anywhere inside the ring is inside a canopy, measured, twice, both times
a wall of blurred leaf. But "you cannot stand anywhere inside" and "there is
nowhere inside to stand" are different claims and only the first was ever
measured. A stand of seven planted on a jittered ring has LANES in it.

THE WIDEST LANE IS THE LARGEST GAP IN A PROJECTION. Pick a direction of travel,
project every drawn point onto the perpendicular axis, sort: two consecutive
values with nothing between them are a band of the plan no plant lies in, clear
by construction rather than clear where somebody checked. Sweep the direction at
3 degrees, the same sweep the establishing heading uses. Two constraints, both
stated: the gap's centre must be in the middle half of the field (otherwise the
widest lane skirts the OUTSIDE, which is not a traverse), and only points within
the travelled window count.

That window is the whole reason it works. Asked of the whole 67-unit field the
widest clear lane at ?garden=7&seed=21 is 2.01 units of half-width — a crack.
The camera covers 23 of those 67 units, and matter beyond the travelled segment
is in the PICTURE, not on the lens: 5.14 units of half-width over the window,
with the nearest drawn point coming to 4.29 as it passes.

TWO THINGS THE FIRST BUILD GOT WRONG, both caught by measuring:

  - A STATION IS A STEM, NOT A BLADE. The lane cleared every axis point by 6.13
    units and the frame was a wall of leaf, because a blade on this catalogue is
    10 to 22 units long against a station spacing of about one. `F.drawn` is the
    stations plus where every organ reaches (its frame's own axis, at half and
    full length), kept separate from `F.plan` because where the plants STAND and
    what is in the way of a LENS are different questions.
  - A LANE IS THE EMPTIEST LINE THROUGH THE STAND, so aiming along it aims at
    the one direction with nothing in it. On the film the last third of the
    traverse was a crowded left half and a bare right one. The aim leans onto
    the mean lateral position of everything drawn ahead within the lead — the
    establishing frame's slide onto the occupied sector, made forwards and
    continuously — clamped to a third of the frame's half width.

THE SPEED IS THE FILM'S OWN DRIFT TIMES THREE, and nothing else:
v = FL_GLIDE_K * FL_DRIFT * (frame width at the aim distance) = 0.73 u/s here,
4.6 cm/s in WORLD.unitM. tools/flowers_clip.mjs over 285 s of film measures the
glide's steady rate at 2.131 %frame/s against FL_DRIFT's 0.75 — 2.84x, and the
six shots now read 0.605 / 0.781 / 0.965 / 1.137 / 2.131 / 3.748. It is the
second-fastest shot, under the dolly.

THE RACK NEEDED NOTHING NEW. 40_boot sets uFocus to the camera-to-target
distance and the target is a fixed lead down the lane, so the plane of focus
rides ahead and every flower resolves as it reaches it and softens as it passes.

Verified rather than assumed: the sight-line cull cannot be revealed by this
shot, because captureDirty only lets camera motion dirty specimen 0 and only
when `framedAx >= 0 || heroHadCull`, both of which are false outside the
close-up. Cost is real and reported: capMs 83.1 against the dolly's 69.3 and the
wide shot's 34.5, and it is 28_lod.js doing its job — a near camera earns a
finer blade mesh.

AND A TELEPORT, FOUND TWICE IN THE SAME PLACE. `mid` is the midpoint of a
support interval, so one new hull vertex — an arm that has just grown past the
old extreme — steps it by tens of units, and 40_boot's 12%-a-frame lerp turns a
30-unit step into 3.6 units in one frame. Seven samples of a 280 s film over 50
u/s, all inside `wide`, peaking at 239 against FL_DIR_VPEAK's 26. Damped at
0.01 a frame. Then the re-decision rule below it put the spikes straight back
(196 u/s, in the middle of a HOLD) and now fires only when no shot clock is
running, which is the pinned-capture case and nothing else.

Wide shot, drawn stations across the frame, before this branch -> now:
  garden=7 seed=21   1.173 -> 1.526     garden=7 seed=31   1.281 -> 1.519
  garden=9 seed=101  1.690 -> 1.739     garden=3 seed=7    1.204 -> 1.191

flowers/build.js exits 0, parity 24/24.

Co-Authored-By: Claude Fable 5 <[email protected]>
…nds its

shot where the plants are

Three follow-ons from watching 290 s of film, all of them the same lesson: a
held frame must not be a function of what the plants did while it was held.

THE HEADING WAS THE TELEPORT, and it took three tries to convict because two
other suspects produce the same signature. `F.pa` is the direction of the field's
plan DIAMETER, and a diameter is not a continuous function of a growing stand:
one arm reaching past the old extreme swaps which pair of points is furthest
apart and swings the answer tens of degrees between two 500 ms measurements. At
the establishing frame's 90-unit standoff, 30 degrees is 47 units of eye, and
40_boot's 12%-a-frame lerp makes that 5.6 units in a frame — 336 u/s against
FL_DIR_VPEAK's 26. tools/flowers_clip.mjs, worst sample over 290 s:

    239.5  ->  196.0  ->  168.1  ->  37.7 u/s
    (lateral shift damped, then the end re-decision gated, then this)

and samples over 50 u/s went 7 -> 7 -> 6 -> none. The `wide` shot's own mean
speed fell 15.0 -> 8.2 u/s with nothing else changed, which is the same fix
reading as a calmer shot. A shot's heading is now decided when the shot begins,
like its end, its subject, its gap and its lane — except where no clock is
running, which is the ?shot= capture case and is the reason the pinned still had
been framing a fast-forwarded stand of seedlings.

A TRANSITION IS AN ARC. The low shot's POSE was solved out of the canopy and it
still entered through leaf, because a pose is where a move ENDS and the straight
line to it goes wherever it goes — and with the heading flipping end for end at
every cut, a great many of those lines run across the middle of the stand at
flower height. flDirBlendEye interpolates the eye in the field's own polar
coordinates (radius, azimuth the short way round, height), so the camera swings
around the stand rather than through it. Two poses on one bearing still give a
straight radial move, which is what the crane and the bank approach already were.
The target still lerps straight: an aim has nothing to collide with.

THE TRAVERSE SPENDS ITS SHOT ON THE MASS. Centred on the field, its last third
had passed everything flanking the lane and was aimed down the empty end of it —
a measured frame with two soft leaves in one corner and nothing else. The
flanking mass has a centroid along the lane, and the window now runs from 1.5 H
before it to 0.5 H after, so the camera spends the shot approaching and passes
through near the end. The last frame of the traverse is a corridor between two
plants instead of an empty one.

Wide shot, drawn stations across the frame, unchanged by all three: 1.526 at
garden=7 seed=21, and the pinned still is reproducible run to run now, which it
demonstrably was not.

tools/README.md gains flowers_frame.mjs, including the two things about it that
would otherwise be relearned: its dead margin is a quantile because a threshold
returns zero on these palettes, and it keeps a second copy of flowerScore that
will drift.

flowers/build.js exits 0, parity 24/24.

Co-Authored-By: Claude Fable 5 <[email protected]>
… is read

Pinning a shot stops the clock, so the glide's u saturates and the camera parks
at the end of its own travel — which, since the window is placed on the mass, is
inside it. The still is a wall of soft blade; in motion the same blade is a wipe.
And a pinned CLIP cannot show this shot at all: 45 s of ?shot=glide travels 1.1
units and scores 94% stationary, because it had arrived before the recording
started. Both measured, both written where somebody would reach for the tool.

Co-Authored-By: Claude Fable 5 <[email protected]>
flowers/README.md is the argument for this piece, so a stale sentence in it is
worse than a stale number in a table: three of them were describing code that no
longer ships. The sixth shot (`glide`) is in the table with the reason a pinned
traverse is not a useful still; the establishing heading is the field's plan
DIAMETER rather than the covariance of its origins, with the 0.584/0.777 fill
that decided it and the four seeds' NDC spans; the low shot solves its standoff
and its pitch out of the skyline; and the five measures the director now keeps
apart (`F.plan`, `F.drawn`, `F.tops`, `F.hull`, `F.discs`) are written down with
what each one is the wrong shape for.

The pollen paragraph said the drawn size "is not taken here" and it has been:
every grain sat at the rasteriser's 1 px clamp with zero variance, which is a
thing no screenshot reports. The ground gains the airlight pool and the flat
pool that was built, measured and rejected for lighting an overhead magenta.

And the second artefact is no longer an open mystery with a GPU tile in it: it
was normalize(0) on the same collapsed blade base, the 112 px is the post
chain's own impulse support, and the guard that could not see it could not see
it because every comparison against a NaN is false. The shipped page's null
geometry is now booked as a source fix rather than left as a footnote.

Co-Authored-By: Claude Fable 5 <[email protected]>
…ecided

Round 4 added a camera language, a floor and a visible plume, and every number
in them was either derived from something already shipped or set by looking.
TUNING is where that distinction is kept, so it now carries all of them with the
label attached: FL_DIR_VPEAK derived (it reproduces the two hand-set transition
times it replaced, 5.02 against 5.0 and 7.85 against 7.5), FL_DRIFT and
FL_LOW_SKY and minAng by eye with the ladders they were taken off, FL_GLIDE_K
stated as a ceiling, and the pool's length scale not a constant here at all but
the clearing's own radius.

Two of them carry a warning rather than a range. The drift's first write-up
quoted a "0.00" baseline that nobody measured — the instrument was written after
the baseline run — and the re-run corrects it and shows the close-up was never
the offender. And the establishing heading is a diameter, which is not
continuous in a growing stand: 336 u/s of eye against a 26 u/s peak, so every
per-shot decision is taken on the cut and held.

Co-Authored-By: Claude Fable 5 <[email protected]>
…n the fix

A person watching said "glitchy flashes", and ten probes later the flash and the
black square found while gating it are the same collapsed blade base reaching the
screen two ways: a triangle with no barycentric denominator handing a fragment
finite-over-nothing varyings, and a vertex normal of exactly zero making
normalize() write a NaN. Both are magnified by the same bloom chain, whose
rectangular impulse support is where the 112 px came from -- the "~128 px, so a
GPU tile" that shaped the first search was an eyeball.

The entry keeps three things a fix alone would lose. The guard added against
corrupt interpolation could not see the worse corruption, because every
comparison against a NaN is false. Three A/B designs returned confident numbers
that were the probe's own floor, and only a control told them apart. And the
cause is in src/50_geom.js, which both pages call, so this is written down as a
source fix somebody should take deliberately.

A second entry takes the round's other four results: the wind clock that had
been sampling one air at N life clocks since the garden shipped, the establishing
heading that was a covariance of origins where it wanted a diameter (and the
teleport that follows from a diameter not being continuous in a growing stand),
the flat pool of light built and rejected for lighting an overhead magenta, and
a plume-scored close-up that loses to a 33-petal corolla which structurally
cannot shed.

Co-Authored-By: Claude Fable 5 <[email protected]>
Each of these cost real time this session and none of them announces itself.
A comparison guard is not NaN-safe -- the one written against corrupt varyings
was the single thing that could not see the corruption that produced a NaN,
because every comparison against a NaN is false; the fix is to state the band
you accept rather than the failure you imagined. Three A/B probes on a page that
never stops moving each returned a confident number that was the probe's own
floor, and only the control -- the identical build against itself -- told them
apart. And a channel drawn at the rasteriser's clamp is invisible in a way no
screenshot reports: 320 grains of pollen, all at exactly 1.00 px, zero variance,
looking on screen precisely like a channel that works.

Co-Authored-By: Claude Fable 5 <[email protected]>
…s to both pages

Two of them closed differently from how the list expected, which is the reason to
write the answer down rather than tick the box. Pollen being the hero's alone was
listed with "the follow-up is cost"; the follow-up was visibility -- every grain
was drawn at the rasteriser's 1 px clamp. And the wide shot's heading was fixed
(covariance of origins -> the field's plan diameter, 0.584 -> 0.777 of the frame)
without answering what the item was actually about, which is recession, so it is
marked improved rather than done.

0f-i is the one that matters and it is only partly discharged: AJ watched and
reported a defect, which is not the same as anybody sitting through the film.

The new item is blade()'s null geometry. flowers.html fixed it downstream and
canalisation.html draws the same 7% of zero-area triangles and 2.30% of zero
normals into the same bloom chain. It is booked as a source decision with the
warning that a guard is what the other page did, and it left the cause in place.

10b also gains the wind clock, fixed on the way past: every garden member was
sampling one air field at its own life clock, so a gust could not cross the stand.

Co-Authored-By: Claude Fable 5 <[email protected]>
…watching

All three are now false. It is six shots and a 24/24 gate, and a person HAS
watched the page -- what they saw was two rasterisation bugs whose cause is in
src/50_geom.js and is still there, which is the one thing somebody arriving at
this file needs to know before they touch either page.

The list keeps its shape (short, pointing at flowers/README.md for the story)
and gains two entries that are lessons rather than features: the film's one
screen-referred rate with the derived transition pace under it, and the fact
that a channel drawn at the rasteriser's clamp is invisible in a way no
screenshot reports -- which was true of the pollen and, from the other end, of
the pool of light on the ground.

Co-Authored-By: Claude Fable 5 <[email protected]>
…rson looks

flowers_floor.mjs and flowers_motes.mjs produced the load-bearing numbers behind
the ground pool and the pollen's angular size, and neither was in tools/README.md
-- which for this project means they would have been rewritten from scratch by
whoever asked the same question next. Both entries carry the trap that bit while
writing them: floor's dMax is the defocus moving at organ silhouettes rather than
floor, and motes reports device AND css pixels because at dpr 2 the two readings
support opposite conclusions.

test/flowers_pollen.mjs was missing from CLAUDE.md's harness list too; run to
confirm before adding it (emit 971, edge 919, residual 0).

Co-Authored-By: Claude Fable 5 <[email protected]>
The probe count in the JOURNAL entry was ten and it is twelve, six per artefact,
and naming them is more useful than the total. The garden section's heading
promised four stated numbers and round 4 added five more. And a "parity 20/20"
from the round-3 ABC work now reads as a claim about the current gate, which is
24/24 -- the sort of sentence that is true of the code it was written against
and false of the code shipping.

Co-Authored-By: Claude Fable 5 <[email protected]>
… say the band

45_director.js works the glide at 0.91 u/s off Rout and its landing commit
quotes 0.73 off the solved aim distance; both are arithmetic on the same law and
neither is measured. Quoting one as if it were the answer is exactly the kind of
number this project gets caught on later, so the docs give the band and point at
the screen rate, which is the thing tools/flowers_clip.mjs actually measured.

Co-Authored-By: Claude Fable 5 <[email protected]>
flDirBlendEye stopped the eye CHORDING across the middle of the stand; what
was left is that the blended path's height and radius are still a line through
whatever canopy stands between two poses. Caught on film (shots/film/fr06.png:
one out-of-focus near blade, no subject, four seconds into a move) and now
measured — tools/flowers_trans.mjs walks every transition in a rotation with
the real poses and the real blend, against the drawn VERTICES rather than a
model of them. Before, on garden=7&seed=21: two of six transitions pass within
0.7 units of tissue and one puts foreground across 46% of the frame. Seed 1337:
0.07 units and 63%.

So a transition cranes. `eye.y += A * 4w(1-w)` — zero at both ends because the
poses are solved and must not move, and zero in VELOCITY there too since w is
already a smoothstep. A is the smallest amplitude for which nothing drawn is
within FL_DIR_BRUSH of any sample of the path, which has a closed form: it is
flDirClearance's derivation turned on its side, asking how far UP rather than
how far ALONG. Solved on the cut and held, like the establishing end, the low
shot's gap and the traverse's lane.

Three things the measurement decided rather than confirmed:

- THE AIM RISES WITH THE EYE. Lifting the eye alone pitches the lens down onto
  the canopy it just cleared, which is the same wall from above: cover 20% ->
  27%, worse. A crane is a translation, not a swing.
- F.solid, and an organ in it is a chain of spheres. `drawn` is a plan
  projection and samples an organ along its own AXIS, so the first version found
  nothing to clear on a path 0.46 units from a blade.
- 6.0 units, swept: 4 leaves the traverse's exit inside a plant, 8 buys nothing
  and starts craning the two moves that were already clear.

And the close-up's entrance was the one straight line left in the film — it is
the shipped framer, held back by a world-space lerp. It goes through the same
blend now, with the framer's own eye as the far end and the crane as an offset
that is taken back off before the framer reads its own state.

seed 21, worst interior clearance 0.07 -> 0.27 (and below the lens rather than
across it), 2/6 transitions inside 3 units -> 1/6, the traverse's exit 0.70 ->
4.49 with cover 46% -> 24%, four of six transitions untouched. A lifted path is
a longer path, so it is re-priced off the polyline it will fly (FL_DIR_VPEAK is
unchanged); the rotation goes 126.2 -> 129.7 s.

Co-Authored-By: Claude Fable 5 <[email protected]>
`src/60_render.js`'s MESH_FS does `normalize(vN)` with no guard of any kind, on
the geometry `blade()` emits, through a comp shader character-for-character the
one flowers transliterated. Every ingredient of flowers.html's one-frame black
square, and nobody had ever probed it. `tools/nan_check.mjs` is that probe.

The ingredient is there and there is MORE of it: the main page's tri stream
carries 41,775 zero normals in 565,932 vertices (7.38%) against the flowers
stream's 1.70%, with no non-unit normals at all.

Measured, over 133,731 frames on ANGLE-on-Metal, headed — solo hero, a garden of
seven at seed 1337, three named species including a fully grown Ashfall Spire,
4x the fragment samples at DPR=2, and 18,000 frames parked on a blade base
filling the frame: ZERO non-finite texels and zero one-frame holes. So the guard
was not ported, and `src/` is untouched.

The reason is structural and `node tools/nan_check.mjs geom` reproduces it. At
u = 0 a blade's half-width is zero, so all MV+1 grid vertices of that row are
the same point, `Pv - P` is the zero vector, and `v3norm` returns an exactly-zero
normal. Per quad in that row you get one triangle with TWO zero normals — area
identically zero, because two corners coincide — and one with ONE, which is
drawn. 13,924 of 13,925 two-zero triangles have area exactly 0 (the last, one
needle, has 1.05e-6). So the only locus where the interpolant is exactly zero
and a fragment could land on it is a single VERTEX; the edge that would divide
by zero over a whole span is collapsed to a point. flowers.html wins that
coincidence rarely too — 69 frames of 4,921 at seed 1337, none at seeds 21 or
4242 — and `flowers_zeron.mjs` shows the drawable population is the same
triangles species for species, so the difference is framing and rasterisation
rather than geometry.

MARK=1 is the A/B and it is better than any picture, because the wind never
stops and a screenshot differ has a floor far above the artefact: it paints the
fragments the guard WOULD discard instead of discarding them. 29,381 frames,
including the conifer and the macro blade base, marked zero blocks. Porting the
guard would be free and would buy nothing today.

Two things worth not relearning, both in the header. The first positive control
wrote `normalize(vec3(0.0))`, which is a compile-time constant — ANGLE folded it
away and the control came back clean, which would have been read as "the probe
works and the page is fine"; it builds the zero vector from a uniform that is
never written. And the exit code flips under CONTROL and MARK, because a
shipped-shader run is bad if it finds something and a control run is bad if it
finds nothing. With the control patched in, canalisation.html draws the black
square perfectly, which is the proof that the chain is identical here and only
the trigger is missing.

node build.js exits 0 and leaves canalisation.html byte-identical; smoke 73/73,
views 23/23.

Co-Authored-By: Claude Fable 5 <[email protected]>
A result nobody can find is not a result. The 2026-08-12 JOURNAL entry has the
frame counts, the geometry table that explains them, the two alternatives that
were ruled out mechanically rather than by eye, and the two instrument lessons —
including the positive control that could not fire because ANGLE folded a
compile-time constant away, which would have been read as a clean page.

Also corrects one claim in the probe's own header: the two comp shaders are not
character-for-character identical, they differ in exactly one token
(`max(c, 0.0)` against `max(c, vec3(0.0))`, a GLSL ES 1.0 requirement). That is
now a check anyone can re-run rather than something read off two screens.

Co-Authored-By: Claude Fable 5 <[email protected]>
# Conflicts:
#	docs/JOURNAL.md
… half-rise

Three corrections, all from measurement, and each one is a thing the first
version got wrong for a reason worth writing down.

THE MODEL WAS A PROXY AND THE PROXY WAS WRONG BOTH WAYS. `drawn` samples an
organ along its own AXIS, so it could not see a blade the lens was inside;
inflating each sample to a sphere of a guessed half-width then over-stated as
often as it under-stated — on seed 1337 it asked for a 36-unit crane where the
true geometry wanted none. Every specimen's FlowerBuffers holds the vertices
that went to the GPU, so `F.solid` is the drawn SURFACE now, subsampled to 8000
points a scan. Same argument as framing a close-up from the drawn reach.

THE WINDOW HAS A FLAT TOP. A crane rises, holds and comes down; `4w(1-w)` is at
full height for an instant, and dividing a required excess by a window that
small blows the amplitude past any ceiling. Two smoothsteps: 24.4 units asked
against 21.9 for the same path.

AND THE AIM RISES ONLY HALF WAY. Sweeping it on the move that cranes 21.9 units
(foreground cover / least ink): no crane 21%/45%, aim 0 20%/44%, aim 0.5
11%/38%, aim 1 10%/25%. At 0 the lens pitches into the canopy it just cleared
and the crane buys nothing; at 1 the top of the arc is empty sky, which is three
blank frames on film. `ink` is new in the harness and is what caught that — a
transition can be a bad two seconds by being empty as well as by being a wall.

The ceiling is `hHi + m` (clearing a point AT the skyline means standing a margin
above it; a bare `hHi` killed a move on seed 1337 by 5%) and it is a KILL
CRITERION: if the crane cannot clear, the director keeps the move it had.
Clamping instead flew the eye through the crown of the plant it could not get
over — clearance 6.41 -> 1.67, cover 8% -> 18%, worse than the straight path.

seed 21, against the same rotation with the crane disabled: bank -> glide cover
21% -> 11%, glide -> dolly 47% -> 25% with clearance 0.23 -> 1.10. seed 1337:
glide -> dolly 63% -> 22% and 0.07 -> 2.54, dolly -> close 47% -> 27% and
0.10 -> 9.20 (that one is the arc alone, no crane). Four of six moves untouched
on seed 21, three of six on 1337.

⚠ And a knob bug worth the line it cost: `+null` is 0 and 0 is a legal margin,
so every unswept run of the page was flying at margin zero while every swept one
used the URL. The ladder was right and the default was a different program.

Co-Authored-By: Claude Fable 5 <[email protected]>
…ry frame

Caught on film, and it predates the crane — it is in both builds. "The short way
round" is not a continuous function of two poses: at a half-turn it is a coin
flip, and `wantEye` is rebuilt every frame by the orbit, the dolly's travel and
the 500 ms field re-measure. `low` and `wide` are very nearly antipodal — one
kneeling outside the stand, one ninety units off the far side — so they sit
exactly on that flip.

tools/flowers_clip.mjs on garden=7&seed=1337 reports `low -> wide` peaking at
191 u/s in the old build and 434 in the new one, against FL_DIR_VPEAK's 26, one
4 Hz sample wide and in the middle of the blend. The track says what it is: the
eye's azimuth runs 221 -> 216 -> 204 -> 186 degrees and then jumps to 238 and
climbs, and the eye moves eighty units between two frames. The blend reversed
its direction of travel mid-move.

The difference is still read from the live want every frame — it has to be, the
want moves — but on the branch the move STARTED on, so it drifts continuously
and can never jump by a turn. Same argument as the frozen heading, the frozen
establishing end, the frozen gap and the frozen lane: nothing about a move in
progress should be a function of what the plants did while it was being flown.

Co-Authored-By: Claude Fable 5 <[email protected]>
…'s hold went

Two small things, both of which were assumptions until they were written down.

THE SOLVE COULD THREAD ITS OWN SAMPLES. Twenty-one samples on a hundred-unit
path is five units apart against a three-unit margin, so a canopy could sit
between two of them and be declared cleared by a crane that flies straight
through it. The count comes off the path's own length now, at half the margin,
measured first with a pass that touches no geometry and capped at 81 because a
solve is one pass over F.solid per sample.

AND THE LOW SHOT'S DWELL WAS NEVER BEING EATEN. It has been read the other way,
so it is worth a note where someone would look: flDirClock ADDS the transition to
the hold rather than taking it out, and tools/flowers_clip.mjs measures `low` at
12.3 s of which the move is 3.3, in the build before this work and in the build
after it. The only part of the hold the move costs is 40_boot's 0.12-a-frame
damping, about 0.15 s. Neither repair someone might reach for is needed, and
lengthening the hold would push a rotation the crane has already taken from
126 to 130 s further out still.

Co-Authored-By: Claude Fable 5 <[email protected]>
…ses under

The requirement was "the eye must be above everything within the margin in
PLAN", which asks a move that passes comfortably BENEATH a canopy to get over
it. Measured on garden=7&seed=1337, `close -> low` has 6.41 units of clearance
to anything drawn and the solve still wanted a 21-unit crane — which took the
clearance to 2.95 and the foreground cover from 7% to 20%. It made a clean move
worse to satisfy a requirement that move never violated. Passing under a plant
is a perfectly good shot.

A point pushes the eye only when the eye is INSIDE its sphere now, and then only
to the top of it; climbing out of one sphere can put the eye inside a higher one,
so the walk repeats. And the amplitude solve is iterated for the same reason one
level up: the requirement is evaluated at the height the eye will actually fly,
which depends on the amplitude being solved for, so a single pass answers the
question the OLD path asked. Without that, seed 1337's traverse exit lifted 18
units and finished with a leaf 0.4 units above the lens.

seed 1337, against the same rotation with the crane off: `close -> low` back to
6.41 / 7% / 62% (clearance / foreground cover / least ink) from the 2.95 / 20% /
28% the plan rule gave it, and `glide -> dolly` 0.32 -> 2.54 with cover 39% ->
24%. seed 21: `bank -> glide` 0.92 -> 0.50 with cover 21% -> 11%, `glide ->
dolly` 0.23 -> 1.37 with cover 47% -> 23%. Four of six moves untouched on seed
21, five of six on 1337. The rotation goes 126.2 -> 129.9 s.

Co-Authored-By: Claude Fable 5 <[email protected]>
…s own solve

A transition can be a bad two seconds in two ways and this file only measured
one of them. `ink` is the fraction of the frame with any drawn vertex in it at
any range, so a crane that rises into blank sky scores near zero on both `cov`
and `ink` and reads as a hole rather than as a wall — which is how the aim
fraction got measured instead of tasted.

Also: the per-sample MODEL column now calls flDirRise rather than the plan rule
it replaced, so the harness and the director are asking the same question.

Co-Authored-By: Claude Fable 5 <[email protected]>
…w is stale

The 3 and 4 rows were measured before the solve stopped craning over canopies
the path passes under, so they were describing a different mechanism. Re-taken:
3 lifts 22.0 and 10.2 units for cover 11% and 23%, 4 lifts 23.5 and 9.8 for 10%
and 22% — a unit and a half of extra crane for nothing a number can see. The 6
row is left as an upper bound and flagged as such rather than quietly kept.

Co-Authored-By: Claude Fable 5 <[email protected]>
…e invariant instead

The comment computed 0.91 u/s off F.Rout while commit b178e2d computed 0.73
off the solved aim distance — same law, different distance, and both are
arithmetic rather than measurements. The docs pass caught it. The number that
does not move with that choice is the measured screen rate, 2.1-2.2 %frame/s
against FL_DRIFT's 0.75, so the comment now quotes the band and anchors on
the invariant.

Co-Authored-By: Claude Fable 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant