@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.
@@ -255,7 +255,70 @@ var DEFAULT_MATERIAL_PROFILE = {
255
255
  tint: srgbToLinear(SRGB_WHITE_TINT),
256
256
  tintAlpha: 0.46,
257
257
  rimWidth: 1.5,
258
- rimAlpha: 0.18,
258
+ /*
259
+ * REFITTED 0.18 → 0.844 (W23 G1; claims §5.100 §4, W23 Decision Log 2 (a)),
260
+ * as the intercept of the amplitude law below rather than as the whole rim.
261
+ *
262
+ * It is not the same quantity it was. Before W23 this constant WAS the rim,
263
+ * and 0.18 drew the same +0.060…0.078 of linear luminance at the contour on
264
+ * every cell of the light bed against a reference of +0.10…+0.26; now it is
265
+ * one of two terms, and on a light surface whose own level is 0.48 the pair
266
+ * draws `0.844 − 0.628 × 0.48 = 0.542` of amplitude — three times the old
267
+ * constant, for a rim about a third brighter than the old one at the
268
+ * contour, because the amplitude is not the rim: the band weight `W` the
269
+ * first two CSS px carry is 0.38…0.46 (claims §5.100 §4).
270
+ *
271
+ * Fitted on vitrea's OWN captures, not on a prediction: the shader's rim is
272
+ * linear in each constant, so a base capture at the shipped `rimAlpha`
273
+ * gives each cell's band weight and one rendered `rimLevelGain` point gives
274
+ * `W × L`, and the pair is solved by least squares over 40 rendered solid
275
+ * rows on 10 cells. **The canonical bed cannot fit it** — over a solid
276
+ * backdrop, unclipped, uncollapsed and outside the holdout the light bed
277
+ * leaves exactly two cells at bodies 0.48 and 0.43, and two nearly collinear
278
+ * rows separate no slope from an intercept (solved on 1x alone they give
279
+ * (0.302, +0.569) and on 2x alone (0.383, +0.183), a factor of three apart
280
+ * and both with the wrong sign) — so W9's light probe grid, whose bodies
281
+ * span 0.43…0.93, is what conditions the solve (9.7). That the routine
282
+ * harness captures no probe grid is recorded as a gap, not fixed here.
283
+ *
284
+ * Rendered, on the rows the wave's acceptance names: the light 1x solid
285
+ * cells go from 0.087 to 0.016 mean |rim − reference| per side (worst 0.168
286
+ * → 0.033) and `dark-solid__rrect-md` from 0.068 to 0.227 against the
287
+ * reference's 0.229.
288
+ *
289
+ * W22 G1 declined this constant on the same rows and that decline is not
290
+ * rewritten (claims §5.94 §3): it was read through the declared box's 3 CSS
291
+ * px band, whose peak-row mean over a dark backdrop carries the corners'
292
+ * backdrop and dilutes a one-pixel line, and it was the right answer to the
293
+ * question that instrument asked. The contour read is a different question.
294
+ */
295
+ rimAlpha: 0.844,
296
+ /*
297
+ * FITTED 1.35 (W23 G1; claims §5.100 §5, Decision Log 2 (d)) — the band at
298
+ * dpr 2, about 10 % narrower than at dpr 1.
299
+ *
300
+ * Two clauses of the wave meet on this constant and they pull opposite
301
+ * ways, which is why it is not simply the minimiser of one of them. The
302
+ * uncollapsed 2x solids want the band NARROW: at 1.5 `dark-solid__rrect-md`
303
+ * reads +0.2467 against the reference's +0.2052 on the light bed, and the
304
+ * rendered ladder point at 1.2 reads +0.1883, so the row's own answer is
305
+ * 1.29. The COLLAPSED cells want it wide, because `rimCollapsed` was
306
+ * fitted through this same band: at 1.5 they read −0.0017 from the
307
+ * reference and at 1.2 −0.0059, which is outside the wave's 0.005.
308
+ *
309
+ * 1.35 leaves the solids at +0.0123 against a bound of 0.03 and the
310
+ * collapsed sides at 0.0038 against a bound of 0.005 — each clause inside
311
+ * its own bound with margin in proportion to how tight that bound is. The
312
+ * joint minimiser over the twelve rows is 1.30, and it is not taken: at
313
+ * 1.30 the collapsed sides read 0.0045 against a 0.005 bound, a margin of
314
+ * 0.0005 on an instrument whose 8-bit resolution at that level is 0.00067.
315
+ *
316
+ * The dark bed does not identify it — its one 2x solid row moves by 0.0061
317
+ * across the whole ladder and is inside the bound at every value — so this
318
+ * is the light bed's constant, checked against the dark bed rather than
319
+ * fitted on it.
320
+ */
321
+ rimWidth2x: 1.35,
259
322
  specularPower: 6,
260
323
  /*
261
324
  * FITTED 0.55 → 0 (W22 G1; claims §5.94 §3, W22 Decision Log 2 (b)). The
@@ -303,6 +366,112 @@ var DEFAULT_MATERIAL_PROFILE = {
303
366
  * makes it inert.
304
367
  */
305
368
  specularGain: 0,
369
+ /*
370
+ * FITTED −0.628 (W23 G1; claims §5.100 §4, W23 Decision Log 2 (a)) — the
371
+ * light rim is a fraction of the body's HEADROOM, and the negative sign is
372
+ * the measurement.
373
+ *
374
+ * On the reference's own solid, unclipped, uncollapsed light sides — 44 of
375
+ * them, bodies 0.4287…0.9326, from both canonical scales and W9's probe
376
+ * grid — the rim falls as the surface brightens: `0.3559 − 0.2752 × base`,
377
+ * mean |residual| 0.0081 where an additive constant reads 0.0249 and a pure
378
+ * screen 0.0168. A pure screen would need the slope to be exactly −α; it is
379
+ * −0.275 against the −0.43 the screen form requires, which the canonical
380
+ * bed's two cells at 0.43 and 0.48 could not have told apart and the probe
381
+ * grid's range can. So the light rim is a white line composited source-over
382
+ * — the form the CSS tier's inset `box-shadow` has always drawn — with an
383
+ * additive part beside it, and this is that composite written once.
384
+ *
385
+ * The gain is steeper here (−0.628) than on the reference (−0.2752) for the
386
+ * same reason `rimAlpha` is larger than the rim: this constant multiplies
387
+ * the shader's per-pixel `rimLuma` before the band weight, and the fit is
388
+ * the one solved on rendered rows.
389
+ */
390
+ rimLevelGain: -0.628,
391
+ /*
392
+ * ADOPTED 1.15 (W24 G2, on G0's fit; claims §5.108 §1, W24 Decision Log 2
393
+ * (a)) — one exponent for both schemes and both scales, and the value at
394
+ * which the most rows meet the wave's clause.
395
+ *
396
+ * The rows, and what they separate. Fitted on the reference's own angular
397
+ * bins over the nineteen untinted solid cells of both canonical beds and
398
+ * both probe grids (285 bins, each cell normalised by its own brightest
399
+ * bin), the joint minimiser is 1.05; the 2x rows — whose arcs the raster
400
+ * actually resolves — give 1.10 light and 1.30 dark, and vitrea's own
401
+ * rendered rows read against the reference give 1.10 ± 0.22 light and
402
+ * 1.24 ± 0.17 dark. The schemes OVERLAP, so what the rows separate is one
403
+ * constant and not two, and 1.15 is where four of the twelve solid rows
404
+ * meet both halves of clause 1 against two at 1.00, two at 1.30 and none
405
+ * at 1.45.
406
+ *
407
+ * What it is not. It is not a per-scale pair: every 2x row wants 1.30–1.45
408
+ * and every 1x row 0.85–1.10, which is a real scale dependence in the
409
+ * reference's own angular contrast (its lit-diagonal bins over its
410
+ * straight-side bins read 1.07 at 1x against 1.39 at 2x on the dark
411
+ * `dark-solid` capsule). A `rimLitExponent2x` sibling on the precedent of
412
+ * `rimWidth2x` would be a third constant fitted on four rows, so the
413
+ * dependence is recorded (W24's Deferred list) rather than carried.
414
+ *
415
+ * The `clear` variant keeps 0 below: no scene on either bed declares it, so
416
+ * it has no rows and nothing to be fitted on (C9a §6.2).
417
+ *
418
+ * RE-FITTED 1.15 → 0.85 (W25 G3b, on the parent's ruling; claims §5.115,
419
+ * W25 Decision Log 6), JOINTLY with `rimAlongSideSlope` below and not
420
+ * separately, because the two multiply the same rim amplitude and both peak
421
+ * on this same diagonal. W24 fitted this exponent with the position term
422
+ * ABSENT, over 285 bins that include the corner arcs, so it absorbed part of
423
+ * a grading that is not a function of the normal at all — and W25 G0's
424
+ * along-side reader, which walks only the STRAIGHT part of a side where this
425
+ * factor is exactly 1, could not see the overlap from its side either.
426
+ * W25 G3's dry run measured the consequence: at slope 0.45 under exponent
427
+ * 1.15 the NW and SE bins of the 1x light `dark-solid__rrect-md` went 0.142
428
+ * → 0.203 against a reference of 0.122, and the thick solids' mean bin error
429
+ * rose on 26 rows of 28.
430
+ *
431
+ * The joint fit is a rendered GRID over the plane — 46 points, each a real
432
+ * render of the solid rows of all four standard profiles, read by W24's
433
+ * angular reader and W25's along-side reader together
434
+ * (`results/2026-09-09-w25-thick-span-composite/g3/g3b-fit.txt`). The pair
435
+ * below is the joint objective's minimum among the pairs that keep the thick
436
+ * solids' angular error at or under the 0.13.0 bed's — the ruling's own
437
+ * acceptance condition — AND that leave every cell of the bed measurable:
438
+ * thick bin error 0.17527 → 0.17208 and thick range error 0.43269 → 0.37472,
439
+ * on 16 rows improving against 12. The objective's own minimum over the
440
+ * allowed set is (0.70, 0.15), and it is refused for a reason no metric
441
+ * carries: at that pair the collapsed `dark-solid__capsule-button` loses its
442
+ * contour on the GPU tier at 1x in both schemes — the capsule's band is
443
+ * entirely corner arc, which is where both of these factors dim it, and the
444
+ * extractor reads a 0.00 px contour and drops two calibration cells out of
445
+ * the bed. A change that narrows the instrument is not a fidelity gain.
446
+ */
447
+ rimLitExponent: 0.85,
448
+ /*
449
+ * W25's along-side field, FITTED (claims §5.113 and §5.115; W25 Decision
450
+ * Log 3 (c), landed at G3's declaration).
451
+ *
452
+ * Its own readers want more of it: G2 fitted 0.45 on the 64 straight sides
453
+ * of the two 1x probe grids' flat solids and G3 re-fitted 0.425–0.479 on the
454
+ * probe set's 64 sides at both scales in both schemes, and at 0.45 the
455
+ * corner-to-corner range reaches 0.743 of the reference's against 0.227
456
+ * without it. What the along-side reader cannot see is the corner ARCS,
457
+ * where this factor multiplies a rim that `rimLitExponent` has already
458
+ * brightened on the same diagonal — so the value here is not that fit's, it
459
+ * is the JOINT one (W25 G3b; W25 Decision Log 6): the minimum over a
460
+ * rendered grid of the two readers' errors together, among the pairs that
461
+ * keep the thick solids' angular error at or under the 0.13.0 bed's.
462
+ *
463
+ * At (0.70, 0.15) the thick solids' bin error falls 0.17527 → 0.17000 and
464
+ * their range error 0.43269 → 0.34919 — a fifth of the grading, where 0.45
465
+ * under the old exponent bought three quarters of it and cost half again as
466
+ * much bin error. The remaining four fifths are not this constant's to buy:
467
+ * the arcs' amplitude is W23's rim law, fitted on the straight spans both of
468
+ * these factors leave alone, and until it moves the two of them are trading
469
+ * against each other rather than against Apple.
470
+ *
471
+ * The `clear` variant keeps 0 below, as the lit edge does: no scene on
472
+ * either bed declares it, so it has no rows (C9a §6.2).
473
+ */
474
+ rimAlongSideSlope: 0.1,
306
475
  shadowDepth: 0.35,
307
476
  /*
308
477
  * REFITTED 0.55 → 0.05 (2026-08-31), and it is the largest single
@@ -327,8 +496,18 @@ var DEFAULT_MATERIAL_PROFILE = {
327
496
  tintAlpha: 0.1,
328
497
  rimWidth: 1.25,
329
498
  rimAlpha: 0.14,
499
+ // No scene on the calibration bed declares this variant, so its rim has no
500
+ // rows: the amplitude law stays at the additive form and the band stays
501
+ // ungraded across the scales (W22's rule for `clear`, C9a §6.2).
502
+ rimWidth2x: 1.25,
330
503
  specularPower: 8,
331
504
  specularGain: 0.45,
505
+ rimLevelGain: 0,
506
+ // No scene declares this variant, so the lit edge has no rows here either
507
+ // and the factor stays inert (C9a §6.2, as `rimLevelGain` above).
508
+ rimLitExponent: 0,
509
+ // Nor does the along-side field have rows here, for the same reason.
510
+ rimAlongSideSlope: 0,
332
511
  shadowDepth: 0.22,
333
512
  shadowAlpha: 0.4,
334
513
  highlight: srgbToLinear(SRGB_WHITE_TINT)
@@ -515,6 +694,41 @@ var DEFAULT_MATERIAL_PROFILE = {
515
694
  sizeScatterRampStartFar2x: 0.21,
516
695
  sizeScatterRampReach1xPx: 80,
517
696
  sizeScatterRampReach2xPx: 100,
697
+ // W25's three mechanisms, all INERT at the defaults (claims §5.113; W25
698
+ // Decision Log 3). The heavy share's thick lift and the level term above the
699
+ // knee are zero, so `kDeep` and the tone response's blend are the curves W11c
700
+ // and W9 fitted, to the bit; the along-side field's slope lives on the optics
701
+ // beside `rimLitExponent` and is zero there. G2 fits them and G3 declares
702
+ // them; what the fits read is recorded in
703
+ // `results/2026-09-09-w25-thick-span-composite/g2/`.
704
+ sizeScatterHeavyShareThick1x: 0,
705
+ sizeScatterHeavyShareThick2x: 0,
706
+ sizeToneLevelFar: 0,
707
+ // The heavy blur, FITTED (W26; claims §5.121 for the identification and §5.122
708
+ // for the fit; W26 Decision Log 6 (a)). Apple's heavy width is 8.6–9.5 device px
709
+ // at BOTH scales, read by the family reader — the one instrument in this wave
710
+ // that passed a control, reproducing vitrea's own drawn width to 0.6 % — and
711
+ // inverted through a ladder whose slope is 0.995–1.111 at an rms of 0.03–0.06
712
+ // device px. What the 0.14.0 material drew at dpr 1 was `CHAIN_LEVEL_SIGMA[4]` =
713
+ // 13.418, the pyramid's LAST level, because `scatterLod` was clamped there: half
714
+ // again too wide, and the share the two previous waves tried to raise was already
715
+ // right to within 0.07. The reference asks 9.48 / 8.63 / 9.19 at dpr 1 (spread
716
+ // 9.8 %, so one number serves both spans) and 8.13 / 9.79 / 8.37 at dpr 2 (spread
717
+ // 20.4 %, so one number does not — the 1.66 device px between spans 96 and 160 is
718
+ // the grading `sizeScatterGainFar2x` used to carry, and one width per source
719
+ // cannot; W26 Decision Log 2 (f) chose that knowingly). Nine is within 1.1 % of
720
+ // the 1x mean and 0.4 % of the 2x light pair's, and it takes
721
+ // |log(read / reference)| from 0.275 to 0.069 over six cells.
722
+ //
723
+ // THE MECHANISM HAS NO SMALL VALUES (W26 Decision Log 6 (c)). `pyramid.ts` builds
724
+ // the heavy texture whenever `heavySigmaCss > 0`, and at σ 0.001 `heavyTapPlan`
725
+ // selects chain level 0 with a residual of a thousandth of a texel — which makes
726
+ // the deep sample the RAW backdrop and moves every 2x row. So 0.001 is not
727
+ // "almost off"; it is the opposite of off. The inert value is exactly 0, and
728
+ // neither anchor may ever carry a small non-zero. The domain is 0 or at least the
729
+ // chain's level-1 width, and the tracker carries the floor that would close it.
730
+ sizeHeavyTapSigma: 9,
731
+ sizeHeavyTapSigma2x: 9,
518
732
  sizeOcclusionGain: 0.05,
519
733
  sizeShadowGainMax: 1,
520
734
  /*
@@ -647,6 +861,122 @@ var DEFAULT_MATERIAL_PROFILE = {
647
861
  * thickness axis now.
648
862
  */
649
863
  backdropToneSizeBias: 0.05,
864
+ /*
865
+ * FITTED 0.017 at dpr 1 and 0.070 at dpr 2 (W24 G1, landed by G2; claims
866
+ * §5.108 §2, W24 Decision Log 2 (b) and (d)) — one pair for both schemes, on
867
+ * the peak of the collapsed `impulse__capsule-button`'s centre dot.
868
+ *
869
+ * At `k` 1 the composite is exactly `(1 − c)·toneColour + c·backdrop`, so the
870
+ * dot's excess is LINEAR in this constant and one non-zero rendered rung fixes
871
+ * it: at c 0.10 vitrea's collapsed capsule passes +0.0386 at 1x and +0.0363 at
872
+ * 2x where the reference passes +0.0066 and +0.0254, which gives 0.0171 and
873
+ * 0.0700. Rendered back at the fit the dot lands +0.0067 and +0.0256 —
874
+ * clause 2's peak met to ±0.0002 against a bound of 0.005 — and the structure
875
+ * that had been passing 0.0000 passes 0.0066 at 1x and 0.0250 at 2x against
876
+ * the reference's 0.0104 and 0.0205.
877
+ *
878
+ * The light and dark rungs read the same numbers to four decimals on that
879
+ * cell, which is why this is one pair in both schemes and lives on the shared
880
+ * default rather than in a per-scheme patch. What separates the two ANCHORS is
881
+ * the kernel and not the scheme: the reference transmits through σ 2.63 device
882
+ * px at 1x and 1.30 at 2x — invariant in neither CSS nor device pixels — where
883
+ * vitrea's runs 1.68 → 4.86, so the SHARE that comes through cannot be one
884
+ * number over a width that is two. How wide the dot ARRIVES is the material's
885
+ * own scatter law and is a recorded gap, not a fit (the dot's FWHM lands 4.99
886
+ * CSS px at 1x against the reference's 7.57, and 4.64 against 3.80 at 2x).
887
+ *
888
+ * What it costs the bed is two cells. `impulse__capsule-button` at 2x pays
889
+ * ΔE +0.00006 and `ssimMean` −0.00096 while its `ssimMin` improves by 0.068
890
+ * and its interior level closes 68 % of its gap; `impulse__rrect-md` at 1x
891
+ * improves; every other capture on both beds is byte-identical, including
892
+ * `dark-solid__capsule-button`, the collapsed stop, where a solid backdrop
893
+ * makes the target's lerp the identity by construction.
894
+ *
895
+ * The correction this constant carries is set beside W7's paragraph above, not
896
+ * over it: "texture collapse" was fitted on `dark-solid`, where a mean and a
897
+ * pixel are the same number and no fit could have told them apart. Every
898
+ * figure W7 recorded stands; what it did not measure is what happens over a
899
+ * backdrop that HAS texture, and the impulse bed says the reference keeps it.
900
+ */
901
+ collapseTransmission: 0.017,
902
+ collapseTransmission2x: 0.07,
903
+ /*
904
+ * FITTED 0.038 (W23 G1; claims §5.100 §3, W23 Decision Log 2 (b)) — and it is
905
+ * NOT the dark material's rim, which is the one thing the charter thought it
906
+ * might be.
907
+ *
908
+ * The reference's collapsed rim, read at the contour over 11 cells and 28
909
+ * sides of both beds at both scales, is +0.0189 mean (+0.0196…+0.0204 over
910
+ * `dark-solid`, +0.0149…+0.0168 over `impulse` — the spread is the backdrop,
911
+ * not noise). The dark material's OWN rim over the same backdrop, uncollapsed,
912
+ * is +0.0256…+0.0258. The two are 0.0068 apart, nine 8-bit codes at that level
913
+ * on an instrument that is exact in float and resolves 0.00067 there, so the
914
+ * collapsed rim is an absolute constant in its own units and the charter's
915
+ * conditional resolves to no.
916
+ *
917
+ * 0.038 is the minimiser over every collapsed side: the worst residual reads
918
+ * 0.0042 at 0.035, **0.0031 at 0.038**, 0.0041 at 0.040 and 0.0065 at 0.045,
919
+ * and it is the only value that leaves every untinted collapsed side inside
920
+ * the wave's clause 1 (0.005) with margin. Rendered, the collapsed sides go
921
+ * from 0.0180 to 0.0021 mean |rim − reference|.
922
+ *
923
+ * The per-row answers span 0.0317…0.0441, which under a rule that refuses a
924
+ * constant its rows do not separate (C9a §6.2) needs a stated reason: the rows
925
+ * disagree because the REFERENCE's own collapsed rim differs by backdrop —
926
+ * +0.0200 over `dark-solid` against +0.0158 over `impulse` — and not because
927
+ * the constant is unidentified on vitrea's side, where the leverage is exactly
928
+ * linear and every row reads the same slope.
929
+ *
930
+ * The collapsed BODY is read and not chased: 0.01103 native against 0.01171
931
+ * web over `dark-solid` (+1.05 codes) and 0.00664 against 0.00367 over
932
+ * `impulse` (−6.2 codes). This constant does not touch it.
933
+ */
934
+ rimCollapsed: 0.038,
935
+ /*
936
+ * REFITTED 0.337 → 0.520 (W23 G3; claims §5.102) under the painted rim's own
937
+ * composition. The reference's collapsed tint-orange capsule keeps +0.1149 of
938
+ * contour rim at 1x and +0.1179 at 2x where the bare one keeps +0.0200, and
939
+ * the drawn rim is linear in this constant, so one rendered point per scale
940
+ * gives each row its own answer.
941
+ *
942
+ * It moved because the LIGHT is now spent differently, not because the reading
943
+ * did. `rimTintChroma` spends a painted surface's rim in the paint's own
944
+ * chromaticity, and an orange paint's red channel is already at 255, so the
945
+ * share of the light that goes there is lost to the raster: at 0.337 the
946
+ * collapsed painted rim fell from +0.115 to +0.072 against a reference of
947
+ * +0.118. The constant carries what the composition costs, which is what an
948
+ * absolute constant is for.
949
+ *
950
+ * The per-side answers are 0.510 at 1x and 0.544 at 2x — the difference is the
951
+ * band, which is scale-graded and this constant is not — and 0.520 is the
952
+ * minimiser over all twelve sides, worst residual 0.0055. The three non-holdout
953
+ * cells that carry it (`dark-solid__capsule-button__rest-tint-orange` and
954
+ * `impulse__capsule-button__rest-tint-orange` on the light bed and
955
+ * `dark-solid__capsule-button__rest-tint-orange` on the dark one) answer the
956
+ * same value in both schemes, because the constant is absolute (X4).
957
+ */
958
+ rimCollapsedTinted: 0.52,
959
+ /*
960
+ * FITTED 1 (W23 G3; claims §5.102) — the rim's light on a painted surface is
961
+ * spent ENTIRELY in the paint's own chromaticity.
962
+ *
963
+ * The rows do not merely prefer it, they ask for more than the constant can be:
964
+ * over 52 tinted sides of both beds at both scales the per-side answer is
965
+ * 0.921…1.732 with a mean of 1.154, and the objective is monotone up to the
966
+ * bound. A mix weight cannot exceed 1, so 1 is both the fit and the ceiling,
967
+ * and what the rows are really saying past it is that the tinted rows' AMOUNT
968
+ * is short in the dark scheme — which is the amplitude law's residual and not
969
+ * this constant's (see below).
970
+ *
971
+ * Rendered, mean |Δ| of the contour row's OKLab against the reference's, over
972
+ * every tinted side of both beds at both scales: **b 0.0554 → 0.0093** and
973
+ * **a 0.0399 → 0.0222**, with the sides outside the wave's 0.02 falling from
974
+ * 52 of 52 to 36. The whole of the remaining 36 is `a` on the dark bed's tinted
975
+ * rows, where vitrea's rim is 0.031 against a reference of 0.127: a rim that
976
+ * dim cannot move its row's hue whatever colour it is spent in, so that
977
+ * residual is the dark law's amount and is recorded as one.
978
+ */
979
+ rimTintChroma: 1,
650
980
  /*
651
981
  * MEASURED (W9 probe, claims §5.30–§5.33): the anchors are the probe bed's
652
982
  * settled reference levels, frequency-settled over seven attested runs,
@@ -758,6 +1088,7 @@ var DEFAULT_MATERIAL_PROFILE = {
758
1088
  sizeGain: 0
759
1089
  },
760
1090
  lightDirection: [-0.3714, -0.9285],
1091
+ rimLitAxis: [-0.7071, -0.7071],
761
1092
  sweepBandRadians: 0.55,
762
1093
  glowRadiusCss: 44,
763
1094
  glowGain: 0.6,
@@ -802,6 +1133,8 @@ var BACKDROP_TONE_MAX = DEFAULT_MATERIAL_PROFILE.backdropToneMax;
802
1133
  var BACKDROP_TONE_LOW = DEFAULT_MATERIAL_PROFILE.backdropToneLow;
803
1134
  var BACKDROP_TONE_HIGH = DEFAULT_MATERIAL_PROFILE.backdropToneHigh;
804
1135
  var BACKDROP_TONE_SIZE_BIAS = DEFAULT_MATERIAL_PROFILE.backdropToneSizeBias;
1136
+ DEFAULT_MATERIAL_PROFILE.collapseTransmission;
1137
+ DEFAULT_MATERIAL_PROFILE.collapseTransmission2x;
805
1138
  DEFAULT_MATERIAL_PROFILE.backdropToneAnchorX;
806
1139
  DEFAULT_MATERIAL_PROFILE.backdropToneResponseThin;
807
1140
  DEFAULT_MATERIAL_PROFILE.backdropToneResponseThick;
@@ -854,6 +1187,11 @@ function withMaterialOverrides(base, patch) {
854
1187
  sizeScatterRampStartFar2x: patch.sizeScatterRampStartFar2x ?? base.sizeScatterRampStartFar2x,
855
1188
  sizeScatterRampReach1xPx: patch.sizeScatterRampReach1xPx ?? base.sizeScatterRampReach1xPx,
856
1189
  sizeScatterRampReach2xPx: patch.sizeScatterRampReach2xPx ?? base.sizeScatterRampReach2xPx,
1190
+ sizeScatterHeavyShareThick1x: patch.sizeScatterHeavyShareThick1x ?? base.sizeScatterHeavyShareThick1x,
1191
+ sizeScatterHeavyShareThick2x: patch.sizeScatterHeavyShareThick2x ?? base.sizeScatterHeavyShareThick2x,
1192
+ sizeToneLevelFar: patch.sizeToneLevelFar ?? base.sizeToneLevelFar,
1193
+ sizeHeavyTapSigma: patch.sizeHeavyTapSigma ?? base.sizeHeavyTapSigma,
1194
+ sizeHeavyTapSigma2x: patch.sizeHeavyTapSigma2x ?? base.sizeHeavyTapSigma2x,
857
1195
  sizeOcclusionGain: patch.sizeOcclusionGain ?? base.sizeOcclusionGain,
858
1196
  sizeShadowGainMax: patch.sizeShadowGainMax ?? base.sizeShadowGainMax,
859
1197
  lensRefractionGain: patch.lensRefractionGain ?? base.lensRefractionGain,
@@ -878,12 +1216,18 @@ function withMaterialOverrides(base, patch) {
878
1216
  backdropToneLow: patch.backdropToneLow ?? base.backdropToneLow,
879
1217
  backdropToneHigh: patch.backdropToneHigh ?? base.backdropToneHigh,
880
1218
  backdropToneSizeBias: patch.backdropToneSizeBias ?? base.backdropToneSizeBias,
1219
+ collapseTransmission: patch.collapseTransmission ?? base.collapseTransmission,
1220
+ collapseTransmission2x: patch.collapseTransmission2x ?? patch.collapseTransmission ?? base.collapseTransmission2x,
1221
+ rimCollapsed: patch.rimCollapsed ?? base.rimCollapsed,
1222
+ rimCollapsedTinted: patch.rimCollapsedTinted ?? base.rimCollapsedTinted,
1223
+ rimTintChroma: patch.rimTintChroma ?? base.rimTintChroma,
881
1224
  backdropToneAnchorX: patch.backdropToneAnchorX ?? base.backdropToneAnchorX,
882
1225
  backdropToneResponseThin: patch.backdropToneResponseThin ?? base.backdropToneResponseThin,
883
1226
  backdropToneResponseThick: patch.backdropToneResponseThick ?? base.backdropToneResponseThick,
884
1227
  backdropToneResponseStrength: patch.backdropToneResponseStrength ?? base.backdropToneResponseStrength,
885
1228
  outerShadow: { ...base.outerShadow, ...patch.outerShadow },
886
1229
  lightDirection: patch.lightDirection ?? base.lightDirection,
1230
+ rimLitAxis: patch.rimLitAxis ?? base.rimLitAxis,
887
1231
  sweepBandRadians: patch.sweepBandRadians ?? base.sweepBandRadians,
888
1232
  glowRadiusCss: patch.glowRadiusCss ?? base.glowRadiusCss,
889
1233
  glowGain: patch.glowGain ?? base.glowGain,
@@ -901,10 +1245,31 @@ function opticsUnderPolicy(optics, policy, profile = DEFAULT_MATERIAL_PROFILE) {
901
1245
  ...next,
902
1246
  tintAlpha: occlusionAlphaUnderPolicy(next.tintAlpha, policy.occlusion, profile.increasedOcclusionLift)
903
1247
  };
904
- if (policy.border === "strong")
905
- next = { ...next, ...profile.strongBorderRim };
1248
+ if (policy.border === "strong") {
1249
+ next = {
1250
+ ...next,
1251
+ rimWidth: profile.strongBorderRim.rimWidth,
1252
+ rimWidth2x: profile.strongBorderRim.rimWidth,
1253
+ rimAlpha: profile.strongBorderRim.rimAlpha,
1254
+ rimLevelGain: 0,
1255
+ // And the lit edge stands down with it (W24): a border a preference asked
1256
+ // for is one brightness the whole way round, and a directional factor
1257
+ // would take it to nothing on two of its four corners.
1258
+ rimLitExponent: 0,
1259
+ // The along-side field stands down for the same reason (W25): a border a
1260
+ // preference asked for is one brightness the whole way round, and a
1261
+ // position field would grade it corner to corner.
1262
+ rimAlongSideSlope: 0
1263
+ };
1264
+ }
906
1265
  return next;
907
1266
  }
1267
+ function collapsedRimUnderPolicy(policy, tintStrength, profile = DEFAULT_MATERIAL_PROFILE) {
1268
+ if (policy.border === "strong")
1269
+ return profile.strongBorderRim.rimAlpha;
1270
+ const strength = Math.min(1, Math.max(0, tintStrength));
1271
+ return profile.rimCollapsed + (profile.rimCollapsedTinted - profile.rimCollapsed) * strength;
1272
+ }
908
1273
  function adaptationStrength(policy, analysisExact, profile = DEFAULT_MATERIAL_PROFILE) {
909
1274
  if (!analysisExact)
910
1275
  return 0;
@@ -990,7 +1355,7 @@ var smoothstep = (edge0, edge1, x) => {
990
1355
  function sizeThickness(spanPx, profile = DEFAULT_MATERIAL_PROFILE) {
991
1356
  return smoothstep(profile.sizeSpanMin, profile.sizeSpanMax, spanPx);
992
1357
  }
993
- function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIAL_PROFILE) {
1358
+ function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIAL_PROFILE, levelFar = 0) {
994
1359
  const xs = profile.backdropToneAnchorX;
995
1360
  const f = smoothstep(0, 1, thickness);
996
1361
  const ys = [0, 1, 2].map((i) => (profile.backdropToneResponseThin[i] ?? 0) + ((profile.backdropToneResponseThick[i] ?? 0) - (profile.backdropToneResponseThin[i] ?? 0)) * f);
@@ -1007,7 +1372,7 @@ function backdropToneResponse(encodedInput, thickness, profile = DEFAULT_MATERIA
1007
1372
  const y1 = seg === 0 ? ys[1] : ys[2];
1008
1373
  const s0 = seg === 0 ? d0 : m1;
1009
1374
  const s1 = seg === 0 ? m1 : d1;
1010
- return y0 * (1 + 2 * t) * (1 - t) * (1 - t) + s0 * h * t * (1 - t) * (1 - t) + y1 * t * t * (3 - 2 * t) + s1 * h * t * t * (t - 1);
1375
+ return y0 * (1 + 2 * t) * (1 - t) * (1 - t) + s0 * h * t * (1 - t) * (1 - t) + y1 * t * t * (3 - 2 * t) + s1 * h * t * t * (t - 1) + levelFar;
1011
1376
  }
1012
1377
  function backdropToneSolveWeight(encodedInput, profile = DEFAULT_MATERIAL_PROFILE) {
1013
1378
  const anchor = profile.backdropToneAnchorX[0];
@@ -1080,6 +1445,12 @@ function rampAtScale(at1x, at2x, devicePixelRatio) {
1080
1445
  return at2x;
1081
1446
  return at1x + (at2x - at1x) * t;
1082
1447
  }
1448
+ function rimWidthAtScale(optics, devicePixelRatio = 1) {
1449
+ return rampAtScale(optics.rimWidth, optics.rimWidth2x, devicePixelRatio);
1450
+ }
1451
+ function collapseTransmissionAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
1452
+ return rampAtScale(profile.collapseTransmission, profile.collapseTransmission2x, devicePixelRatio);
1453
+ }
1083
1454
  function scatterGainAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
1084
1455
  return rampAtScale(profile.sizeScatterGainMax, profile.sizeScatterGainMax2x, devicePixelRatio);
1085
1456
  }
@@ -1101,7 +1472,25 @@ function scatterSpanMaxAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRa
1101
1472
  }
1102
1473
  function scatterDeepThickness(spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
1103
1474
  const floor = scatterFloorAtScale(profile, devicePixelRatio);
1104
- return floor + (1 - floor) * smoothstep(profile.sizeSpanMin, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx);
1475
+ const lift = scatterHeavyShareThickAtScale(profile, devicePixelRatio) * sizeThickness(spanPx, profile);
1476
+ return clampUnit(floor + (1 - floor) * smoothstep(profile.sizeSpanMin, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx) + lift);
1477
+ }
1478
+ function scatterHeavyShareThickAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
1479
+ return rampAtScale(profile.sizeScatterHeavyShareThick1x, profile.sizeScatterHeavyShareThick2x, devicePixelRatio);
1480
+ }
1481
+ function heavyTapSigmaAtScale(profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1) {
1482
+ return rampAtScale(profile.sizeHeavyTapSigma, profile.sizeHeavyTapSigma2x, devicePixelRatio);
1483
+ }
1484
+ function sizeToneLevelFar(spanPx, profile = DEFAULT_MATERIAL_PROFILE, devicePixelRatio = 1, fold = 1) {
1485
+ return profile.sizeToneLevelFar * smoothstep(profile.sizeSpanMax, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx) * fold;
1486
+ }
1487
+ function rimAlongSideField(offset, half) {
1488
+ const x = offset[0] / Math.max(Math.abs(half[0]), 1e-6);
1489
+ const y = offset[1] / Math.max(Math.abs(half[1]), 1e-6);
1490
+ return Math.max(-1, Math.min(1, x * y));
1491
+ }
1492
+ function rimAlongSideFactor(field, spanPx, optics, profile = DEFAULT_MATERIAL_PROFILE) {
1493
+ return Math.max(0, 1 + optics.rimAlongSideSlope * sizeThickness(spanPx, profile) * field);
1105
1494
  }
1106
1495
  function scatterSharpShare(uDevicePx, devicePixelRatio, profile = DEFAULT_MATERIAL_PROFILE, spanPx = 0) {
1107
1496
  const deepSharp = 1 - scatterDeepThickness(spanPx, profile, devicePixelRatio);
@@ -2105,6 +2494,9 @@ var poolKey = {
2105
2494
  backdropChainScratch: (sourceId, level) => `backdrop:${sourceId}:chain-scratch:${level}`,
2106
2495
  backdropBody: (sourceId) => `backdrop:${sourceId}:body`,
2107
2496
  backdropBodyScratch: (sourceId) => `backdrop:${sourceId}:body-scratch`,
2497
+ /** The heavy blur and its scratch (W26) — the body's pair, one width deeper. */
2498
+ backdropHeavy: (sourceId) => `backdrop:${sourceId}:heavy`,
2499
+ backdropHeavyScratch: (sourceId) => `backdrop:${sourceId}:heavy-scratch`,
2108
2500
  backdropUpload: (sourceId) => `backdrop:${sourceId}:upload`,
2109
2501
  groupField: (groupId) => `group:${groupId}:field`,
2110
2502
  groupAux: (groupId) => `group:${groupId}:aux`,
@@ -3068,7 +3460,9 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
3068
3460
  /// accessibility fold \u2014 the refraction ladder read at the preference's cap,
3069
3461
  /// which every facet's span-dependent rise is multiplied by (W11c)
3070
3462
  tone : vec4f,
3071
- /// rimWidthPx, rimAlpha, specularPower, specularGain
3463
+ /// rimWidthPx, rimAlpha; (z) and (w) carried specularPower and specularGain
3464
+ /// until W24 retired the one-sided specular from the rim (claims 5.108
3465
+ /// section 1) and are written but unread
3072
3466
  rim : vec4f,
3073
3467
  /// light direction, unit (xy), shadowDepth (z), shadowAlpha (w)
3074
3468
  light : vec4f,
@@ -3117,7 +3511,11 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
3117
3511
  /// three anchors for a surface of sizeThickness 0 (xyz); w is the law's
3118
3512
  /// per-profile authority \u2014 0 on dark profiles, whose response is unmeasured
3119
3513
  toneRowThin : vec4f,
3120
- /// the thick row (sizeThickness saturated), same layout
3514
+ /// the thick row (sizeThickness saturated), xyz as the thin row's; w is the
3515
+ /// collapse's transmission (W24 G1), in the padding slot this vec4's alignment
3516
+ /// already required \u2014 it belongs to the tone block and the tone block's other
3517
+ /// three vec4s are full. At 0 the collapse's target is the group's mean
3518
+ /// backdrop colour and this pass is W7's to the bit.
3121
3519
  toneRowThick : vec4f,
3122
3520
  /// the size law's bands: the scatter facet's floor (x, resolved at the
3123
3521
  /// group's device ratio since W15 G1 \u2014 the deep value is per-scale, claims
@@ -3158,6 +3556,30 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
3158
3556
  /// which is the only place the CSS-px-to-texel conversion is knowable, and
3159
3557
  /// already clamped to chainMaxLod (w)
3160
3558
  shadowLift : vec4f,
3559
+ /// the rim's amplitude law (W23): the gain on the surface's own rendered
3560
+ /// luminance (x), the rim the COLLAPSED appearance keeps \u2014 bare (y) and at the
3561
+ /// author tint's full coverage (z) \u2014 which rises with the adaptation the
3562
+ /// scheme's own rim falls with, and how much of an author tint's own colour
3563
+ /// the rim's light is spent in (w)
3564
+ rimLaw : vec4f,
3565
+ /// the lit edge (W24): the axis the rim's directional factor is symmetric
3566
+ /// about, unit, viewport coordinates with y down (xy), and the factor's
3567
+ /// exponent (z) \u2014 0 leaves the factor at 1 for every normal and the rim
3568
+ /// exactly as W23 left it. (w) is the along-side field's slope (W25), in the
3569
+ /// slot W24 left free \u2014 0 leaves the factor at 1 at every position.
3570
+ rimLit : vec4f,
3571
+ /// the thick-span composite (W25; claims 5.113): the heavy share's thick-end
3572
+ /// lift on 'sizeThickness', resolved at this group's device ratio (x), and the
3573
+ /// level term's gain above the thickness knee (y). Both 0 on the landed
3574
+ /// material, so both terms are one multiplication by zero. (z) and (w) free.
3575
+ thickSpan : vec4f,
3576
+ /// the heavy blur's enable (W26; 'MaterialProfile.sizeHeavyTapSigma', and the
3577
+ /// measured cause in claims 5.116 section 2) \u2014 1 where this group's source
3578
+ /// carries a heavy texture, 0 where it does not. The WIDTH is not here: the
3579
+ /// pyramid blurred it into 'backdropHeavy' before any group was drawn, so all
3580
+ /// this pass decides is which of two textures the deep sample comes from.
3581
+ /// (y) (z) (w) free.
3582
+ heavyTap : vec4f,
3161
3583
  };
3162
3584
 
3163
3585
  @group(0) @binding(0) var<uniform> ou : OpticsUniforms;
@@ -3171,6 +3593,11 @@ var WGSL_OPTICS_PASS = `struct OpticsUniforms {
3171
3593
  /// centre (xy) and its half-extents (zw), group-local CSS px \u2014 the lens's oval.
3172
3594
  @group(0) @binding(7) var aux2Texture : texture_2d<f32>;
3173
3595
 
3596
+ /// The heavy blur (W26) \u2014 the backdrop taken to the profile's heavy width by the
3597
+ /// pyramid's own separable passes, at the extent of the chain level it was built
3598
+ /// from. Bound at every draw; read only where 'heavyTap.x' says there is one.
3599
+ @group(0) @binding(8) var backdropHeavy : texture_2d<f32>;
3600
+
3174
3601
  /// One encoded sRGB channel from a linear one \u2014 the space the backdrop tone
3175
3602
  /// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.
3176
3603
  fn srgb_encode(c : f32) -> f32 {
@@ -3182,7 +3609,7 @@ fn srgb_encode(c : f32) -> f32 {
3182
3609
  /// (Fritsch\u2013Carlson) interpolation through the three anchors, clamped to their
3183
3610
  /// span; smoothstep between the thin and thick rows. Mirrors material.ts's
3184
3611
  /// 'backdropToneResponse' term for term \u2014 the constants are authored there.
3185
- fn tone_response(x : f32, sizeK : f32) -> f32 {
3612
+ fn tone_response(x : f32, sizeK : f32, levelFar : f32) -> f32 {
3186
3613
  let f = sizeK * sizeK * (3.0 - 2.0 * sizeK);
3187
3614
  let ys = mix(ou.toneRowThin.xyz, ou.toneRowThick.xyz, vec3f(f));
3188
3615
  let xs = ou.toneAnchor.xyz;
@@ -3201,10 +3628,18 @@ fn tone_response(x : f32, sizeK : f32) -> f32 {
3201
3628
  h = h1; t = (xc - xs.y) / h1;
3202
3629
  y0 = ys.y; y1 = ys.z; s0 = m1; s1 = d1;
3203
3630
  }
3631
+ // 'levelFar' is W25's level term above the thickness knee (claims 5.113; W25
3632
+ // Decision Log 3 (b)) - an OFFSET on the settled level this curve returns, in
3633
+ // its own encoded units, and not a continuation of the thin-to-thick blend
3634
+ // above. The rows chose the shape: the residual against vitrea above span 96
3635
+ // is backdrop-INDEPENDENT where the blend's direction is different at every
3636
+ // backdrop level (G2 'fit-level.txt'). Exactly 0 at and below sizeSpanMax by
3637
+ // the shape of its span curve, and 0 at every span on the landed material.
3204
3638
  return y0 * (1.0 + 2.0 * t) * (1.0 - t) * (1.0 - t)
3205
3639
  + s0 * h * t * (1.0 - t) * (1.0 - t)
3206
3640
  + y1 * t * t * (3.0 - 2.0 * t)
3207
- + s1 * h * t * t * (t - 1.0);
3641
+ + s1 * h * t * t * (t - 1.0)
3642
+ + levelFar;
3208
3643
  }
3209
3644
 
3210
3645
  /// Rim proximity: 1 exactly on the contour, falling to 0 by 'width' on either
@@ -3536,11 +3971,27 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3536
3971
  */
3537
3972
  let scatterFloor = clamp(ou.scatter.x, 0.0, 1.0);
3538
3973
  let deepT = clamp((span - ou.scatter.z) / max(ou.lensOval.w - ou.scatter.z, 1e-6), 0.0, 1.0);
3539
- let kDeep = scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT);
3974
+ // W25's share law (claims 5.113; W25 Decision Log 3 (a)): the thick end's lift
3975
+ // on the material's own thin/thick curve, ADDED to the W11c span curve rather
3976
+ // than replacing it, so the thin end keeps the constants it was fitted with and
3977
+ // 'sizeThick' being exactly 0 at sizeSpanMin makes the thin controls
3978
+ // bit-identical whatever the lift says.
3979
+ let kDeep = clamp(
3980
+ scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT)
3981
+ + ou.thickSpan.x * sizeThick,
3982
+ 0.0,
3983
+ 1.0,
3984
+ );
3540
3985
  let sDeep = 1.0 - kDeep;
3541
3986
  let rampT = max(1.0 - max(-d, 0.0) / max(ou.lensOval.z, 1e-6), 0.0);
3542
3987
  let farT = clamp((span - ou.scatter.w) / max(ou.lensOval.w - ou.scatter.w, 1e-6), 0.0, 1.0);
3543
3988
  let farS = farT * farT * (3.0 - 2.0 * farT);
3989
+ // W25's level term rides the very same curve (claims 5.113): one span
3990
+ // statistic, now read three times \u2014 the ramp's far decline, the 2x heavy
3991
+ // gain's rise and the body's level above the knee. Folded like the response it
3992
+ // extends, because a preference that has stopped the material transmitting has
3993
+ // no thin-to-thick step left to continue.
3994
+ let toneLevelFar = ou.thickSpan.y * farS * fold;
3544
3995
  let rampStart = ou.scatter.y + (ou.shadowSize.z - ou.scatter.y) * sizeThick
3545
3996
  + (ou.shadowThick.w - ou.shadowSize.z) * farS;
3546
3997
  let sharpShare = clamp(sDeep + max(rampStart - sDeep, 0.0) * rampT, 0.0, 1.0);
@@ -3608,6 +4059,14 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3608
4059
  // along 'farS' \u2014 the very smoothstep the ramp's far anchor already declines
3609
4060
  // along, computed above with the share. One curve, two quantities.
3610
4061
  let gainEff = ou.size.x + (ou.shadowSize.w - ou.size.x) * farS;
4062
+ /*
4063
+ * Everything above this point grades the GAIN, and claims \xA75.116 \xA72 measured
4064
+ * that the gain stops being a width: 'ou.lens.w' is the chain's own last level,
4065
+ * 4 on the bed's 320 \xD7 200 backdrop, and 'ou.size.w + log2(8)' is 4.06, so the
4066
+ * clamp has been absorbing the gain since the material was fitted. This is the
4067
+ * path a material that names no heavy width still takes, and the heavy blur
4068
+ * below is what replaces it where one is named.
4069
+ */
3611
4070
  let scatterLod = clamp(ou.size.w + log2(max(gainEff, 1e-4)), 0.0, ou.lens.w);
3612
4071
 
3613
4072
  var backdrop = vec3f(0.0);
@@ -3615,7 +4074,32 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3615
4074
  // Both components at the refracted position (W11c G2): the band and the
3616
4075
  // interior are one body, and the displacement alone is the lens.
3617
4076
  let bodySample = textureSampleLevel(backdropBody, backdropSampler, refractedUv, 0.0);
3618
- let scatterSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, scatterLod);
4077
+ var scatterSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, scatterLod);
4078
+ /*
4079
+ * The heavy blur (W26). Where the profile named a heavy width the deep sample
4080
+ * is not a chain level at all: the pyramid took the chain level whose own
4081
+ * blur is nearest below the target up to the target exactly, with the two
4082
+ * separable passes it already runs for the body, and this pass reads the
4083
+ * result at the same refracted uv the chain tap used.
4084
+ *
4085
+ * That is the whole mechanism, and it is here rather than in a grid of taps
4086
+ * for two measured reasons. The width the chain can reach is bounded by
4087
+ * 'chainMaxLod' \u2014 the pyramid stops when a level's shorter side would fall
4088
+ * under eight texels \u2014 so at dpr 1 on a 320 x 200 backdrop the deep sample
4089
+ * saturates at 13.4 device px against the reference's 19.5, and a residual
4090
+ * Gaussian is the only thing that carries the octave the chain does not have
4091
+ * (claims \xA75.119). And a 9 x 9 grid at the tap costs +1.1 ms on the optics
4092
+ * pass against 0.070 ms for the separable pair (W26 Decision Log 2 (b)).
4093
+ *
4094
+ * The price is that the width is one per SOURCE, not one per pixel: the
4095
+ * texture is built before any group is drawn, so the span grading the gain
4096
+ * carried above no longer reaches the deep sample where this is on. The
4097
+ * reference's heavy width does not grade with the span at 1x (claims
4098
+ * \xA75.113 \xA74), which is what says the material can afford it.
4099
+ */
4100
+ if (ou.heavyTap.x > 0.5) {
4101
+ scatterSample = textureSampleLevel(backdropHeavy, backdropSampler, refractedUv, 0.0);
4102
+ }
3619
4103
  // Premultiplied linear in, straight colour out: the material composites over
3620
4104
  // whatever is behind it, so a partially transparent backdrop must not darken
3621
4105
  // the glass.
@@ -3711,7 +4195,7 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3711
4195
  let authority =
3712
4196
  smoothstep(anchor * 0.5, anchor, encodedInput) * clamp(ou.toneRowThin.w, 0.0, 1.0);
3713
4197
  if (authority > 0.0) {
3714
- let response = tone_response(encodedInput, sizeK);
4198
+ let response = tone_response(encodedInput, sizeK, toneLevelFar);
3715
4199
  // The collapse's mean pull is toward L(toneColour.rgb) \u2014 the LINEAR
3716
4200
  // mean, which toneAnchor.w carries \u2014 not toward the encoded level.
3717
4201
  let preCollapse = (response - toneAdapt * ou.toneAnchor.w) / (1.0 - toneAdapt);
@@ -3742,11 +4226,44 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3742
4226
  }
3743
4227
  }
3744
4228
 
4229
+ /*
4230
+ * The collapse's TARGET (W24 G1) \u2014 what the material converges on where it has
4231
+ * adapted, and the one place the transmission was lost.
4232
+ *
4233
+ * The pair below reduces exactly to 'colour = (1 \u2212 k)\xB7M + k\xB7target', with 'M'
4234
+ * the unadapted composite '(1 \u2212 \u03B1)\xB7backdrop + \u03B1\xB7neutral'. At 'target' =
4235
+ * 'toneColour.rgb', the group's MEAN backdrop colour, a fully collapsed
4236
+ * surface is one flat number and nothing under it comes through \u2014 which is
4237
+ * exactly what the reference's collapsed capsule over the impulse grid does
4238
+ * NOT do (claims \xA75.107 \xA72: it passes the centre dot at four times its own
4239
+ * body). So the target lerps toward the per-pixel blurred backdrop the
4240
+ * refraction path above already sampled, by the profile's own constant.
4241
+ *
4242
+ * Only the target moves. The tone axis's argument is still the group's mean
4243
+ * luminance and the response solve still composites against 'toneAnchor.w',
4244
+ * so 'k' and the law's level are the numbers W7 and W9 fitted: the collapse
4245
+ * still collapses the level, and stops flattening the structure.
4246
+ *
4247
+ * The alpha solve above needs no gate of its own, and this is arithmetic
4248
+ * rather than a choice: on a fully collapsed surface it never runs (its own
4249
+ * 'toneAdapt < 0.995' stands it down where the collapse owns the pixel), and
4250
+ * below that it is the (1 \u2212 k) half of the same lerp, which transmits already.
4251
+ *
4252
+ * Gated on 'flags.x': with no pyramid to sample 'backdrop' is the zero vector
4253
+ * and this pass writes a layer for the browser to composite, so a target
4254
+ * lerped toward it would be a black surface rather than a transmitting one.
4255
+ * There the CSS tier's own 'backdrop-filter' is what carries the transmission.
4256
+ */
4257
+ var toneTarget = ou.toneColour.rgb;
4258
+ if (ou.flags.x > 0.5) {
4259
+ toneTarget = mix(toneTarget, backdrop, clamp(ou.toneRowThick.w, 0.0, 1.0));
4260
+ }
4261
+
3745
4262
  let adaptedAlpha = solvedAlpha + toneAdapt * (1.0 - solvedAlpha);
3746
4263
  var adapted = solvedNeutral;
3747
4264
  if (toneAdapt > 0.0 && adaptedAlpha > 0.0) {
3748
4265
  adapted =
3749
- (solvedNeutral * ((1.0 - toneAdapt) * solvedAlpha) + ou.toneColour.rgb * toneAdapt) /
4266
+ (solvedNeutral * ((1.0 - toneAdapt) * solvedAlpha) + toneTarget * toneAdapt) /
3750
4267
  adaptedAlpha;
3751
4268
  }
3752
4269
 
@@ -3804,6 +4321,45 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3804
4321
  // seed); and '1 \u2212 toneAdapt' folds the shade out where the collapse has made
3805
4322
  // the material a dark body, where the reference renders the pure seed too.
3806
4323
  // At zero grip the layer is the bare seed \u2014 the author's colour, flat.
4324
+ /*
4325
+ * The material's own composite, kept beside the tinted one (W23; claims \xA75.100
4326
+ * \xA75). The rim is the MATERIAL's mark and the author's colour is painted over
4327
+ * it, so the amplitude law below reads the level the material reached and not
4328
+ * the level the paint left \u2014 which is what the reference does: its tinted rows
4329
+ * read +0.13\u2026+0.17 of contour rim in BOTH colour schemes, where the two
4330
+ * materials' own laws on the PAINTED level differ by a factor of five and land
4331
+ * the dark bed's tinted rows 0.216 over.
4332
+ *
4333
+ * For an untinted pixel these carry exactly 'colour' and 'bodyAlpha', so the
4334
+ * rim below is bit-identical to the law without them.
4335
+ */
4336
+ var materialColour = colour;
4337
+ var materialAlpha = bodyAlpha;
4338
+ /*
4339
+ * The colour the rim's light is spent in (W23 G3; claims \xA75.102). White on a
4340
+ * bare surface, and on a PAINTED one the author's own CHROMATICITY: the
4341
+ * reference's rim on a tinted capsule is the paint lifted rather than white
4342
+ * added over it \u2014 orange (255, 148, 0) rises to (254, 188, 0) with its blue
4343
+ * channel still at 0, where vitrea drew (255, 192, 130).
4344
+ *
4345
+ * The layer is normalised by its own LUMINANCE and not by its brightest
4346
+ * channel, which is what the rows chose: on the collapsed orange capsule at 2x
4347
+ * the reference lifts the green channel by 0.213 of linear light where a white
4348
+ * rim of the same amount lifts it by 0.304, and 0.213 / 0.304 = 0.70 is exactly
4349
+ * the green coefficient of that orange divided by its luminance. Normalising by
4350
+ * the brightest channel instead reproduces the hue and loses the AMOUNT \u2014 it
4351
+ * divides the rim's luminance by the paint's, which on the same cell took the
4352
+ * contour rim from 0.115 to 0.030 against a reference of 0.118. Chromaticity is
4353
+ * unbounded as a paint darkens, so the divisor has a floor of 0.05: below that
4354
+ * the paint has no readable hue and the normalisation would be a colour cast of
4355
+ * arbitrary size rather than a rim.
4356
+ *
4357
+ * 'rimTintChroma' (rimLaw.w) is how much of that is taken, and it is
4358
+ * multiplied by the pixel's own tint strength, so an UNTINTED pixel keeps a
4359
+ * white rim at every value of the constant \u2014 which is what makes the mechanism
4360
+ * reach painted pixels only (W23 S10).
4361
+ */
4362
+ var rimTintColour = vec3f(1.0);
3807
4363
  if (aux.w > 0.0) {
3808
4364
  // The untinted material's luminance at this pixel. Over a backdrop that is
3809
4365
  // the composite; as a layer it is the layer over the tone the host measured
@@ -3814,6 +4370,8 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3814
4370
  let shade = mix(1.0, clamp(mix(ou.tone.x, ou.tone.y, clamp(u, 0.0, 1.0)), 0.0, 1.0), grip);
3815
4371
  let layer = ou.seed.rgb * shade;
3816
4372
  let s = clamp(aux.w, 0.0, 1.0);
4373
+ let layerLuma = max(dot(layer, vec3f(0.2126, 0.7152, 0.0722)), 0.05);
4374
+ rimTintColour = mix(vec3f(1.0), layer / layerLuma, clamp(ou.rimLaw.w, 0.0, 1.0) * s);
3817
4375
  let encodedMaterial = linear_to_srgb(clamp(colour, vec3f(0.0), vec3f(1.0)));
3818
4376
  let encodedLayer = linear_to_srgb(layer);
3819
4377
  if (ou.flags.x > 0.5) {
@@ -3858,15 +4416,118 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3858
4416
  let shadowedAlpha = 1.0 - shadowKeep * (1.0 - bodyAlpha);
3859
4417
  colour = colour * (shadowKeep * bodyAlpha / max(shadowedAlpha, 1e-6));
3860
4418
  bodyAlpha = shadowedAlpha;
4419
+ // The same occlusion on the material's own composite, so that the rim's law
4420
+ // reads a level the inner shadow has reached exactly as it always did.
4421
+ let materialShadowedAlpha = 1.0 - shadowKeep * (1.0 - materialAlpha);
4422
+ materialColour = materialColour * (shadowKeep * materialAlpha / max(materialShadowedAlpha, 1e-6));
4423
+ materialAlpha = materialShadowedAlpha;
3861
4424
 
3862
- // Rim and specular from the gradient. The rim is unlit ambient edge brightness;
3863
- // the specular term is the same edge lit from 'light.xy'.
4425
+ /*
4426
+ * The rim from the gradient. Its amplitude law is below and the direction it
4427
+ * is LIT from is the factor after it.
4428
+ *
4429
+ * The one-sided specular that used to be added here \u2014 'pow(clamp(dot(normal,
4430
+ * light.xy), 0, 1), rim.z) * rim.w' \u2014 is retired (W24; claims \xA75.108 \xA71). Read
4431
+ * around the whole contour the reference's rim is symmetric about the diagonal
4432
+ * rather than one-sided, and a term that can only reach one end of it fits at
4433
+ * 0.288 of normalised RMS where the symmetric factor fits at 0.148. 'rim.z'
4434
+ * and 'rim.w' are written by the pass and no longer read.
4435
+ */
3864
4436
  let rw = rim_weight(d, ou.rim.x);
3865
- let facing = dot(normal, ou.light.xy);
3866
- let spec = pow(clamp(facing, 0.0, 1.0), max(ou.rim.z, 1e-3)) * ou.rim.w;
3867
- let rim = rw * (ou.rim.y + spec) * present;
4437
+ /*
4438
+ * The rim's amplitude law, and the rim that survives the collapse (W23;
4439
+ * claims \xA75.100 \xA7\xA73-4).
4440
+ *
4441
+ * - The amplitude is affine in the MATERIAL's own rendered luminance, taken
4442
+ * exactly as the tint shade takes it above \u2014 the composite where this layer
4443
+ * covers the pixel, the group's measured backdrop tone where it does not,
4444
+ * and in both cases before the author's colour is painted over it \u2014
4445
+ * so that a rim fitted as 'a fraction of the body's headroom' (a negative
4446
+ * gain, the screen form the CSS tier's inset shadow already is) and a rim
4447
+ * fitted as 'a line that rides its own body up' (a positive one, which is
4448
+ * what the dark reference's rows read as) are the same expression with the
4449
+ * sign the rows chose. The environment term the wave chartered beside it is
4450
+ * not here: it is worse than this law on the reference in both schemes and
4451
+ * no row of either bed separates it, so it is not carried (C9a \xA76.2).
4452
+ * - 'rimCollapsed' rises with 'toneAdapt' exactly as the rest of the
4453
+ * appearance falls with it. At toneAdapt 1 the surface draws its backdrop
4454
+ * with this rim and nothing else, which is what the reference's collapsed
4455
+ * capsule does; at 0 it contributes nothing at all.
4456
+ * The collapsed rim it rises to is the AUTHOR TINT's coverage lerped between
4457
+ * two absolute constants: the reference's collapsed capsule keeps +0.020 of
4458
+ * contour rim bare and +0.115 painted, and both are absolutes rather than
4459
+ * fractions of the appearance's own rim, because the reference draws one
4460
+ * collapsed appearance out of two materials whose amplitude laws differ by
4461
+ * 1.8\xD7 (claims \xA75.100 \xA75). 'aux.w' is the same per-pixel tint strength the
4462
+ * author tint layer composites with sixty lines above.
4463
+ */
4464
+ let rimLuma = materialAlpha * dot(materialColour, vec3f(0.2126, 0.7152, 0.0722))
4465
+ + (1.0 - materialAlpha) * ou.toneColour.w;
4466
+ let rimAmplitude = ou.rim.y + ou.rimLaw.x * rimLuma;
4467
+ let rimCollapsed = mix(ou.rimLaw.y, ou.rimLaw.z, clamp(aux.w, 0.0, 1.0));
4468
+ /*
4469
+ * The lit edge (W24; claims \xA75.107) \u2014 the directional factor the whole rim is
4470
+ * multiplied by, symmetric about 'rimLit.xy'.
4471
+ *
4472
+ * Apple's rim is not one number around the contour. Read at 720 or more points
4473
+ * of the declared boundary and binned by the NORMAL's angle, the reference's
4474
+ * north-west and south-east bins are five to twenty-five times its north-east
4475
+ * and south-west ones on every untinted solid cell of both beds, while every
4476
+ * per-side reader in three waves read it flat \u2014 a light on the diagonal
4477
+ * projects equally on all four straight sides. This is the shape of that.
4478
+ *
4479
+ * '1.4142135' is the amplitude's re-expression and not a scale: it normalises
4480
+ * the dot product by 'cos 45 deg', so at the default axis the factor is exactly
4481
+ * 1 wherever the normal is horizontal or vertical, at EVERY exponent. W23
4482
+ * fitted 'rimAlpha' and 'rimLevelGain' on those straight spans, so they keep
4483
+ * their meaning untouched and only the corners and the arcs move \u2014 which is
4484
+ * also why the CSS tier, whose one inset layer cannot vary around a contour,
4485
+ * needs no counterpart and no re-fit.
4486
+ *
4487
+ * The factor multiplies the COLLAPSED rim as well as the appearance's own. That
4488
+ * is a measurement and not a symmetry: the reference's collapsed cells \u2014 the
4489
+ * 'dark-solid' capsule at both scales and the probe grids' 'dark-solid'
4490
+ * rrect-sm and rrect-lg \u2014 fit the same axis (136.0 deg) and the same exponent
4491
+ * (1.15 against 1.00) as the uncollapsed rows, so one factor outside the
4492
+ * bracket is what the rows say and two constants would be one more than they
4493
+ * separate.
4494
+ *
4495
+ * The floor is 1e-6 and not 0 so that 'pow' is defined where the normal is
4496
+ * exactly perpendicular to the axis; at exponent 0 it returns 1 there as it
4497
+ * does everywhere else, which is what makes this term inert at the defaults.
4498
+ */
4499
+ let lit = pow(max(abs(dot(normal, ou.rimLit.xy)) * 1.4142135, 1e-6), ou.rimLit.z);
4500
+ /*
4501
+ * The along-side field (W25; claims 5.113, W25 Decision Log 3 (c)) \u2014 the
4502
+ * POSITION half of the light whose direction half W24 landed.
4503
+ *
4504
+ * W24's factor is a function of the normal, so it is one number on a whole
4505
+ * straight side. Read by position along the side instead, on flat solid
4506
+ * backdrops where a lens has no gradient to refract, the reference's rim is
4507
+ * graded on every thick cell of both probe grids and flat at spans 32 and 44 \u2014
4508
+ * a term on the thickness curve. Its four slopes are equal and OPPOSITE across
4509
+ * opposite sides, which a field linear in position cannot be and the product of
4510
+ * the two normalised coordinates is exactly: +1 at the top-left and
4511
+ * bottom-right corners, -1 at the other two, the same diagonal 'rimLit.xy' is
4512
+ * symmetric about.
4513
+ *
4514
+ * 'aux2.xy' is the pixel's offset from its own surface's centre in CSS px and
4515
+ * 'aux2.zw' its half-extents, so the field is the surface's own coordinate and
4516
+ * a container of differently sized members grades each of them by its own box
4517
+ * out of one pass. The field's mean over any straight side is exactly zero, so
4518
+ * W23's and W24's straight-span amplitudes keep the meaning they were fitted
4519
+ * with and the CSS tier's single inset needs no counterpart.
4520
+ *
4521
+ * 'sizeThick' is the unfolded thickness curve, exactly 0 at sizeSpanMin, so
4522
+ * rrect-sm and every thinner control are untouched by construction; at slope 0
4523
+ * the factor is exactly 1 everywhere.
4524
+ */
4525
+ let alongSide = clamp((rel.x / halfExt.x) * (rel.y / halfExt.y), -1.0, 1.0);
4526
+ let alongFactor = max(1.0 + ou.rimLit.w * sizeThick * alongSide, 0.0);
4527
+ let rim = rw * lit * alongFactor * (rimAmplitude * present + rimCollapsed * toneAdapt);
4528
+ let rimLight = rim * rimTintColour;
3868
4529
  if (ou.flags.x > 0.5) {
3869
- colour = colour + vec3f(rim);
4530
+ colour = colour + rimLight;
3870
4531
  } else {
3871
4532
  // Added light has no premultiplied form of its own \u2014 a canvas colour may
3872
4533
  // not exceed its alpha \u2014 so the layer carries the light in its opacity:
@@ -3877,8 +4538,11 @@ fn fs_optics(in : FullscreenOut) -> @location(0) vec4f {
3877
4538
  // shows through \u2014 where the mix form ("white over the layer at the rim's
3878
4539
  // weight") is short by the rim times the whole composite, which halved
3879
4540
  // the rim on a tinted panel.
4541
+ // The alpha the rim carries is its LIGHT and not its colour: a coloured rim
4542
+ // spends the same light through a narrower set of channels, so the layer's
4543
+ // opacity is still 'rim' and only the colour it carries is tinted.
3880
4544
  let carried = clamp(bodyAlpha + rim, 0.0, 1.0);
3881
- colour = min((colour * bodyAlpha + vec3f(rim)) / max(carried, 1e-6), vec3f(1.0));
4545
+ colour = min((colour * bodyAlpha + rimLight) / max(carried, 1e-6), vec3f(1.0));
3882
4546
  bodyAlpha = carried;
3883
4547
  }
3884
4548
 
@@ -4160,7 +4824,7 @@ function createPassRunner(context) {
4160
4824
  };
4161
4825
  },
4162
4826
  opticsPass(encoder, args) {
4163
- const slot = uniformSlot(`optics:${args.groupId}`, 96);
4827
+ const slot = uniformSlot(`optics:${args.groupId}`, 112);
4164
4828
  const d = slot.data;
4165
4829
  d[0] = args.viewportDevice[0];
4166
4830
  d[1] = args.viewportDevice[1];
@@ -4233,7 +4897,7 @@ function createPassRunner(context) {
4233
4897
  d[68] = args.backdropToneResponseThick[0];
4234
4898
  d[69] = args.backdropToneResponseThick[1];
4235
4899
  d[70] = args.backdropToneResponseThick[2];
4236
- d[71] = 0;
4900
+ d[71] = args.collapseTransmission;
4237
4901
  d[72] = args.sizeScatterFloor;
4238
4902
  d[73] = args.sizeScatterRampStartThin;
4239
4903
  d[74] = args.sizeSpanMin;
@@ -4258,9 +4922,26 @@ function createPassRunner(context) {
4258
4922
  d[93] = args.outerShadowLift[1];
4259
4923
  d[94] = args.outerShadowLift[2];
4260
4924
  d[95] = args.outerShadowLift[3];
4925
+ d[96] = args.rimLevelGain;
4926
+ d[97] = args.rimCollapsed;
4927
+ d[98] = args.rimCollapsedTinted;
4928
+ d[99] = args.rimTintChroma;
4929
+ d[100] = args.rimLitAxis[0];
4930
+ d[101] = args.rimLitAxis[1];
4931
+ d[102] = args.rimLitExponent;
4932
+ d[103] = args.rimAlongSideSlope;
4933
+ d[104] = args.sizeScatterHeavyShareThick;
4934
+ d[105] = args.sizeToneLevelFar;
4935
+ d[106] = 0;
4936
+ d[107] = 0;
4937
+ d[108] = args.heavyTapEnabled ? 1 : 0;
4938
+ d[109] = 0;
4939
+ d[110] = 0;
4940
+ d[111] = 0;
4261
4941
  slot.write();
4262
4942
  const chain = args.backdrop?.chain ?? placeholderView;
4263
4943
  const body = args.backdrop?.body ?? placeholderView;
4944
+ const heavy = args.backdrop?.heavy ?? placeholderView;
4264
4945
  const pipeline = opticsPipeline(args.targetFormat);
4265
4946
  const pass = encoder.beginRenderPass({
4266
4947
  label: `vitrea:pass:optics:${args.groupId}`,
@@ -4281,7 +4962,8 @@ function createPassRunner(context) {
4281
4962
  // Linear, no mips: the field targets have one level, and this is only
4282
4963
  // read at all when the governor shrank them below the group's rect.
4283
4964
  { binding: 6, resource: context.flatSampler },
4284
- { binding: 7, resource: args.fields.aux2.createView() }
4965
+ { binding: 7, resource: args.fields.aux2.createView() },
4966
+ { binding: 8, resource: heavy }
4285
4967
  ]
4286
4968
  }));
4287
4969
  pass.draw(3);
@@ -4455,6 +5137,29 @@ function bodyBlurPlan(sigmaPx, plan) {
4455
5137
  const residualLevel0 = Math.sqrt(Math.max(sigmaPx * sigmaPx - covered * covered, 0));
4456
5138
  return { level, residualSigmaTexels: residualLevel0 / Math.pow(2, level) };
4457
5139
  }
5140
+ var CHAIN_LEVEL_SIGMA = [0, 1.542, 3.281, 6.679, 13.418, 26.867];
5141
+ function chainLevelSigma(level) {
5142
+ if (level <= 0)
5143
+ return 0;
5144
+ if (level < CHAIN_LEVEL_SIGMA.length)
5145
+ return CHAIN_LEVEL_SIGMA[level];
5146
+ const last = CHAIN_LEVEL_SIGMA[CHAIN_LEVEL_SIGMA.length - 1];
5147
+ return last * Math.pow(2, level - (CHAIN_LEVEL_SIGMA.length - 1));
5148
+ }
5149
+ function heavyTapPlan(sigmaTexels, plan) {
5150
+ let level = 0;
5151
+ if (sigmaTexels > 0) {
5152
+ for (let i = 1; i < plan.levelCount; i += 1) {
5153
+ if (chainLevelSigma(i) > sigmaTexels)
5154
+ break;
5155
+ level = i;
5156
+ }
5157
+ }
5158
+ const scale = Math.pow(2, level);
5159
+ const covered = chainLevelSigma(level);
5160
+ const residual = Math.sqrt(Math.max(sigmaTexels * sigmaTexels - covered * covered, 0)) / scale;
5161
+ return { level, residualSigmaTexels: residual };
5162
+ }
4458
5163
 
4459
5164
  // ../renderer-webgpu/dist/rebuild-ledger.js
4460
5165
  function createRebuildLedger() {
@@ -4511,7 +5216,8 @@ function createRebuildLedger() {
4511
5216
  var chainUsage = () => GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;
4512
5217
  var densityOf = (source, request) => texelsPerCssPx(source.width, source.height, request.placement, request.viewportCss[0], request.viewportCss[1]);
4513
5218
  var same = (next, existing) => Math.abs(next - existing) <= 1e-6 * Math.max(1, Math.abs(existing));
4514
- var sameBody = (existing, request) => same(densityOf({ width: existing.sourceWidth, height: existing.sourceHeight }, request), existing.texelsPerCss) && same(request.bodySigmaCss, existing.bodySigmaCss);
5219
+ var sameHeavySigma = (next, existing) => next > 0 === existing > 0 && same(next, existing);
5220
+ var sameBody = (existing, request) => same(densityOf({ width: existing.sourceWidth, height: existing.sourceHeight }, request), existing.texelsPerCss) && same(request.bodySigmaCss, existing.bodySigmaCss) && sameHeavySigma(request.heavySigmaCss, existing.heavySigmaCss);
4515
5221
  function createPyramidStore(context) {
4516
5222
  const { device, pool, cache } = context;
4517
5223
  const resources = /* @__PURE__ */ new Map();
@@ -4584,13 +5290,17 @@ function createPyramidStore(context) {
4584
5290
  return void 0;
4585
5291
  if (pool.peek(poolKey.backdropBody(sourceId)) !== target.body)
4586
5292
  return void 0;
5293
+ if (target.heavy !== void 0 && pool.peek(poolKey.backdropHeavy(sourceId)) !== target.heavy) {
5294
+ return void 0;
5295
+ }
4587
5296
  return target;
4588
5297
  };
4589
5298
  const mipView = (texture, level) => texture.createView({ baseMipLevel: level, mipLevelCount: 1, dimension: "2d" });
4590
- function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density, bodySigmaCss) {
5299
+ function allocate(sourceId, plan, bodyLevel, sizeEpoch, builtEpoch, bodySigmaTexels, density, bodySigmaCss, heavyLevel, heavySigmaCss) {
4591
5300
  const existing = resources.get(sourceId);
4592
- const bodyWidth = (plan.levels[bodyLevel] ?? plan.levels[0]).width;
4593
- const bodyHeight = (plan.levels[bodyLevel] ?? plan.levels[0]).height;
5301
+ const levelSize = (level) => plan.levels[level] ?? plan.levels[0];
5302
+ const bodyWidth = levelSize(bodyLevel).width;
5303
+ const bodyHeight = levelSize(bodyLevel).height;
4594
5304
  const chain = pool.acquire(poolKey.backdropChain(sourceId), {
4595
5305
  width: plan.width,
4596
5306
  height: plan.height,
@@ -4606,6 +5316,19 @@ function createPyramidStore(context) {
4606
5316
  usage: chainUsage(),
4607
5317
  label: `vitrea:pyramid:${sourceId}:body`
4608
5318
  });
5319
+ let heavy;
5320
+ if (heavyLevel === void 0) {
5321
+ pool.release(poolKey.backdropHeavy(sourceId));
5322
+ pool.release(poolKey.backdropHeavyScratch(sourceId));
5323
+ } else {
5324
+ heavy = pool.acquire(poolKey.backdropHeavy(sourceId), {
5325
+ width: levelSize(heavyLevel).width,
5326
+ height: levelSize(heavyLevel).height,
5327
+ format: WORKING_TEXTURE_FORMAT,
5328
+ usage: chainUsage(),
5329
+ label: `vitrea:pyramid:${sourceId}:heavy`
5330
+ });
5331
+ }
4609
5332
  let stats = existing?.stats;
4610
5333
  if (stats === void 0) {
4611
5334
  stats = device.createBuffer({
@@ -4614,7 +5337,7 @@ function createPyramidStore(context) {
4614
5337
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
4615
5338
  });
4616
5339
  }
4617
- if (existing === void 0 || existing.chain !== chain || existing.body !== body) {
5340
+ if (existing === void 0 || existing.chain !== chain || existing.body !== body || existing.heavy !== heavy) {
4618
5341
  reallocations += 1;
4619
5342
  }
4620
5343
  const next = {
@@ -4622,6 +5345,7 @@ function createPyramidStore(context) {
4622
5345
  plan,
4623
5346
  chain,
4624
5347
  body,
5348
+ heavy,
4625
5349
  stats,
4626
5350
  sizeEpoch,
4627
5351
  builtEpoch,
@@ -4629,7 +5353,8 @@ function createPyramidStore(context) {
4629
5353
  texelsPerCss: density.texelsPerCss,
4630
5354
  sourceWidth: density.sourceWidth,
4631
5355
  sourceHeight: density.sourceHeight,
4632
- bodySigmaCss
5356
+ bodySigmaCss,
5357
+ heavySigmaCss
4633
5358
  };
4634
5359
  resources.set(sourceId, next);
4635
5360
  return next;
@@ -4710,22 +5435,23 @@ function createPyramidStore(context) {
4710
5435
  pass.end();
4711
5436
  }
4712
5437
  }
4713
- function runBodyBlur(encoder, sourceId, plan, chain, body, level, residualSigmaTexels) {
5438
+ function runSeparableBlur(encoder, sourceId, kind, plan, chain, target, level, residualSigmaTexels) {
4714
5439
  const pipeline = chainPipeline("fs_blur");
4715
5440
  const size = plan.levels[level] ?? plan.levels[0];
4716
- const scratch = pool.acquire(poolKey.backdropBodyScratch(sourceId), {
5441
+ const scratchKey = kind === "body" ? poolKey.backdropBodyScratch(sourceId) : poolKey.backdropHeavyScratch(sourceId);
5442
+ const scratch = pool.acquire(scratchKey, {
4717
5443
  width: size.width,
4718
5444
  height: size.height,
4719
5445
  format: WORKING_TEXTURE_FORMAT,
4720
5446
  usage: chainUsage(),
4721
- label: `vitrea:pyramid:${sourceId}:body-scratch`
5447
+ label: `vitrea:pyramid:${sourceId}:${kind}-scratch`
4722
5448
  });
4723
5449
  const stages = [
4724
5450
  { target: scratch, source: mipView(chain, level), dir: [1, 0], tag: "h" },
4725
- { target: body, source: scratch.createView(), dir: [0, 1], tag: "v" }
5451
+ { target, source: scratch.createView(), dir: [0, 1], tag: "v" }
4726
5452
  ];
4727
5453
  for (const stage of stages) {
4728
- const slot = uniformSlot(`body:${sourceId}:${stage.tag}`, 8);
5454
+ const slot = uniformSlot(`${kind}:${sourceId}:${stage.tag}`, 8);
4729
5455
  slot.data[0] = 1 / size.width;
4730
5456
  slot.data[1] = 1 / size.height;
4731
5457
  slot.data[2] = 0;
@@ -4736,7 +5462,7 @@ function createPyramidStore(context) {
4736
5462
  slot.data[7] = 0;
4737
5463
  slot.write();
4738
5464
  const pass = encoder.beginRenderPass({
4739
- label: `vitrea:pass:body-blur-${stage.tag}:${sourceId}`,
5465
+ label: `vitrea:pass:${kind}-blur-${stage.tag}:${sourceId}`,
4740
5466
  ...timedRender(PASS_LABEL.bodyBlur),
4741
5467
  colorAttachments: [
4742
5468
  { view: stage.target.createView(), loadOp: "clear", storeOp: "store", clearValue: { r: 0, g: 0, b: 0, a: 0 } }
@@ -4839,10 +5565,14 @@ function createPyramidStore(context) {
4839
5565
  const planScale = frame.width > 0 ? plan.width / frame.width : 1;
4840
5566
  const bodySigmaTexels = request.bodySigmaCss * texelsPerCss * planScale;
4841
5567
  const bodyPlan = bodyBlurPlan(bodySigmaTexels, plan);
4842
- const target = allocate(request.sourceId, plan, bodyPlan.level, frame.sizeEpoch, request.epoch, bodySigmaTexels, { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height }, request.bodySigmaCss);
5568
+ const heavyPlan = request.heavySigmaCss > 0 ? heavyTapPlan(request.heavySigmaCss * texelsPerCss * planScale, plan) : void 0;
5569
+ const target = allocate(request.sourceId, plan, bodyPlan.level, frame.sizeEpoch, request.epoch, bodySigmaTexels, { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height }, request.bodySigmaCss, heavyPlan?.level, request.heavySigmaCss);
4843
5570
  runImport(encoder, request.sourceId, frame, target.chain);
4844
5571
  runChain(encoder, request.sourceId, plan, target.chain);
4845
- runBodyBlur(encoder, request.sourceId, plan, target.chain, target.body, bodyPlan.level, bodyPlan.residualSigmaTexels);
5572
+ runSeparableBlur(encoder, request.sourceId, "body", plan, target.chain, target.body, bodyPlan.level, bodyPlan.residualSigmaTexels);
5573
+ if (heavyPlan !== void 0 && target.heavy !== void 0) {
5574
+ runSeparableBlur(encoder, request.sourceId, "heavy", plan, target.chain, target.heavy, heavyPlan.level, heavyPlan.residualSigmaTexels);
5575
+ }
4846
5576
  runAnalysis(encoder, request.sourceId, plan, target.chain, target.stats);
4847
5577
  provider.markImported();
4848
5578
  return { status: "built", resources: target };
@@ -4920,6 +5650,8 @@ function createPyramidStore(context) {
4920
5650
  pool.release(poolKey.backdropChain(sourceId));
4921
5651
  pool.release(poolKey.backdropBody(sourceId));
4922
5652
  pool.release(poolKey.backdropBodyScratch(sourceId));
5653
+ pool.release(poolKey.backdropHeavy(sourceId));
5654
+ pool.release(poolKey.backdropHeavyScratch(sourceId));
4923
5655
  resources.get(sourceId)?.stats.destroy();
4924
5656
  resources.delete(sourceId);
4925
5657
  readbacks.get(sourceId)?.staging.destroy();
@@ -5072,7 +5804,8 @@ function createWebGPURenderer(options = {}) {
5072
5804
  const sameDensity = Math.abs(next - existing.texelsPerCss) <= 1e-6 * Math.max(1, existing.texelsPerCss);
5073
5805
  const sigmaCss = bodySigmaCssFor(sourceId);
5074
5806
  const sameSigma = Math.abs(sigmaCss - existing.bodySigmaCss) <= 1e-6 * Math.max(1, existing.bodySigmaCss);
5075
- if (sameDensity && sameSigma)
5807
+ const sameHeavy = sameHeavySigma(heavySigmaCssFor(sourceId), existing.heavySigmaCss);
5808
+ if (sameDensity && sameSigma && sameHeavy)
5076
5809
  continue;
5077
5810
  requests.push({
5078
5811
  sourceId,
@@ -5093,6 +5826,11 @@ function createWebGPURenderer(options = {}) {
5093
5826
  const optics = opticsUnderPolicy(material.optics[sourceVariant(sourceId)], accessibility, material);
5094
5827
  return optics.blurSigma / Math.max(viewport.devicePixelRatio, 1e-3);
5095
5828
  };
5829
+ const heavySigmaCssFor = (sourceId) => {
5830
+ if (bodySigmaCssFor(sourceId) <= 0)
5831
+ return 0;
5832
+ return heavyTapSigmaAtScale(material, viewport.devicePixelRatio) / Math.max(viewport.devicePixelRatio, 1e-3);
5833
+ };
5096
5834
  const groupTintSeed = (input) => input.surfaces.find((surface) => surface.fieldReferenceOnly !== true && (surface.tint?.strength ?? 0) > 0)?.tint?.color;
5097
5835
  const stateOf = (input, resolution) => {
5098
5836
  const resolved = resolution?.groups.find((group) => group.groupId === input.groupId);
@@ -5159,6 +5897,9 @@ function createWebGPURenderer(options = {}) {
5159
5897
  // scale. At dpr 1 this is `optics.blurSigma` unchanged, which is what
5160
5898
  // leaves the 1x law exactly as landed.
5161
5899
  bodySigmaCss: bodySigmaCssFor(request.sourceId),
5900
+ // The heavy blur's own σ, through the same conversion (W26). At 0 the
5901
+ // pyramid allocates nothing and encodes nothing.
5902
+ heavySigmaCss: heavySigmaCssFor(request.sourceId),
5162
5903
  viewportCss: [viewport.widthCss, viewport.heightCss],
5163
5904
  ...isUsablePlacement(placement) ? { placement } : {}
5164
5905
  }, provider, encoder);
@@ -5302,11 +6043,54 @@ function createWebGPURenderer(options = {}) {
5302
6043
  tintSeed: (policy.glass === "none" ? void 0 : groupTintSeed(input)) ?? optics.tint,
5303
6044
  tintToneAdaptation: tintToneAdaptation(policy, material),
5304
6045
  tintShade: [material.tintShadeDark, material.tintShadeLight, material.tintShadeStrength],
5305
- rimWidth: optics.rimWidth,
6046
+ // The band's half-width is a per-scale reading since W23: the reference's
6047
+ // rim narrows between the scales where vitrea's widened (claims §5.100
6048
+ // §5). At dpr 1, and on any variant whose two anchors are equal, this is
6049
+ // `optics.rimWidth` exactly.
6050
+ rimWidth: rimWidthAtScale(optics, dpr),
5306
6051
  rimAlpha: optics.rimAlpha,
5307
6052
  specularPower: optics.specularPower,
5308
6053
  specularGain: optics.specularGain,
6054
+ // The rim's amplitude law (W23). The level gain is per variant, because
6055
+ // a variant with a different `rimAlpha` has a different rim; the two
6056
+ // collapsed rims are the profile's, because the collapsed appearance is
6057
+ // one appearance and the reference's fixtures carry it identically in
6058
+ // both schemes, painted or bare (X4).
6059
+ rimLevelGain: optics.rimLevelGain,
6060
+ // Both ends of the collapsed rim's tint lerp, under the accessibility
6061
+ // regime: `collapsedRimUnderPolicy` returns the two absolute constants
6062
+ // unless a preference has asked for a border, in which case both ends are
6063
+ // the border's own alpha and the shader's `mix` is that constant at every
6064
+ // tint strength (W23 G1's review fix).
6065
+ rimCollapsed: collapsedRimUnderPolicy(policy, 0, material),
6066
+ rimCollapsedTinted: collapsedRimUnderPolicy(policy, 1, material),
6067
+ // The rim's light in the author's own colour (W23 G3). Under a strong
6068
+ // border the rim is the preference's mark and not the material's, so it
6069
+ // stays white: an accessibility border that took the paint's hue would
6070
+ // be the paint again, which is what it exists not to be.
6071
+ rimTintChroma: policy.border === "strong" ? 0 : material.rimTintChroma,
5309
6072
  lightDirection: material.lightDirection,
6073
+ // The lit edge (W24): the rim's own axis, kept apart from
6074
+ // `lightDirection` because the shadow reads that one and the two are
6075
+ // measured 22 degrees apart. The exponent comes from the variant's
6076
+ // optics under the accessibility fold, so a strong border's rim is one
6077
+ // brightness the whole way round.
6078
+ rimLitAxis: material.rimLitAxis,
6079
+ rimLitExponent: optics.rimLitExponent,
6080
+ // W25's three mechanisms (claims §5.113; W25 Decision Log 3), each of
6081
+ // them 0 on the landed material. The along-side field's slope is the
6082
+ // variant's under the same accessibility fold as the exponent it grades;
6083
+ // the heavy share's thick lift is resolved at the ratio this group draws
6084
+ // at, on the pattern every second-scale constant already has; the level
6085
+ // term's gain is the profile's, and the span curve it rides is the
6086
+ // shader's own `farS`.
6087
+ rimAlongSideSlope: optics.rimAlongSideSlope,
6088
+ sizeScatterHeavyShareThick: scatterHeavyShareThickAtScale(material, dpr),
6089
+ sizeToneLevelFar: material.sizeToneLevelFar,
6090
+ // The heavy blur (W26): whether this group's source carries one. The width
6091
+ // itself is already in the texture, so this pass only chooses which of
6092
+ // two textures the deep sample comes from.
6093
+ heavyTapEnabled: pyramid?.heavy !== void 0,
5310
6094
  shadowDepth: optics.shadowDepth,
5311
6095
  shadowAlpha: optics.shadowAlpha,
5312
6096
  // The size law's gains, per group (W2); the per-pixel factor they
@@ -5383,6 +6167,16 @@ function createWebGPURenderer(options = {}) {
5383
6167
  // were fitted on.
5384
6168
  backdropToneResponseStrength: backdropToneUnderPolicy(policy, material) >= 0.999 ? material.backdropToneResponseStrength : 0,
5385
6169
  backdropToneLinearMean: input.backdropToneLinearLuminance ?? backdropToneLevel,
6170
+ /*
6171
+ * The collapse's transmission (W24 G1) rides the UN-DEGRADED regime, on
6172
+ * the same gate and for the same reason as the response law above: it is
6173
+ * fitted on the standard reference, and the accessibility references are
6174
+ * a nearly opaque material whose collapsed appearance was never read
6175
+ * over a textured backdrop. Where any policy fold touches the tone axis
6176
+ * the collapse's target is the group's mean, which is W7's behaviour and
6177
+ * what those profiles were fitted on.
6178
+ */
6179
+ collapseTransmission: backdropToneUnderPolicy(policy, material) >= 0.999 ? collapseTransmissionAtScale(material, dpr) : 0,
5386
6180
  outerShadow: [
5387
6181
  // The thin regime's LINEAR occlusion at this group's backdrop (W14
5388
6182
  // G1). The conversion to the compositing space moved into the shader
@@ -5413,7 +6207,8 @@ function createWebGPURenderer(options = {}) {
5413
6207
  outerShadowRectCssHeight: rectDevice.height * cssPerDevice,
5414
6208
  backdrop: pyramid === void 0 || policy.glass === "none" ? void 0 : {
5415
6209
  chain: pyramid.chain.createView(),
5416
- body: pyramid.body.createView()
6210
+ body: pyramid.body.createView(),
6211
+ heavy: pyramid.heavy?.createView()
5417
6212
  }
5418
6213
  });
5419
6214
  if (active.highlight !== void 0) {
@@ -5444,6 +6239,11 @@ function createWebGPURenderer(options = {}) {
5444
6239
  * it, on this same product, and that zeroing is unchanged.
5445
6240
  */
5446
6241
  sweepGain: policy.glass === "none" ? 0 : material.sweepGain * lead.channels.shimmer,
6242
+ // `rimWidth`, NOT the scale-graded band the optics pass takes (W23).
6243
+ // The second anchor was fitted on the ambient rim read at the contour
6244
+ // on a resting surface, and this band carries the specular sweep,
6245
+ // which is gated to nothing at rest (W22) and has no row on any bed.
6246
+ // A constant whose rows do not separate it is not applied here either.
5447
6247
  rimWidth: optics.rimWidth,
5448
6248
  pressPointCss: lead.channels.pressPoint ?? lead.centre,
5449
6249
  glowRadiusCss: material.glowRadiusCss,
@@ -5702,6 +6502,6 @@ function createWebGPURenderer(options = {}) {
5702
6502
  };
5703
6503
  }
5704
6504
 
5705
- export { ADAPTIVE_LUMINANCE_HIGH, ADAPTIVE_LUMINANCE_LOW, ADAPTIVE_TINT_DARK, ADAPTIVE_TINT_LIGHT, ANALYSIS_DISPATCH, ANALYSIS_GRID, ANALYSIS_PASS_ID, ANALYSIS_STATS_FLOATS, ANALYSIS_TARGET_EXTENT, ANALYSIS_WORKGROUP, BACKDROP_ALPHA_MODES, BACKDROP_COLOR_SPACES, BACKDROP_KINDS, BACKDROP_PASS_ID, BACKDROP_TONE_HIGH, BACKDROP_TONE_LOW, BACKDROP_TONE_MAX, BACKDROP_TONE_SIZE_BIAS, CANVAS_FORMAT, CHAIN_SIGMA_AT_LEVEL_1, CROSS_CHECK_SHAPE_FLOATS, CROSS_CHECK_WORKGROUP, DEFAULT_MATERIAL_PROFILE, FAMILY_C_CROSS_CHECK, FIELD_PASS_ID, GOVERNOR_LADDER, HIGHLIGHT_PASS_ID, IDENTITY_FIT, IDLE_CHANNELS, INCREASED_OCCLUSION_LIFT, INSTANCE_BYTES, INSTANCE_FLOATS, LENS_AMOUNT_MAX, LENS_AMOUNT_PER_SPAN, LENS_EXTENT_GAIN, LENS_HEIGHT_MAX, LENS_HEIGHT_PER_SPAN, LENS_OVALIZATION, LENS_PROFILE_EXPONENT, LENS_REFRACTION_GAIN, LENS_SIZE_GAIN_MAX, LENS_THICKNESS_REFERENCE, LUMINANCE_WEIGHTS, MATERIAL_OPTICS, MATERIAL_VARIANTS, MAX_CHAIN_LEVELS, MIN_LEVEL_EXTENT, NOMINAL_GOVERNOR, NOMINAL_MATERIAL_POLICY, OPTICS_PASS_ID, OUTER_SHADOW, OUTER_SHADOW_THICK_SPANS, OUTER_SHADOW_THIN_L, OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE, OUTPUT_TEXTURE_FORMAT, PASS_LABEL, REFRACTION_LADDER, REFRACTION_SCALE, RENDERER_ERROR_CODES, RENDERER_PASS_IDS, RendererError, SIZE_OCCLUSION_GAIN, SIZE_SCATTER_FLOOR, SIZE_SCATTER_FLOOR_2X, SIZE_SCATTER_GAIN_FAR_2X, SIZE_SCATTER_GAIN_MAX, SIZE_SCATTER_GAIN_MAX_2X, SIZE_SCATTER_RAMP_REACH_1X_PX, SIZE_SCATTER_RAMP_REACH_2X_PX, SIZE_SCATTER_RAMP_START_FAR_1X, SIZE_SCATTER_RAMP_START_FAR_2X, SIZE_SCATTER_RAMP_START_THICK_1X, SIZE_SCATTER_RAMP_START_THICK_2X, SIZE_SCATTER_RAMP_START_THIN_1X, SIZE_SCATTER_RAMP_START_THIN_2X, SIZE_SCATTER_SPAN_MAX, SIZE_SCATTER_SPAN_MAX_2X, SIZE_SHADOW_GAIN_MAX, SIZE_SPAN_MAX, SIZE_SPAN_MIN, SRGB_ENCODING_EXPONENT, SUPPORTED_APP_TEXTURE_FORMATS, WGSL_ANALYSIS_PASS, WGSL_CROSS_CHECK_PASS, WGSL_DOWNSAMPLE_PASS, WGSL_FIELD_KERNELS, WGSL_FIELD_PASS, WGSL_FIELD_SAMPLE, WGSL_HIGHLIGHT_PASS, WGSL_IMPORT_PASS, WGSL_INSTANCE_STRUCT, WGSL_OPTICS_PASS, WGSL_PRELUDE, WGSL_RSUPN_GRAD, WGSL_RSUP_GRAD, WGSL_SMOOTH_UNION, WORKING_TEXTURE_FORMAT, ZERO_STATS, accessibilityRefractionCap, adaptationStrength, adaptedTintAlpha, adaptedTintColour, adaptiveTint, allShaderSource, alphaNormalisationMode, analysisModule, backdropFit, backdropToneAdaptation, backdropToneResponse, backdropToneSizeBiasUnderPolicy, backdropToneSolveWeight, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, coverFit, createAdaptationState, createAppTextureProvider, createCopyProvider, createDeviceHost, createGovernor, createGpuContext, createGradientProvider, createPassRunner, createPipelineCache, createPyramidStore, createRebuildLedger, createStorageSlot, createTexturePool, createTimingCollector, createUniformSlot, createVideoProvider, createWebGPURenderer, crossCheckKernelModule, displayP3ToSrgbLinear, effectiveRefraction, encodeOutput, encodeOutputBytes, fieldModule, fieldPassSource, groupFieldRect, highlightModule, importColorMatrix, importModule, importPassSource, isUsablePlacement, lensAmountBasePx, lensDepthPx, lensDirection, lensDisplacementPx, lensExtentPx, lensHeightBasePx, lensMagnitudePx, lensOvalizationAt, lensSizeGain, lensSizeGainFromThickness, linearGradientStops, linearToSrgb, linearToSrgbChannel, occlusionAlphaUnderPolicy, opticsModule, opticsUnderPolicy, outerShadowAlpha, outerShadowFalloff, outerShadowLiftRise, outerShadowOcclusionAt, outerShadowReachPx, outerShadowThickOcclusion, outerShadowThinOcclusion, outerShadowUnderPolicy, packInstances, pipelineKey, placementFit, planPyramid, poolKey, readbackDue, refractionRank, relativeLuminance, rendererError, resolveSurfaces, samePlacement, scatterDeepThickness, scatterFloorAtScale, scatterGainAt, scatterGainAtScale, scatterGainFarAtScale, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterSpanMaxAtScale, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
5706
- //# sourceMappingURL=dist-JWOMZCFF.js.map
5707
- //# sourceMappingURL=dist-JWOMZCFF.js.map
6505
+ export { ADAPTIVE_LUMINANCE_HIGH, ADAPTIVE_LUMINANCE_LOW, ADAPTIVE_TINT_DARK, ADAPTIVE_TINT_LIGHT, ANALYSIS_DISPATCH, ANALYSIS_GRID, ANALYSIS_PASS_ID, ANALYSIS_STATS_FLOATS, ANALYSIS_TARGET_EXTENT, ANALYSIS_WORKGROUP, BACKDROP_ALPHA_MODES, BACKDROP_COLOR_SPACES, BACKDROP_KINDS, BACKDROP_PASS_ID, BACKDROP_TONE_HIGH, BACKDROP_TONE_LOW, BACKDROP_TONE_MAX, BACKDROP_TONE_SIZE_BIAS, CANVAS_FORMAT, CHAIN_SIGMA_AT_LEVEL_1, CROSS_CHECK_SHAPE_FLOATS, CROSS_CHECK_WORKGROUP, DEFAULT_MATERIAL_PROFILE, FAMILY_C_CROSS_CHECK, FIELD_PASS_ID, GOVERNOR_LADDER, HIGHLIGHT_PASS_ID, IDENTITY_FIT, IDLE_CHANNELS, INCREASED_OCCLUSION_LIFT, INSTANCE_BYTES, INSTANCE_FLOATS, LENS_AMOUNT_MAX, LENS_AMOUNT_PER_SPAN, LENS_EXTENT_GAIN, LENS_HEIGHT_MAX, LENS_HEIGHT_PER_SPAN, LENS_OVALIZATION, LENS_PROFILE_EXPONENT, LENS_REFRACTION_GAIN, LENS_SIZE_GAIN_MAX, LENS_THICKNESS_REFERENCE, LUMINANCE_WEIGHTS, MATERIAL_OPTICS, MATERIAL_VARIANTS, MAX_CHAIN_LEVELS, MIN_LEVEL_EXTENT, NOMINAL_GOVERNOR, NOMINAL_MATERIAL_POLICY, OPTICS_PASS_ID, OUTER_SHADOW, OUTER_SHADOW_THICK_SPANS, OUTER_SHADOW_THIN_L, OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE, OUTPUT_TEXTURE_FORMAT, PASS_LABEL, REFRACTION_LADDER, REFRACTION_SCALE, RENDERER_ERROR_CODES, RENDERER_PASS_IDS, RendererError, SIZE_OCCLUSION_GAIN, SIZE_SCATTER_FLOOR, SIZE_SCATTER_FLOOR_2X, SIZE_SCATTER_GAIN_FAR_2X, SIZE_SCATTER_GAIN_MAX, SIZE_SCATTER_GAIN_MAX_2X, SIZE_SCATTER_RAMP_REACH_1X_PX, SIZE_SCATTER_RAMP_REACH_2X_PX, SIZE_SCATTER_RAMP_START_FAR_1X, SIZE_SCATTER_RAMP_START_FAR_2X, SIZE_SCATTER_RAMP_START_THICK_1X, SIZE_SCATTER_RAMP_START_THICK_2X, SIZE_SCATTER_RAMP_START_THIN_1X, SIZE_SCATTER_RAMP_START_THIN_2X, SIZE_SCATTER_SPAN_MAX, SIZE_SCATTER_SPAN_MAX_2X, SIZE_SHADOW_GAIN_MAX, SIZE_SPAN_MAX, SIZE_SPAN_MIN, SRGB_ENCODING_EXPONENT, SUPPORTED_APP_TEXTURE_FORMATS, WGSL_ANALYSIS_PASS, WGSL_CROSS_CHECK_PASS, WGSL_DOWNSAMPLE_PASS, WGSL_FIELD_KERNELS, WGSL_FIELD_PASS, WGSL_FIELD_SAMPLE, WGSL_HIGHLIGHT_PASS, WGSL_IMPORT_PASS, WGSL_INSTANCE_STRUCT, WGSL_OPTICS_PASS, WGSL_PRELUDE, WGSL_RSUPN_GRAD, WGSL_RSUP_GRAD, WGSL_SMOOTH_UNION, WORKING_TEXTURE_FORMAT, ZERO_STATS, accessibilityRefractionCap, adaptationStrength, adaptedTintAlpha, adaptedTintColour, adaptiveTint, allShaderSource, alphaNormalisationMode, analysisModule, backdropFit, backdropToneAdaptation, backdropToneResponse, backdropToneSizeBiasUnderPolicy, backdropToneSolveWeight, backdropToneUnderPolicy, bodyBlurPlan, chainModule, clipFieldRectToCanvas, collapsedRimUnderPolicy, coverFit, createAdaptationState, createAppTextureProvider, createCopyProvider, createDeviceHost, createGovernor, createGpuContext, createGradientProvider, createPassRunner, createPipelineCache, createPyramidStore, createRebuildLedger, createStorageSlot, createTexturePool, createTimingCollector, createUniformSlot, createVideoProvider, createWebGPURenderer, crossCheckKernelModule, displayP3ToSrgbLinear, effectiveRefraction, encodeOutput, encodeOutputBytes, fieldModule, fieldPassSource, groupFieldRect, heavyTapSigmaAtScale, highlightModule, importColorMatrix, importModule, importPassSource, isUsablePlacement, lensAmountBasePx, lensDepthPx, lensDirection, lensDisplacementPx, lensExtentPx, lensHeightBasePx, lensMagnitudePx, lensOvalizationAt, lensSizeGain, lensSizeGainFromThickness, linearGradientStops, linearToSrgb, linearToSrgbChannel, occlusionAlphaUnderPolicy, opticsModule, opticsUnderPolicy, outerShadowAlpha, outerShadowFalloff, outerShadowLiftRise, outerShadowOcclusionAt, outerShadowReachPx, outerShadowThickOcclusion, outerShadowThinOcclusion, outerShadowUnderPolicy, packInstances, pipelineKey, placementFit, planPyramid, poolKey, readbackDue, refractionRank, relativeLuminance, rendererError, resolveSurfaces, rimAlongSideFactor, rimAlongSideField, samePlacement, scatterDeepThickness, scatterFloorAtScale, scatterGainAt, scatterGainAtScale, scatterGainFarAtScale, scatterHeavyShareThickAtScale, scatterRampAreaMean, scatterRampReachDevicePx, scatterRampStart, scatterSharpShare, scatterSpanMaxAtScale, scatterThickness, shadowDepthPx, sizeOcclusionAlpha, sizeOcclusionAlphaAt, sizeOuterShadowOcclusion, sizeOuterShadowOcclusionAt, sizeScatterSigma, sizeScatterSigmaAt, sizeShadowDepth, sizeShadowDepthAt, sizeThickness, sizeThicknessUnderPolicy, sizeToneLevelFar, snapRectToDevicePixels, srgbToLinear, srgbToLinearChannel, statsFromBuffer, supportsTimestamps, texelsPerCssPx, tintShade, tintShadeLayer, tintToneAdaptation, tintedMaterialColour, validateAppTexture, withMaterialOverrides };
6506
+ //# sourceMappingURL=dist-PT4PUS4K.js.map
6507
+ //# sourceMappingURL=dist-PT4PUS4K.js.map