Commit graph

2 commits

Author SHA1 Message Date
CRT
9de2721422 Frame every model in the tour, and measure that it does
The showcase is the one deliverable a still render cannot check, and until now
the only way to check it was to watch it -- which is how a model half out of
frame gets shipped. `__probe.framing()` projects the current model's bounding
box into the frame and reports the worst corner in normalised device
coordinates: 0 is comfortably inside, 1 is exactly on the edge. The whole 60
seconds can then be swept and the bad moments found by number.

Swept, it found five models leaving the frame. Four of them were during the dip
between beats, where the veil is 92% opaque and the point is that you cannot see
the swap -- so the honest figure is two frames out of 1060, the broom and the
ladder, each for a twentieth of a second. Not much. Also not nothing, when the
whole point of the tour is that someone records it once and posts it.

The first fix was to widen the framing margin from 1.55 to 1.62. It worked and
it was the wrong fix: it took a slice of the frame off all thirty-five models to
buy back two frames from one, and mean fill fell to 0.515 -- every model sitting
in half a screen of empty space.

The right fix is in the chase. The camera's distance follows the model's size by
exponential approach at a single rate, and the two directions are not the same
mistake: falling behind a model that is GROWING crops it, and falling behind one
that is shrinking only leaves it small for a moment, which nobody notices. The
broom was the last offender because its bundle and its handle both sweep. So the
camera now retreats at 18 and closes at 7, and with that in place the margin
came back in past where it started, to 1.38.

Measured over the visible frames of a full 60 s run: no frame crops, the closest
any model comes to the edge is 0.81, and mean fill is 0.605 against 0.515 for
the wide-margin version and 0.55 for the original. Models are bigger in frame
than before AND nothing is cut.

Also here: the tour verified end to end -- 1201 frames, 60.05 s, 35 models, no
repeats, chest to oak -- and two stale numbers in the README. It claimed ~800
checks (1,044) and did its showcase arithmetic for 27 models, which is the kind
of sentence that goes quietly wrong every time a model is added, so it now says
what the number does when the kit grows.

One correction to my own measurements, twice over. `showcase.update` clamps its
delta to 0.05 internally, which `frameStep` does not, so stepping 0.2 advances
0.05 -- my first two readings of the tour's length were wrong by 4x and 10x and
disagreed with each other, which is what gave it away. And the run that
reported 34 models in 57.8 s was racing a page reload, not a dropped model.
2026-08-27 01:30:34 +07:00
CRT
7d2877c901 Add the oak
The first thing in this kit that grew rather than got made, and the first one
built entirely against reference photographs from the start rather than after
three rounds of guessing.

Two references, generated with the same Codex tool the rest of the kit now
uses: one oak in full leaf and the same tree bare. Both of them contradicted
what I was about to build, and the default lowpoly tree -- a tall pole with a
ball on it -- turns out to be wrong in every measurement that matters.

  crown width / tree height     1.32 to 1.43.  An open-grown oak is half again
                                as WIDE as it is tall. Nothing else in this kit
                                is wider than it is tall.
  widest at                     24% of the height. Not halfway up: a quarter,
                                just above the ground, because the lowest limbs
                                are the longest and leave almost horizontally.
  bole runs to                  72% of the height as one continuous stem. It
                                does not fork low into equal leaders, which is
                                what the leafy photograph alone suggested and
                                the winter one disproved.
  bole width / height           0.130 at 2% of the height, 0.073 at 10%. It
                                nearly halves in the bottom tenth and then
                                barely tapers at all for a quarter of the tree.

The taper table in the model is those rows, read off the photograph one at a
time. The limbs SWEEP -- out at a shallow angle, turning up at the end -- which
comes free from bending each limb along its own axis before rotating it into
place, and which cost a correction I had not expected: bending a limb swings
its whole chord up by half the arc, so every limb was arriving 0.21 rad high
and the crown's widest point had climbed to 38%. Aiming low by exactly what the
bend will lift is the fix, and it is a constant.

Measuring is the whole story of this one. `scripts/probe-tree.ts` prints the
four reference numbers off the built geometry the same way they came off the
photographs, plus one a photograph cannot give: how many separate pieces the
crown is in. A crown is one piece. This one was four, then one, then two, then
one again, and the flood fill was right every time my eye was vague.

Four things it caught that looking would not have:

  - Forks throwing DOWNWARD. The rise of a fork is sin(splay) * sin(spin), so
    the sign of the PRODUCT decides it. I constrained the spin and alternated
    the splay, which left every second fork pointing at the floor. The
    measurement said so plainly while the reasoning said the opposite.
  - The crown torn in two, and not where I kept looking. Locating the loose
    piece -- height 10-64%, bearing 228-313, reaching 5.7 m where the main mass
    stopped at 4.5 -- ended four rounds of widening clumps and evening out
    bearings, none of which were the gap. The gap was the MIDDLE: pushing the
    leaves outboard to open the space under the crown had taken the inside out
    with it, and nine lobes hung off a bare hub. The reference's crown is full
    from the bole outward; the clear space is underneath.
  - Occlusion, exonerated. Turning it off entirely changed the clipping by
    nothing at all, which took two minutes and saved a redesign.
  - My own metric, wrong twice. It counted every dark pixel in the crown's box
    and 87% of what it found was the cast shadow, so it read 10.8% clipping on
    a crown that was barely clipping. And it measured the reference by row
    width but our own geometry by twice its radius, which is a different
    quantity on anything that is not symmetric.

Colour is measured too, and the measurement contradicted me again: I was about
to bake a top-to-bottom gradient into the crown, and sampled in three bands the
reference reads 0.362, 0.336, 0.324 -- no gradient at all. What is there is
local, a spread of 0.45 in lightness within one band. Foliage varies leaf to
leaf, not top to bottom. Chasing that 0.45 with tint, mottle and occlusion all
at once put 2.2% of the crown through the floor into pure black against the
reference's 0.19%, which is the straw trap for the third time: a statistic taken
off fine detail cannot be added on top of the machinery that already
reproduces it.

The bark is measured off the WINTER photograph after the summer one gave a
colour 28 degrees too green -- a trunk under a full crown is lit through the
leaves. Low saturation made it worse than the hue did: a nearly neutral colour
takes its hue from its light, and this renderer's blue-grey sky dragged the
rendered bole to hue 119 on a tree whose bark is brown.

Finished: hue 79.6 against 77.9, saturation 0.386 against 0.381, lightness
0.386 against 0.373, 0.00% clipped. Crown 1.325 wide for its height, in one
piece, hanging from 8% where the reference hangs from 11%.

The honest limits. What fills a real winter silhouette is thousands of twigs
and no budget here reaches them, so `leafiness: 0` is a bare tree of LIMBS --
a good dead or winter tree, not a photograph of one. And the crown still
carries more of its width high than the reference does: widest at 50% against
24%, on a reference profile that is nearly flat from 24 to 44 so the peak is
softer than the number sounds.

2310 triangles, inside the kit's 2500 budget, which cost a side off every clump
and a level off every fork -- but not one clump, because the count is what
holds the crown together. 35 models, 31 404 triangles, thirteen material slots,
all checks pass, 0 floating cases, GLB round-trip clean, Conformant.
2026-08-23 19:47:21 +07:00