@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/{dist-JWOMZCFF.js → dist-PT4PUS4K.js} +844 -44
- package/dist/dist-PT4PUS4K.js.map +1 -0
- package/dist/index.d.ts +644 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/dist-JWOMZCFF.js.map +0 -1
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
|
-
/**
|
|
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
|