@vitreajs/vitrea 0.11.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1665,9 +1665,197 @@ interface MaterialOptics {
1665
1665
  /** Rim band half-width in CSS px, and its ambient brightness. */
1666
1666
  readonly rimWidth: number;
1667
1667
  readonly rimAlpha: number;
1668
- /** Specular exponent and gain on the rim. */
1668
+ /**
1669
+ * **The rim band's half-width at dpr 2** (W23; claims §5.100 §5, Decision
1670
+ * Log 2 (d)) — `rimWidth`'s second reading, on the precedent of
1671
+ * `sizeScatterGainMax2x` and its siblings and interpolated by the same
1672
+ * `rampAtScale`.
1673
+ *
1674
+ * The rim's amplitude below is one law for both scales, and it cannot be: read
1675
+ * at the contour, vitrea's per-CSS-px band integral RISES 19 % between 1x and
1676
+ * 2x (0.068 → 0.081) while the reference's FALLS 10 % (0.229 → 0.205), so the
1677
+ * same amplitude that lands the 1x dark-backdrop solids at −0.003…−0.007 lands
1678
+ * the 2x rows at +0.037…+0.051. The mismatch is the band's shape and not its
1679
+ * height: at 1x over a dark backdrop the two rims are already the same
1680
+ * one-pixel line (the reference's second contour row carries 8 % of the peak
1681
+ * and vitrea's −7 %), and at 2x vitrea spreads 35 % of its peak onto the second
1682
+ * row where the reference puts 55 % of a NARROWER line. So `rimWidth` does not
1683
+ * move — the 1x rows do not ask it to — and the 2x band narrows instead.
1684
+ *
1685
+ * At dpr ≤ 1 this constant is not read at all (`rimWidthAtScale`), so a profile
1686
+ * that carries it renders the 1x material unchanged by construction.
1687
+ */
1688
+ readonly rimWidth2x: number;
1689
+ /**
1690
+ * Specular exponent and gain on the rim — **RETIRED from the rim (W24 G2;
1691
+ * claims §5.108 §1, W24 Decision Log 2 (a)), and the note is set beside the
1692
+ * W22 fit below rather than over it.**
1693
+ *
1694
+ * The term was `max(dot(normal, lightDirection), 0)^specularPower ×
1695
+ * specularGain`, one-sided, added to the rim's amplitude. W24 read the
1696
+ * reference's rim around the whole contour instead of per side and found the
1697
+ * variation it was reaching for — but symmetric about the diagonal, not
1698
+ * one-sided: the two ends of that diagonal are drawn EQUAL to a thousandth
1699
+ * (2x dark tl 0.0418 against br 0.0418; 2x light 0.2786 against 0.2823), and
1700
+ * over the nineteen untinted solid rows the one-sided form reaches a
1701
+ * normalised RMS of 0.288 against the symmetric form's 0.148, degenerating in
1702
+ * the fit to the ceiling of both its exponent and its floor trying to become
1703
+ * symmetric. So the shape was wrong, which is the deeper reason W22 G1 rightly
1704
+ * fitted the gain to 0 on the regular variant (claims §5.94 §3): no amount of
1705
+ * a term with the wrong shape helps. `rimLitExponent` below is the shape the
1706
+ * rows chose, and it replaces this one.
1707
+ *
1708
+ * Nothing on either canonical bed moves: the shipped profiles carry
1709
+ * `specularGain` 0 on `regular` since W21/W22, and no scene on either bed or in
1710
+ * the golden suite declares `clear`. What DOES change is the `clear` variant's
1711
+ * unfitted structural 0.45, which drew a one-sided highlight this material is
1712
+ * now measured not to have; it is recorded rather than replaced, because the
1713
+ * lit factor is inert on `clear` for want of rows.
1714
+ *
1715
+ * The two constants stay on the profile so that the W22 fit's record and the
1716
+ * profile documents that carry it remain readable, and so that removing them
1717
+ * is one reviewable change of the profile's SHAPE rather than a side effect of
1718
+ * a material gate. Nothing reads them.
1719
+ */
1669
1720
  readonly specularPower: number;
1670
1721
  readonly specularGain: number;
1722
+ /**
1723
+ * **The rim's amplitude law (W23; claims §5.100 §4, Decision Log 2 (a))** — the
1724
+ * term that lets the rim depend on what it is drawn over, which `rimAlpha`
1725
+ * alone cannot.
1726
+ *
1727
+ * `rimAlpha` was an additive constant: the shader added `rimWeight × rimAlpha`
1728
+ * and nothing scaled it. The reference's rim is not a constant. Read at the
1729
+ * contour (claims §5.99, §5.100 §2; W23 X1) the light reference's rim is
1730
+ * +0.23…0.26 of linear luminance over a dark solid, +0.13…0.21 over a
1731
+ * structured backdrop and clipped to white over `light-solid`, while vitrea
1732
+ * drew the same +0.060…0.078 everywhere; and the dark reference's rim GROWS
1733
+ * with what is behind it, +0.026 over `dark-solid` and +0.103 over
1734
+ * `light-solid`, at a body that moves by only a twelfth as much.
1735
+ *
1736
+ * `rimLevelGain` is the coefficient of the surface's OWN rendered level: the
1737
+ * rim becomes `rimAlpha + rimLevelGain × luminance(surface)`. Four candidate
1738
+ * forms were fitted on the reference's own solid, unclipped, uncollapsed sides
1739
+ * — 44 in light and 36 in dark, from both canonical scales and both probe grids
1740
+ * — and this one wins in both schemes on mean |residual|: 0.0081 / 0.0013
1741
+ * against 0.0249 / 0.0253 for the additive constant, 0.0168 / 0.0259 for a pure
1742
+ * screen and 0.0105 / 0.0042 for screen plus an environment term.
1743
+ *
1744
+ * The gain is SIGNED, and its sign is the whole finding. A negative gain is the
1745
+ * screen form — a white line composited source-over at a fraction of the body's
1746
+ * headroom, which is what the CSS tier's inset `box-shadow` already is — and
1747
+ * the light material's rows want one. A positive gain is a rim that rides its
1748
+ * own body up, and the dark material's rows want that, strongly.
1749
+ *
1750
+ * **The environment term is not here, and its absence is a measurement.** W23
1751
+ * chartered `rimEnvGain` — a coefficient on the backdrop source's own average
1752
+ * luminance — as the candidate (L3) for what makes the reference's rim clip
1753
+ * over a bright backdrop while its body is nowhere near white. It is declined
1754
+ * and REMOVED rather than shipped at 0: it is worse than this law on the
1755
+ * reference in both schemes, and no row of either bed separates it on vitrea's
1756
+ * side (a rendered ladder point at +0.10 of gain moved every solid cell by 0 or
1757
+ * 0.0005, because `light-solid` clips and the dark solids have no environment
1758
+ * to speak of). C9a §6.2's rule is that a constant whose rows do not separate
1759
+ * it is not carried. What the reference does there is real and is recorded in
1760
+ * the wave's Deferred list with its numbers: a bed with a mid-bright solid
1761
+ * backdrop under a light-scheme thick surface would tell the environment apart
1762
+ * from the body, and no bed that exists can.
1763
+ */
1764
+ readonly rimLevelGain: number;
1765
+ /**
1766
+ * **The lit edge (W24; claims §5.107)** — the exponent of the directional
1767
+ * factor `(√2 · |n · L|)^rimLitExponent` the rim's whole amplitude is
1768
+ * multiplied by, with `L` the profile's `rimLitAxis`.
1769
+ *
1770
+ * W23 gave the rim the right AMOUNT and the wrong SHAPE. Read around the whole
1771
+ * contour rather than per side (`results/2026-09-09-w24-lit-edge/g0/
1772
+ * read-angular.py`), Apple's rim is not constant: on the 2x dark
1773
+ * `dark-solid__rrect-md` the bins whose normal points north-west and
1774
+ * south-east read 0.0408 and 0.0418 against 0.0016 for north-east and
1775
+ * south-west, with the four straight sides at 0.0312–0.0328; the same cell in
1776
+ * the light scheme reads 0.284 / 0.286 against 0.038, sides 0.233–0.247.
1777
+ * vitrea drew one number everywhere — a drawn line, which is what the user's
1778
+ * eye called an aesthetic regression on the W23 landing sheet.
1779
+ *
1780
+ * No per-side reader could see it, and the reason is geometric: a light on the
1781
+ * 45° diagonal projects EQUALLY on all four straight sides, so `L−R` and
1782
+ * `T−B` are 0 for the reference exactly as they are for vitrea. The variation
1783
+ * lives in the corner arcs, which W23's contour reader excludes by
1784
+ * construction and W21's band reader averages into its corner overshoot.
1785
+ *
1786
+ * **The form is symmetric and it is not a Lambert.** Fitted on the reference's
1787
+ * own bins over the 19 untinted solid cells of both canonical beds and both
1788
+ * probe grids, `(√2 · |n · L|)^p` reaches an RMS of 0.148 of each cell's own
1789
+ * peak against 0.288 for the one-sided `max(n · L, 0)^p` that W22's `spec`
1790
+ * term draws and 0.312 for the flat rim vitrea ships. The one-sided form
1791
+ * cannot reach both ends of a diagonal whose two corners the reference draws
1792
+ * equal to a thousandth, and that — not its gain — is why W22 rightly fitted
1793
+ * `specularGain` to 0.
1794
+ *
1795
+ * **There is no ambient floor.** The wave chartered `a + (1 − a)|n · L|^p` with
1796
+ * `a` expected around 0.15 dark and 0.25 light. Every grouping of the rows fits
1797
+ * `a` to 0.000 (the search ran 0…0.6 in steps of 0.005), because the bin mean
1798
+ * of `|cos|^p` over the 22.5° straddling the null is already 0.10–0.16 and
1799
+ * supplies everything the null bins carry. A constant every row fits to zero is
1800
+ * a constant the material does not have (C9a §6.2), so it is not here.
1801
+ *
1802
+ * **The `√2` is the amplitude's re-expression, in closed form.** W23 fitted
1803
+ * `rimAlpha` and `rimLevelGain` on the STRAIGHT SPANS, which under this factor
1804
+ * sit at `(cos 45°)^p` of the peak. Normalising the dot product by `cos 45°`
1805
+ * inside the power makes the factor exactly 1 wherever the normal is
1806
+ * horizontal or vertical, at every exponent — so no fitted amplitude moves,
1807
+ * W23's straight-span reads hold identically rather than approximately, and
1808
+ * only the corners and the arcs change. It is why the CSS tier, whose inset
1809
+ * shadow cannot vary around a contour, needs no re-fit either.
1810
+ *
1811
+ * At 0 the factor is `pow(x, 0)` = 1 for every normal, so a profile that does
1812
+ * not carry this constant renders the W23 material byte for byte.
1813
+ */
1814
+ readonly rimLitExponent: number;
1815
+ /**
1816
+ * **The lit edge's along-side field (W25; claims §5.113, W25 Decision Log 3
1817
+ * (c))** — the slope of the position field the rim's amplitude is graded by
1818
+ * across the surface, riding `sizeThickness`.
1819
+ *
1820
+ * W24 gave the rim a factor of the NORMAL, which is one number on a whole
1821
+ * straight side. W25 G0 read the rim's peak excess by POSITION along each
1822
+ * straight side instead and found it graded on every thick cell of both probe
1823
+ * grids, on flat solid backdrops where a lens has no gradient to refract: the
1824
+ * 1x dark `dark-solid__rrect-md` reads slopes of −0.000192 (top), +0.000192
1825
+ * (bottom), −0.000379 (left) and +0.000379 (right) luma per CSS px, and the
1826
+ * corner-to-corner range 0.0187 / 0.0226 / 0.0345 on `light-solid` /
1827
+ * `dark-solid` / `mid-dark-solid` at span 96 falls to 0.0000 / 0.0016 at spans
1828
+ * 32 and 44 and saturates above 96 — the signature of a term on
1829
+ * `sizeThickness` and not of the lens.
1830
+ *
1831
+ * **The field is the product of the two normalised coordinates, and that is
1832
+ * what the four slopes say.** A field linear in position — `a·x + b·y` — gives
1833
+ * the top and the bottom side the SAME slope in x; the reference's are equal
1834
+ * and opposite. `(x / halfWidth) · (y / halfHeight)` gives exactly the measured
1835
+ * antisymmetry, is +1 at the top-left and bottom-right corners and −1 at the
1836
+ * other two — the same diagonal `rimLitAxis` is symmetric about, which is why
1837
+ * this is the position half of one light and not a second one — and predicts
1838
+ * the two sides' slope ratio as the box's aspect: 160/96 = 1.67 against the
1839
+ * measured 0.000379 / 0.000192 = 1.97, where a metric diagonal would predict
1840
+ * 1.0. Reading the reference's two sides through it gives 0.62 (top) and 0.73
1841
+ * (left) for this constant, which is the agreement a 56 CSS px straight side
1842
+ * on a six-code contrast supports.
1843
+ *
1844
+ * The factor is `1 + rimAlongSideSlope · sizeThickness(span) · field`, applied
1845
+ * beside W24's `lit` factor and outside W23's amplitude bracket. Two
1846
+ * consequences are exact rather than approximate. **The field's mean over every
1847
+ * straight side is zero**, because the product is odd in the coordinate that
1848
+ * runs along the side, so W23's and W24's straight-span amplitudes keep their
1849
+ * fitted meaning and the CSS tier — whose one inset shadow cannot vary around a
1850
+ * contour — is coherent with the GPU tier's side mean without carrying the term
1851
+ * at all. **It is exactly 0 at or below `sizeSpanMin`**, so `rrect-sm` and every
1852
+ * thin control are untouched by construction; the capsule's span of 44 takes
1853
+ * 0.0923 of it, which is the thin end's whole exposure.
1854
+ *
1855
+ * At 0 the factor is exactly 1 everywhere, so a profile that does not carry
1856
+ * this constant renders the W24 material byte for byte.
1857
+ */
1858
+ readonly rimAlongSideSlope: number;
1671
1859
  /** Inner-shadow depth (0..1) and how much of it is applied. */
1672
1860
  readonly shadowDepth: number;
1673
1861
  readonly shadowAlpha: number;
@@ -2027,6 +2215,17 @@ interface MaterialProfile {
2027
2215
  * σ 10 device px against a body σ of 1.25, and the gain sweep has a clear
2028
2216
  * minimum at 8 (RMS 0.0164 against 0.0180 at 6 and 0.0191 at 10 on the probe
2029
2217
  * bed).
2218
+ *
2219
+ * **INERT on the GPU tier at any material that names a heavy width** (W26;
2220
+ * claims §5.122 §6a). This constant reaches the deep sample only through
2221
+ * `scatterLod`, and where `sizeHeavyTapSigma` is non-zero the optics pass
2222
+ * overwrites that sample with the heavy texture — measured, not argued: fifty
2223
+ * rows byte-identical between `sizeScatterGainFar2x` 9.9 and 4.8 at the landed
2224
+ * width. It is KEPT and not retired because retiring it means deciding what a
2225
+ * profile naming NO heavy width draws, which is a code-removal wave with no
2226
+ * fidelity content (W26 Decision Log 6 (b)); the tracker carries it. The CSS
2227
+ * tier still reads it for the same reason — the collapsed single-`blur()` form
2228
+ * and the sampling-padding projection, where no heavy width applies.
2030
2229
  */
2031
2230
  readonly sizeScatterGainMax: number;
2032
2231
  /**
@@ -2146,6 +2345,11 @@ interface MaterialProfile {
2146
2345
  * **The span top, 256** — the 1x value, unchanged, because a floor of 1
2147
2346
  * leaves the deep value nothing to rise to and the top has no work at this
2148
2347
  * ratio. Stage 1 swept it against 128 and the bed did not ask for the change.
2348
+ *
2349
+ * **The gain is INERT on the GPU tier at any material that names a heavy
2350
+ * width** (W26; claims §5.122 §6a), for `sizeScatterGainMax`'s reason and with
2351
+ * the same measurement behind it. The floor and the span top above are NOT —
2352
+ * they grade the deep value's SHARE, which the heavy texture does not touch.
2149
2353
  */
2150
2354
  readonly sizeScatterGainMax2x: number;
2151
2355
  readonly sizeScatterFloor2x: number;
@@ -2195,6 +2399,19 @@ interface MaterialProfile {
2195
2399
  * 0.1125 → 0.0993 against native 0.1018 at 9.9, which is the sweep's best on
2196
2400
  * its own objective. The confirmation's holdout `rrect-lg` rose 0.9661 →
2197
2401
  * 0.9762 with its interior spread 0.0721 against native 0.0810.
2402
+ *
2403
+ * **INERT on the GPU tier at any material that names a heavy width**, and this
2404
+ * is the one of the three whose silence costs something (W26; claims §5.122
2405
+ * §§3, 6a). It is the constant that graded the 2x heavy width with the span,
2406
+ * and the heavy texture is one width per SOURCE, so where a heavy width is
2407
+ * named there is nothing left for it to grade: fifty rows byte-identical
2408
+ * between 9.9 and 4.8 at the landed width. What that gives up is measured on
2409
+ * the instrument of record rather than estimated — the reference wants **1.66
2410
+ * device px more heavy width at span 160 than at span 96 at dpr 2**, 20 % of
2411
+ * the smaller, and W26 lands one number inside 11 % of each instead. That is
2412
+ * W26 Decision Log 2 (f)'s recorded gap, now with a size; the constant is kept
2413
+ * against the profile that names no heavy width and against the wave that
2414
+ * makes the width per surface.
2198
2415
  */
2199
2416
  readonly sizeScatterGainFar2x: number;
2200
2417
  /**
@@ -2345,6 +2562,210 @@ interface MaterialProfile {
2345
2562
  readonly sizeScatterRampStartFar2x: number;
2346
2563
  readonly sizeScatterRampReach1xPx: number;
2347
2564
  readonly sizeScatterRampReach2xPx: number;
2565
+ /**
2566
+ * **The heavy share's thick end** (W25; claims §5.113, W25 Decision Log 3 (a))
2567
+ * — how much heavier the deep value runs on a thick surface than the span
2568
+ * curve above makes it, riding `sizeThickness` and read once per scale.
2569
+ *
2570
+ * W25 G0 measured the reference's kernel as TWO components and found that what
2571
+ * separates the thick surface from the thin one is neither width: read on the
2572
+ * same cell at 1x the reference's single-Gaussian width is 1.30 device px
2573
+ * against a 16 CSS px checkerboard, 4.75 against 32 and 6.25 against 64, where
2574
+ * one Gaussian returns one number at every pitch. The dot's own two-component
2575
+ * fit on `impulse__rrect-md` reads sharp σ 2.79 and heavy σ 19.52 device px at
2576
+ * 1x and 1.40 / 11.29 at 2x — both components HALVING in device px — with the
2577
+ * heavy SHARE moving 0.47 → 0.69 the other way, and 0.00 on the collapsed
2578
+ * capsule. vitrea's own pair on the landed material reaches 0.69 at 2x and
2579
+ * carries 0.23 at 1x. So the share is the quantity, and this is where the wave
2580
+ * puts it.
2581
+ *
2582
+ * ```
2583
+ * kDeep(span, dpr) = floor(dpr) + (1 − floor(dpr))
2584
+ * · smoothstep(sizeSpanMin, sizeScatterSpanMax(dpr), span)
2585
+ * + heavyShareThick(dpr) · sizeThickness(span) ← this
2586
+ * ```
2587
+ *
2588
+ * **What stays, and why the thin capsule cannot move.** `sizeScatterFloor`,
2589
+ * `sizeScatterSpanMax` and the ramp's start anchors are NOT re-derived: the
2590
+ * W11c curve stays as the law's thin end and this constant is the lift the
2591
+ * thick end takes above it. That is X5 discharged by the form rather than by a
2592
+ * capture — `sizeThickness` is exactly 0 at and below `sizeSpanMin`, so
2593
+ * `rrect-sm` and every smaller control are bit-identical whatever this says,
2594
+ * and the capsule at span 44 takes 0.0923 of it, which is the whole of the
2595
+ * thin end's exposure and is what the ladder's thin-invariance rung reads. The
2596
+ * alternative — re-expressing the whole curve on a thin/thick anchor pair —
2597
+ * would have made the capsule's own share a fitted quantity of this wave, and
2598
+ * the reference does not ask for that: its sharp σ is 2.62 device px on the
2599
+ * collapsed capsule against 2.79 on the thick rrect, span-flat to 6 %.
2600
+ *
2601
+ * **Inert at 0**, which is what ships until G3 declares the fit: the term is
2602
+ * one multiplication by zero added to the curve W11c fitted, so the resolved
2603
+ * material and every golden are byte-identical to the W24 bed.
2604
+ *
2605
+ * At dpr 2 the 2x anchor is additionally inert on the landed material for a
2606
+ * second reason: `sizeScatterFloor2x` is 1, so `kDeep` is already 1 at every
2607
+ * span and the clamp absorbs any lift. The 2x share is therefore not a
2608
+ * quantity this bed can carry, and it waits for G1's 2x probe fixtures.
2609
+ */
2610
+ readonly sizeScatterHeavyShareThick1x: number;
2611
+ readonly sizeScatterHeavyShareThick2x: number;
2612
+ /**
2613
+ * **The body's level above the thickness knee** (W25; claims §5.113, W25
2614
+ * Decision Log 3 (b)) — an OFFSET on the interior level a surface settles at,
2615
+ * in the tone response's own encoded units, reached at `sizeScatterSpanMax`.
2616
+ *
2617
+ * W25 G0 answered clause 4 in the landed law's favour and found one residual
2618
+ * it cannot carry. `sizeThickness(short side)` at knee 96 scores r 0.95–0.998
2619
+ * against 0.68–0.96 for the long side, the area, √area and the radius, on the
2620
+ * width and on the level, in both probe grids and both schemes — so the
2621
+ * argument and the knee stay. But the reference's body LEVEL keeps grading
2622
+ * above 96: on the W9 light grid over `checkerboard` it reads 0.61484 /
2623
+ * 0.61299 / 0.67915 / 0.69083 / 0.70458 across spans 32 / 44 / 96 / 128 / 160,
2624
+ * where `sizeThickness` has been flat since 96. The width does not grade there
2625
+ * on any pitch; only the level does.
2626
+ *
2627
+ * ```
2628
+ * R(x, span, dpr) = R₀(x, sizeK)
2629
+ * + sizeToneLevelFar · smoothstep(sizeSpanMax,
2630
+ * sizeScatterSpanMax(dpr), span)
2631
+ * ```
2632
+ *
2633
+ * **Where it enters.** On the tone response's OUTPUT — the settled interior
2634
+ * level `backdropToneResponse` returns, which is the law that owns the
2635
+ * interior mean (claims §5.33) — and not in the blur, not on a gain on the
2636
+ * mix, and not (this is the correction) on the response's own thin-to-thick
2637
+ * blend.
2638
+ *
2639
+ * **Why not on the blend, which is what the wave chartered.** G0's reading
2640
+ * that the residual's "sign follows the backdrop" is a reading of the
2641
+ * REFERENCE's absolute grading, and the quantity a term has to close is the
2642
+ * residual AGAINST vitrea, whose own deep value keeps rising to
2643
+ * `sizeScatterSpanMax` over the same spans. G2's ladder measured both shapes
2644
+ * on the same rows (`fit-level.txt`): carrying the blend past the thick row
2645
+ * explains 0.3 % of the above-knee residual and its per-row gains run
2646
+ * −1.13 … +0.24 with the two grids disagreeing in sign, because the blend's
2647
+ * direction is different at every backdrop level and the residual's is not. An
2648
+ * offset explains 11 % of it and the light grid's rows agree: `resid(160) −
2649
+ * resid(96)` is +2.2 … +4.2 codes over `checkerboard` at four pitches,
2650
+ * `dark-solid`, `mid-dark-solid`, `hc-text` at two pitches and `photo`, over
2651
+ * backdrops spanning 0.012 to 0.89 linear. Backdrop-independent is what the
2652
+ * rows say, so backdrop-independent is the shape.
2653
+ *
2654
+ * The curve is the one the ramp's far anchor declines along and the 2x heavy
2655
+ * gain rises along, so no new span statistic enters the material, and it is
2656
+ * **exactly 0 at and below `sizeSpanMax`** — nothing at or under span 96 moves
2657
+ * at any value of this constant, which is what let G2 probe it against the
2658
+ * frozen bed with 77 control rows reading a lever of 0.000000 codes per unit.
2659
+ *
2660
+ * Folded with `sizeK`, like the response it offsets: under reduced
2661
+ * transparency the material has stopped transmitting and the level it settles
2662
+ * at is the preference's, not the size law's.
2663
+ *
2664
+ * **Inert at 0**, which is what ships until G3 declares the fit. What G2's
2665
+ * ladder read is in `fit-level.txt`; the constant is weakly conditioned on the
2666
+ * bed as it stands and G1's probe set at both scales is what would condition
2667
+ * it (G0 §6: 118 level rows on the 1x grids, 202–238 with the 2x captures).
2668
+ */
2669
+ readonly sizeToneLevelFar: number;
2670
+ /**
2671
+ * **The heavy blur's width, in device px per scale** (W26; W26 Decision Log 1
2672
+ * and 2, from the measured cause in claims §5.116 §2) — the constant that makes
2673
+ * the deep sample's width a continuous parameter instead of a chain level.
2674
+ *
2675
+ * W25 could not raise the heavy share because vitrea's heavy component is
2676
+ * 13.3 device px at 1x against the reference's 19.5, and raising the share at
2677
+ * the wrong width adds narrow structure the reference does not have. The width
2678
+ * was not a lever: `sizeScatterGainMax` 8 → 10.3 left reader A at 13.29. W26 G0
2679
+ * measured why, and it is arithmetic rather than material
2680
+ * (`results/2026-09-10-w26-heavy-width/g0/tap-today.txt`). The body's deep
2681
+ * sample is
2682
+ *
2683
+ * ```
2684
+ * scatterLod = clamp(bodyChainLod + log2(gain), 0, chainMaxLod)
2685
+ * ```
2686
+ *
2687
+ * `chainMaxLod` is `planPyramid`'s `levelCount − 1`, and the chain stops when
2688
+ * the shorter side would fall below `MIN_LEVEL_EXTENT` = 8. On the bed's
2689
+ * 320 × 200 backdrop raster the chain is five levels, so `chainMaxLod` is **4**
2690
+ * at dpr 1, and `bodyChainLod + log2(8)` is 4.06 — **already past the clamp**.
2691
+ * Every gain at or above 7.5 draws the same level 4, whose own kernel is
2692
+ * 13.4 level-0 texels wide (`CHAIN_LEVEL_SIGMA`) — which is the 13.3 the ledger
2693
+ * recorded. G0 rendered the three impulse rows at gains 8, 10.3, 16 and 32 and
2694
+ * read them identical to the last digit, moving only at gain 4, which asks for
2695
+ * level 3.06 and gets it. So `sizeScatterGainMax`, `sizeScatterGainMax2x` and
2696
+ * `sizeScatterGainFar2x` grade a quantity the clamp then discards, and a
2697
+ * fractional level or a blend of two levels cannot widen anything at dpr 1 —
2698
+ * G0 measured both **inert to the bit** there and removed them again (W26
2699
+ * Decision Log 2 (a); the branch and `results/…/g0/` are their record).
2700
+ *
2701
+ * What widens is a Gaussian, and it is built where the chain is built. The
2702
+ * pyramid takes the chain level whose own blur is nearest below this σ and runs
2703
+ * the two separable passes it already runs for the body until the total is this
2704
+ * σ exactly (`heavyTapPlan`, `PyramidResources.heavy`), so the width is
2705
+ * continuous and is bounded by nothing the chain's depth decides — the residual
2706
+ * carries whatever octave the chain lacks. The optics pass then reads that
2707
+ * texture in place of the chain tap.
2708
+ *
2709
+ * **Per scale**, resolved by `rampAtScale` on the pattern `sizeScatterGainMax2x`
2710
+ * established, because the reference's heavy component is a device-px quantity
2711
+ * that does not simply halve between the scales (19.52 at 1x, 11.29 at 2x;
2712
+ * claims §5.113 §2) — so a profile naming only the 1x end drags the 2x end
2713
+ * toward the 2x constant's own default, and a document that means both names
2714
+ * both.
2715
+ *
2716
+ * **At 0 the mechanism does not exist**: no texture is allocated, no pass is
2717
+ * encoded, and the optics pass takes the single `textureSampleLevel` of the
2718
+ * chain the material has always taken. That is what makes the landed 0.14.0
2719
+ * goldens byte-identical.
2720
+ *
2721
+ * **What it costs, and what it gives up.** One texture and two passes per
2722
+ * source per frame — 0.070 ms on the mobile bench row, against +1.1 ms for the
2723
+ * in-shader grid G0 measured (W26 Decision Log 2 (b)). The width is then one
2724
+ * per SOURCE rather than one per pixel, so the span grading `sizeScatterGainFar2x`
2725
+ * carried does not reach the deep sample where this is on. The reference's heavy
2726
+ * width does not grade with the span at 1x (claims §5.113 §4), which is what
2727
+ * says the material can afford that; at 2x it does (the `-lg` row reads 16.92
2728
+ * against `-md`'s 11.29), and that is a recorded gap rather than an answered
2729
+ * one (W26 Decision Log 2 (f)).
2730
+ *
2731
+ * ---
2732
+ *
2733
+ * **WHAT WAS THEN MEASURED, and it moved the target as well as the width**
2734
+ * (W26 G1b and G1c; claims §5.121 and §5.122; W26 Decision Log 5 and 6 (a)).
2735
+ * The readings quoted above — 19.52 at 1x, 11.29 and 16.92 at 2x — are
2736
+ * two-Gaussian fits to ONE backdrop each, and the same reference reads 8.4
2737
+ * through `checkerboard-64` where it reads 19.5 through the impulse tile. They
2738
+ * stand as recorded, with these beside them.
2739
+ *
2740
+ * The instrument of record is the family reader: the composite this renderer
2741
+ * actually computes, fitted to the pixels jointly across every thick untinted
2742
+ * backdrop of one surface, with a per-backdrop gain. It is the only reader in
2743
+ * this wave that was held against a control — it returns vitrea's OWN drawn
2744
+ * width to 0.6 % — and on it **Apple's heavy width is 8.6–9.2 device px at
2745
+ * dpr 1 and 8.7–9.6 at dpr 2**, on both surfaces and in both schemes, with the
2746
+ * share already right to 0.07. So the 13.418 the clamped tap drew at dpr 1 was
2747
+ * half again too wide, and the reason two waves could not raise the share is
2748
+ * that more of a too-wide heavy component is more of the wrong thing.
2749
+ *
2750
+ * **The landed 9 and 9**, fitted through a ladder the reader sees one for one
2751
+ * (slope 0.995–1.111, rms 0.03–0.06 device px over seven rungs from 8 to
2752
+ * 13.418), inverted per cell: 9.48 / 8.63 / 9.19 at dpr 1 and 8.13 / 9.79 /
2753
+ * 8.37 at dpr 2. At dpr 1 the spread is 9.8 % and one number serves both spans;
2754
+ * at dpr 2 it is 20.4 % and one number does not, which is the span grading of
2755
+ * the paragraph above, now measured at 1.66 device px.
2756
+ *
2757
+ * **The mechanism has no small values** (W26 Decision Log 6 (c)). The paragraph
2758
+ * above says the mechanism does not exist at 0; the counterpart is that it does
2759
+ * exist at 0.001, where `heavyTapPlan` selects chain level 0 with a residual of
2760
+ * a thousandth of a texel and the deep sample becomes the UNBLURRED backdrop.
2761
+ * A near-zero σ is therefore the opposite of "almost off" — it is the widest
2762
+ * possible departure from the material — and a profile must name 0 or a real
2763
+ * width and nothing between. The domain is 0 or at least the chain's level-1
2764
+ * width; a floor in `heavyTapPlan` would make it continuous, and the tracker
2765
+ * carries it.
2766
+ */
2767
+ readonly sizeHeavyTapSigma: number;
2768
+ readonly sizeHeavyTapSigma2x: number;
2348
2769
  /**
2349
2770
  * The occlusion gain — "a larger size is more opaque. A smaller size is
2350
2771
  * clearer" (S284). The fraction of the *remaining* transparency the size law
@@ -2531,6 +2952,160 @@ interface MaterialProfile {
2531
2952
  readonly backdropToneLow: number;
2532
2953
  readonly backdropToneHigh: number;
2533
2954
  readonly backdropToneSizeBias: number;
2955
+ /**
2956
+ * **The transmission the collapse keeps (W24 G1)** — and the correction, set
2957
+ * BESIDE the paragraph above rather than over it, of what "texture collapse"
2958
+ * was measured on.
2959
+ *
2960
+ * W7 fitted the collapse on `dark-solid`, a backdrop with no texture in it,
2961
+ * and the paragraph above therefore says the collapse converges the interior
2962
+ * on the backdrop's mean COLOUR. On a solid backdrop the mean and the pixel
2963
+ * are the same number, so the fit could not tell the two apart; the impulse
2964
+ * bed can, and it says they are not the same. Through the reference's
2965
+ * collapsed `impulse__capsule-button` the centre dot still comes through at
2966
+ * +0.0065 linear over a body of 0.0065 at 1x and +0.0254 over 0.0065 at 2x,
2967
+ * where vitrea's collapsed capsule passes exactly 0.0000 (claims §5.107 §2).
2968
+ * The reference's collapsed material is a dark glass that still transmits what
2969
+ * lies beneath it, blurred — it collapses the LEVEL, not the structure.
2970
+ *
2971
+ * The arithmetic the collapse already has makes the correction one constant.
2972
+ * Writing `M` for the unadapted composite this pass would otherwise produce,
2973
+ * the (colour, alpha) pair the shader solves reduces exactly to
2974
+ * `colour = (1 − k)·M + k·target`, and `target` is today the group's mean
2975
+ * backdrop colour — one number for the whole surface, which is precisely what
2976
+ * flattens the dot away at `k` 1. So `collapseTransmission` lerps the TARGET
2977
+ * from that mean (0) to the per-pixel blurred backdrop sample the refraction
2978
+ * path already computed (1):
2979
+ *
2980
+ * target = mix(toneColour.rgb, backdrop, collapseTransmission)
2981
+ *
2982
+ * The tone axis's ARGUMENT is untouched — `k` is still read from the group's
2983
+ * mean luminance and the size bias, and the response law still solves against
2984
+ * `toneAnchor.w` — so the collapse collapses exactly as far as it did and
2985
+ * only stops flattening what is under it. The blurred sample's mean under the
2986
+ * surface is the group's mean to within the difference between a local and a
2987
+ * global average, so the body's LEVEL moves by less than a code where the
2988
+ * backdrop is anything like uniform, and not at all where it is solid: over
2989
+ * `dark-solid` the sample IS the mean and every collapsed cell of that bed is
2990
+ * byte-identical at any value of this constant. That is the stop the fit is
2991
+ * checked against.
2992
+ *
2993
+ * At 0 the target is the mean and the shader's arithmetic is W7's to the bit,
2994
+ * which is why this can be added without moving a pixel anywhere.
2995
+ *
2996
+ * What it cannot carry is the reference's WIDTH. Fitted on the reference's own
2997
+ * dot the transmitted profile is a 4 CSS px box convolved with σ 2.63 device
2998
+ * px at 1x and σ 1.38 device px at 2x — the same kernel the reference's
2999
+ * UNCOLLAPSED cells show (σ 2.86 / 1.40 device px on `impulse__rrect-md`), so
3000
+ * the collapse does not change Apple's blur, but that kernel is neither
3001
+ * CSS-invariant nor device-invariant and vitrea's is neither of those numbers.
3002
+ * This constant sets how MUCH comes through; how WIDE it arrives is the
3003
+ * material's own scatter law and is recorded as a gap, not fitted here
3004
+ * (W24 G1 findings).
3005
+ */
3006
+ readonly collapseTransmission: number;
3007
+ /**
3008
+ * **The collapse's transmission at dpr 2** (W24 G1), the second anchor of the
3009
+ * constant above, on the pattern `sizeScatterGainMax2x` established for the
3010
+ * body's own second scale (claims §5.69 §1).
3011
+ *
3012
+ * It is a per-scale reading and not a per-scheme one, and the evidence is the
3013
+ * fixtures': the light and dark captures of the collapsed cells are the same
3014
+ * bytes, so the collapsed appearance is one appearance in both schemes, while
3015
+ * the width the reference transmits through is a different number at each
3016
+ * scale. Fitted on the reference's own dot, its kernel is a 4 CSS px box
3017
+ * convolved with σ 2.63 device px at 1x and σ 1.38 device px at 2x — a width
3018
+ * that is invariant in neither CSS nor device pixels — so the SHARE that comes
3019
+ * through cannot be one number over a kernel that is two.
3020
+ *
3021
+ * Defaults to the 1x constant, so a profile that names only that one renders
3022
+ * it at every ratio and this anchor is the identity on the landed material.
3023
+ */
3024
+ readonly collapseTransmission2x: number;
3025
+ /**
3026
+ * **The rim that survives the collapse (W23)** — the one mark the collapsed
3027
+ * appearance keeps.
3028
+ *
3029
+ * The paragraph above is right about the body and wrong about the rim. W7 read
3030
+ * the settled reference's `dark-solid__capsule-button` as "byte-identical to
3031
+ * its own background, rim included", and at the contour it never was: the
3032
+ * fixture carries a body one code BELOW its backdrop and a contour rim of
3033
+ * +0.020 linear per CSS px (55/255 on a 28/255 backdrop at 2x), in every
3034
+ * standard profile, at both scales, in both schemes (claims §5.99). vitrea
3035
+ * folds that rim out with everything else through the shader's one
3036
+ * `present = 1 − toneAdapt`, and the user's eye named the result: "not one of
3037
+ * our glasses is visible on black, where Apple's clearly show their presence."
3038
+ *
3039
+ * So the shader's rim becomes
3040
+ * `rimWeight × (rimAmplitude × present + rimCollapsed × toneAdapt)`: the
3041
+ * scheme's own rim fading out with the adaptation as it does now, and an
3042
+ * absolute rim the collapsed appearance owns rising with it. At `toneAdapt` 0
3043
+ * nothing changes at all, which is why this constant can be added without
3044
+ * moving a single uncollapsed pixel.
3045
+ *
3046
+ * It lives on the profile and NOT in the dark patch, because the collapsed
3047
+ * appearance is scheme-independent and the fixtures say so: the light and dark
3048
+ * fixtures of `dark-solid__capsule-button` are byte-identical at both scales
3049
+ * (W23 X4). A reading that separates the schemes under collapse is a finding
3050
+ * about the wave, not a second constant. G0 strengthened the evidence: the
3051
+ * identity survives an AUTHOR TINT — `dark-solid__capsule-button__rest-tint-
3052
+ * orange` is the same bytes in both schemes at both scales — so what the
3053
+ * collapse draws is one appearance however the surface was painted.
3054
+ *
3055
+ * It is expressed in its own units and not in the dark rim's, because the two
3056
+ * were measured apart: see the value's own note on the default profile.
3057
+ */
3058
+ readonly rimCollapsed: number;
3059
+ /**
3060
+ * **The rim a PAINTED surface keeps under the collapse** (W23 G1; claims
3061
+ * §5.100 §5, Decision Log 2 (c)) — `rimCollapsed`'s sibling, at the author
3062
+ * tint's full coverage, with the two lerped by the coverage between them.
3063
+ *
3064
+ * The reference's collapsed capsules keep +0.020 of contour rim bare and
3065
+ * **+0.115 painted** (`dark-solid` and `impulse` `capsule-button`
3066
+ * `rest-tint-orange`, both schemes, both scales, on fixtures that are the same
3067
+ * bytes in the two schemes). An author tint over black is painted, not
3068
+ * adapted: the tone collapse takes the material's own appearance to its
3069
+ * backdrop and the colour the author put on it does not go with it.
3070
+ *
3071
+ * It is ABSOLUTE, in its own units, for the same reason `rimCollapsed` is and
3072
+ * on the same evidence — and G1 measured what the alternative would have cost.
3073
+ * Decision Log 2 (c) proposed gating the collapse itself on the tint's
3074
+ * coverage, so that a painted surface keeps its APPEARANCE's own rim; rendered,
3075
+ * that mechanism needs a gate of 0.534 on the light bed and 0.294 on the dark
3076
+ * one to reach +0.115 on a cell whose reference fixture is byte-identical
3077
+ * between the schemes, because it makes the kept rim proportional to each
3078
+ * scheme's own amplitude law and those differ by 1.8× there. A proportional
3079
+ * form cannot draw one appearance from two materials; an absolute one does,
3080
+ * which is X4 again and the reason this constant has the shape it has.
3081
+ *
3082
+ * It is fitted on orange alone, and that is a stated limit: the reference's
3083
+ * collapsed tint-blue capsule reads +0.176 against orange's +0.115, so the
3084
+ * quantity depends on the tint's own colour, and every collapsed blue cell on
3085
+ * the bed is holdout. What lands here is the orange rows' answer with the
3086
+ * colour dependence recorded as future work.
3087
+ */
3088
+ readonly rimCollapsedTinted: number;
3089
+ /**
3090
+ * **How much of an author tint's own colour the rim's light is spent in**
3091
+ * (W23 G3; claims §5.102) — 0…1, multiplied by the surface's tint coverage.
3092
+ *
3093
+ * Apple's rim on a painted surface is the paint LIFTED, not white added over
3094
+ * it. Read on the contour row's straight-span mean colour at 2x in light, an
3095
+ * orange paint of (255, 148, 0) rises to (254, 188, 0) with its blue channel
3096
+ * still at 0, and a blue paint of (8, 120, 236) to (59, 199, 248); vitrea drew
3097
+ * (255, 192, 130) and (145, 183, 255) — the same rim in white, which turns an
3098
+ * orange edge peach and a blue edge lilac. No luminance clause sees it: the
3099
+ * rim's amplitude is right and its colour is not.
3100
+ *
3101
+ * So the rim's light is spent in `mix(white, paint / max(paint), chroma × s)`.
3102
+ * The paint is normalised by its own brightest channel rather than by its
3103
+ * luminance, so a dark paint darkens the rim's HUE and not its amount, and the
3104
+ * factor is the pixel's own tint strength, so an untinted surface keeps a white
3105
+ * rim at every value of this constant — which is what makes the mechanism reach
3106
+ * painted pixels only and every untinted capture byte-identical (W23 S10).
3107
+ */
3108
+ readonly rimTintChroma: number;
2534
3109
  /**
2535
3110
  * **The backdrop tone response (W9)** — the law that owns the interior MEAN,
2536
3111
  * where the four constants above own texture collapse and nothing else.
@@ -2591,6 +3166,31 @@ interface MaterialProfile {
2591
3166
  * specular from.
2592
3167
  */
2593
3168
  readonly lightDirection: readonly [number, number];
3169
+ /**
3170
+ * **The lit edge's axis (W24; claims §5.107)** — the unit direction `L` the
3171
+ * rim's directional factor is symmetric about, in the same viewport
3172
+ * coordinates as `lightDirection`, y pointing down.
3173
+ *
3174
+ * It is a SEPARATE constant from `lightDirection` and not a second reading of
3175
+ * it, for two reasons the rows give. First, they are measured to differ: the
3176
+ * rim's axis fits at 136° of compass bearing over the 19 solid rows (135.0° ±
3177
+ * 0.7° over the dark rows alone, 137.7° ± 1.5° over the light ones), where
3178
+ * `lightDirection` [−0.3714, −0.9285] is a bearing of 338.2°, an axis of
3179
+ * 158.2° — 22° away, and it was fitted for the inner shadow and the sweep, not
3180
+ * for the contour. Second, `light.xy` reaches the one-sided `spec` term this
3181
+ * factor replaces, and re-pointing it to fit the contour would move the
3182
+ * shadow's own light with it; a constant of its own keeps that seam where W2
3183
+ * and W22 left it.
3184
+ *
3185
+ * The default is the exact diagonal (−1, −1)/√2 — a bearing of 135° — and not
3186
+ * the fitted 136°: the rows do not separate the two (the joint fit's RMS moves
3187
+ * by less than a thousandth between them), and only the exact diagonal makes
3188
+ * the factor equal on all four straight sides, which is what lets the
3189
+ * amplitude's re-expression be exact rather than a 2 % trade against W23's
3190
+ * straight-span reads. `rimLitExponent` is 0, so the axis draws nothing until a
3191
+ * profile carries an exponent.
3192
+ */
3193
+ readonly rimLitAxis: readonly [number, number];
2594
3194
  /** Specular sweep band width in radians, and the press glow's reach in CSS px. */
2595
3195
  readonly sweepBandRadians: number;
2596
3196
  readonly glowRadiusCss: number;
@@ -2629,6 +3229,11 @@ interface MaterialProfilePatch {
2629
3229
  readonly sizeScatterRampStartFar2x?: number;
2630
3230
  readonly sizeScatterRampReach1xPx?: number;
2631
3231
  readonly sizeScatterRampReach2xPx?: number;
3232
+ readonly sizeScatterHeavyShareThick1x?: number;
3233
+ readonly sizeScatterHeavyShareThick2x?: number;
3234
+ readonly sizeToneLevelFar?: number;
3235
+ readonly sizeHeavyTapSigma?: number;
3236
+ readonly sizeHeavyTapSigma2x?: number;
2632
3237
  readonly sizeOcclusionGain?: number;
2633
3238
  readonly sizeShadowGainMax?: number;
2634
3239
  readonly lensRefractionGain?: number;
@@ -2653,12 +3258,18 @@ interface MaterialProfilePatch {
2653
3258
  readonly backdropToneLow?: number;
2654
3259
  readonly backdropToneHigh?: number;
2655
3260
  readonly backdropToneSizeBias?: number;
3261
+ readonly collapseTransmission?: number;
3262
+ readonly collapseTransmission2x?: number;
3263
+ readonly rimCollapsed?: number;
3264
+ readonly rimCollapsedTinted?: number;
3265
+ readonly rimTintChroma?: number;
2656
3266
  readonly backdropToneAnchorX?: readonly [number, number, number];
2657
3267
  readonly backdropToneResponseThin?: readonly [number, number, number];
2658
3268
  readonly backdropToneResponseThick?: readonly [number, number, number];
2659
3269
  readonly backdropToneResponseStrength?: number;
2660
3270
  readonly outerShadow?: Readonly<Partial<MaterialOuterShadow>>;
2661
3271
  readonly lightDirection?: readonly [number, number];
3272
+ readonly rimLitAxis?: readonly [number, number];
2662
3273
  readonly sweepBandRadians?: number;
2663
3274
  readonly glowRadiusCss?: number;
2664
3275
  readonly glowGain?: number;
@@ -3407,6 +4018,7 @@ interface RebuildLedger {
3407
4018
  * import provider frame -> chain mip 0 (premultiplied linear, X5)
3408
4019
  * downsample mip n-1 -> chain mip n (13-tap, one pass per level)
3409
4020
  * blur x2 chain[bodyLvl] -> body (separable, residual sigma)
4021
+ * blur x2 chain[heavyLvl] -> heavy (separable, residual sigma; W26)
3410
4022
  * analysis chain[anaLvl] -> stats buffer (compute, one workgroup)
3411
4023
  * ```
3412
4024
  *
@@ -3421,6 +4033,23 @@ interface PyramidResources {
3421
4033
  readonly plan: PyramidPlan;
3422
4034
  readonly chain: GPUTexture;
3423
4035
  readonly body: GPUTexture;
4036
+ /**
4037
+ * The **heavy** blur (W26; `MaterialProfile.sizeHeavyTapSigma`) — one more
4038
+ * texture beside the body, built by the same two separable passes from
4039
+ * whichever chain level `heavyTapPlan` names, and `undefined` where the
4040
+ * profile asked for no width.
4041
+ *
4042
+ * It is here rather than in the optics pass because the optics pass is a
4043
+ * fragment shader over the glass's own area: W26 G0 measured a 9 × 9 in-shader
4044
+ * grid at +1.1 ms on the mobile bench row against 0.070 ms for the two
4045
+ * separable passes the chain already runs (W26 Decision Log 2 (b)). The price
4046
+ * of building it here is that the width is **one per source** rather than one
4047
+ * per pixel — every group sampling this source gets the same heavy width,
4048
+ * because the texture is built before any group is drawn. The reference's heavy
4049
+ * width does not grade with the span at 1x (claims §5.113 §4), which is what
4050
+ * says the material can afford that.
4051
+ */
4052
+ readonly heavy: GPUTexture | undefined;
3424
4053
  readonly stats: GPUBuffer;
3425
4054
  /** Source size epoch this allocation was made for. */
3426
4055
  readonly sizeEpoch: number;
@@ -3458,6 +4087,14 @@ interface PyramidResources {
3458
4087
  * chain's body and `bodyChainLod` belong to the previous scale.
3459
4088
  */
3460
4089
  readonly bodySigmaCss: number;
4090
+ /**
4091
+ * The heavy blur's σ in **CSS px** the build converted with, for `sameBody`'s
4092
+ * reason and by the same rule: the heavy width is a device-px quantity
4093
+ * (claims §5.113 §2), so `sizeHeavyTapSigma / dpr` is what reaches the source's
4094
+ * texels, and a window dragged between displays asks for a different heavy
4095
+ * texture from the same clean source.
4096
+ */
4097
+ readonly heavySigmaCss: number;
3461
4098
  }
3462
4099
  interface PyramidInstrumentation {
3463
4100
  /** Successful rebuilds since the store was created. */
@@ -3487,6 +4124,12 @@ interface PyramidBuildRequest {
3487
4124
  * The build resolves it once the frame's real extent is known.
3488
4125
  */
3489
4126
  readonly bodySigmaCss: number;
4127
+ /**
4128
+ * The heavy blur's σ in **CSS px** (W26), 0 where the profile declines the
4129
+ * width — at which point nothing is allocated and nothing is drawn, so a
4130
+ * material that names no heavy width pays for none of this.
4131
+ */
4132
+ readonly heavySigmaCss: number;
3490
4133
  readonly viewportCss: readonly [number, number];
3491
4134
  /**
3492
4135
  * Where the source sits on the plane, in CSS px relative to the viewport, if