@vitreajs/vitrea 0.22.0 → 0.23.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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../renderer-webgpu/src/wgsl/analysis.ts","../../policy/src/refraction.ts","../../renderer-webgpu/src/color.ts","../../renderer-webgpu/src/material.ts","../../renderer-webgpu/src/analysis.ts","../../renderer-webgpu/src/errors.ts","../../renderer-webgpu/src/backdrop.ts","../../renderer-webgpu/src/backdrop-fit.ts","../../renderer-webgpu/src/device.ts","../../renderer-webgpu/src/governor.ts","../../renderer-webgpu/src/pipeline-cache.ts","../../renderer-webgpu/src/texture-pool.ts","../../renderer-webgpu/src/gpu-context.ts","../../renderer-webgpu/src/render-model.ts","../../renderer-webgpu/src/instances.ts","../../renderer-webgpu/src/timing.ts","../../renderer-webgpu/src/wgsl/cross-check.ts","../../renderer-webgpu/src/wgsl/backdrop.ts","../../renderer-webgpu/src/wgsl/field.ts","../../renderer-webgpu/src/wgsl/highlight.ts","../../renderer-webgpu/src/wgsl/optics.ts","../../renderer-webgpu/src/wgsl/prelude.ts","../../renderer-webgpu/src/wgsl/silhouette-tone.ts","../../renderer-webgpu/src/wgsl/index.ts","../../renderer-webgpu/src/passes.ts","../../renderer-webgpu/src/pyramid-plan.ts","../../renderer-webgpu/src/rebuild-ledger.ts","../../renderer-webgpu/src/pyramid.ts","../../renderer-webgpu/src/silhouette-tone.ts","../../renderer-webgpu/src/renderer.ts"],"names":["t","smoothstep","shape","outerShadowReachPx","level"],"mappings":"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GAAsB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACoC5B,IAAM,gBAAA,GAAmB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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","file":"dist-N437MSRG.js","sourcesContent":["/**\n * The analysis reduction: luminance, variance and edge density off the blur\n * pyramid, into a four-float stats buffer per backdrop source.\n *\n * This is what `analysis: \"exact\"` means in X2 — a real reduction over the real\n * pixels, not an estimate. It runs once per pyramid rebuild, which by the §Core\n * model invariant is at most once per dirty source per frame.\n *\n * ## Why one workgroup\n *\n * The reduction reads a fixed 64×64 grid of bilinear samples off a chosen chain\n * level, whatever that level's real size is. That makes the pass's cost constant\n * — 4096 samples, one workgroup, one dispatch — instead of proportional to the\n * backdrop's resolution, and it makes the result independent of the resolution\n * policy, so raising or lowering `scale` does not move the tint. A grid rather\n * than every texel is the right trade because the values feed a tint and a\n * light/dark decision, both of which are already low-passed in time.\n *\n * ## Edge density\n *\n * Central differences of luminance on the same grid, averaged. Read off a\n * mid-chain level rather than the coarsest: the coarsest level has had every edge\n * blurred out of it, so an edge measurement there would report the same small\n * number for a photograph and for a solid colour. The level choice lives on the\n * CPU (`pyramid-plan.ts`) where the sizes are known.\n *\n * ## Variance\n *\n * Accumulated as the mean of squares and folded at the end, which is the\n * numerically shakier of the two standard routes — but the inputs are luminances\n * in [0, ~1] over 4096 samples, so the cancellation is nowhere near f32's\n * resolution, and it costs one accumulator instead of two passes.\n */\n\nexport const ANALYSIS_WORKGROUP = 64;\nexport const ANALYSIS_GRID = 64;\n\n/**\n * `stats` layout: mean luminance (ENCODED-space mean, decoded once by the host —\n * the W9 model, claims §5.31), variance (linear), edge density, sample count.\n */\nexport const ANALYSIS_STATS_FLOATS = 4;\n\nexport const WGSL_ANALYSIS_PASS = `struct AnalysisUniforms {\n /// grid.xy = sample grid size, grid.z = source level, grid.w = 1/(grid-1)\n grid : vec4f,\n /// texel.xy = one texel of the sampled level, in uv\n texel : vec4f,\n};\n\n@group(0) @binding(0) var<uniform> au : AnalysisUniforms;\n@group(0) @binding(1) var analysisSampler : sampler;\n@group(0) @binding(2) var analysisTexture : texture_2d<f32>;\n@group(0) @binding(3) var<storage, read_write> stats : array<f32>;\n\nvar<workgroup> partialLum : array<f32, ${ANALYSIS_WORKGROUP}>;\nvar<workgroup> partialTone : array<f32, ${ANALYSIS_WORKGROUP}>;\nvar<workgroup> partialSq : array<f32, ${ANALYSIS_WORKGROUP}>;\nvar<workgroup> partialEdge : array<f32, ${ANALYSIS_WORKGROUP}>;\n\nfn lum_at(uv : vec2f) -> f32 {\n let s = textureSampleLevel(analysisTexture, analysisSampler, uv, au.grid.z);\n // Level 0 onwards is premultiplied linear; unpremultiplying keeps a\n // transparent backdrop region from reading as black rather than as absent.\n let colour = s.rgb / max(s.a, 1e-6);\n return luminance(colour);\n}\n\n@compute @workgroup_size(${ANALYSIS_WORKGROUP})\nfn cs_analysis(@builtin(local_invocation_index) lane : u32) {\n let total = u32(au.grid.x * au.grid.y);\n var sumLum = 0.0;\n var sumTone = 0.0;\n var sumSq = 0.0;\n var sumEdge = 0.0;\n var n = 0.0;\n\n var i = lane;\n loop {\n if (i >= total) { break; }\n let gx = f32(i % u32(au.grid.x));\n let gy = f32(i / u32(au.grid.x));\n let uv = vec2f(gx, gy) * au.grid.w;\n\n let c = lum_at(uv);\n let dx = lum_at(uv + vec2f(au.texel.x, 0.0)) - lum_at(uv - vec2f(au.texel.x, 0.0));\n let dy = lum_at(uv + vec2f(0.0, au.texel.y)) - lum_at(uv - vec2f(0.0, au.texel.y));\n\n // The published luminance accumulates ENCODED — the W9 model (claims\n // 5.31): the reference's tone responses track the encoded-space mean of a\n // structured backdrop, not its linear mean. The host decodes the mean once\n // on readback, so every consumer downstream still speaks linear light.\n // The linear sum stays, because the variance fold below needs a mean in\n // the same space as its squares; variance and edge density stay linear —\n // nothing tonal reads them.\n sumLum = sumLum + c;\n sumTone = sumTone + linear_to_srgb(vec3f(c, c, c)).x;\n sumSq = sumSq + c * c;\n sumEdge = sumEdge + length(vec2f(dx, dy)) * 0.5;\n n = n + 1.0;\n\n i = i + ${ANALYSIS_WORKGROUP}u;\n }\n\n partialLum[lane] = sumLum;\n partialTone[lane] = sumTone;\n partialSq[lane] = sumSq;\n partialEdge[lane] = sumEdge;\n workgroupBarrier();\n\n // Tree reduction. ${ANALYSIS_WORKGROUP} is a power of two, so no tail case.\n var stride = ${ANALYSIS_WORKGROUP}u / 2u;\n loop {\n if (stride == 0u) { break; }\n if (lane < stride) {\n partialLum[lane] = partialLum[lane] + partialLum[lane + stride];\n partialTone[lane] = partialTone[lane] + partialTone[lane + stride];\n partialSq[lane] = partialSq[lane] + partialSq[lane + stride];\n partialEdge[lane] = partialEdge[lane] + partialEdge[lane + stride];\n }\n workgroupBarrier();\n stride = stride / 2u;\n }\n\n if (lane == 0u) {\n let count = max(f32(total), 1.0);\n let mean = partialLum[0] / count;\n // stats[0] is the ENCODED-space mean; the host decodes it once (W9).\n stats[0] = partialTone[0] / count;\n stats[1] = max(partialSq[0] / count - mean * mean, 0.0);\n stats[2] = partialEdge[0] / count;\n stats[3] = count;\n }\n}`;\n","// The refraction ladder, and the dual-cap rule that only means something against\n// it (Decision Log #19). `index.ts` carries the account of why the ladder lives\n// in a package of its own rather than in core; this file is the ladder.\n//\n// Every declaration's doc comment below is inlined verbatim into the published\n// `vitrea` and `vitrea-web` type declarations, because tsup's `dts.resolve`\n// bundles this package into both. That is the reason the prose here stays on\n// what a consumer of `effectiveRefraction` needs and the workspace-internal\n// layering argument stays in `index.ts`, where nothing inlines it: a file\n// comment only detaches from the first declaration when imports sit between\n// them, and this file has no imports to sit there.\n\n/**\n * The refraction ladder, weakest rung first.\n *\n * Two independent things cap refraction: the accessibility policy's ceiling\n * (core's `ResolvedMaterialPolicy.refraction`, a regime — `nominal | reduced |\n * none`) and the group's resolved capability state (X2's `RefractionQuality` —\n * `true | approximate | none`, what the sampling backend can actually deliver).\n * **Renderers honour the lower of the two** (Decision Log #19), which is only a\n * meaningful sentence against an ordering — this one.\n *\n * Written out rather than derived from `RefractionQuality`, because that type's\n * own declaration order is not an ordering.\n */\nexport const REFRACTION_LADDER = [\"none\", \"approximate\", \"true\"] as const;\n\n/**\n * X2's capability-derived refraction level (`core/src/state.ts` re-exports this\n * name). Derived from the ladder so the rungs and the type cannot drift apart.\n */\nexport type RefractionQuality = (typeof REFRACTION_LADDER)[number];\n\n/**\n * The accessibility *ceiling* axis — core's `ResolvedMaterialPolicy.refraction`.\n * A different vocabulary from `RefractionQuality` on purpose: one says what the\n * backend can deliver, the other what the user's preferences permit.\n */\nexport type RefractionRegime = \"nominal\" | \"reduced\" | \"none\";\n\n/**\n * The slice of a resolved material policy the ladder reads: one axis.\n *\n * Typed as the minimum rather than as a whole policy so both tiers' fuller types\n * satisfy it structurally with no adapter — core's `ResolvedMaterialPolicy` above\n * the seam, the renderer's `MaterialPolicyView` below it.\n */\nexport interface RefractionPolicyView {\n readonly refraction: RefractionRegime;\n}\n\nexport function refractionRank(quality: RefractionQuality): number {\n return REFRACTION_LADDER.indexOf(quality);\n}\n\n/**\n * The accessibility regime as a rung on the same ladder.\n *\n * `reduced` maps to `approximate` rather than to something between: the ladder\n * has three rungs and \"less refraction than true lensing\" is exactly the\n * rim-lensing approximation. `nominal` maps to the top rung, which is a cap of\n * \"uncapped\" — it can never raise a state, only fail to lower it.\n */\nexport function accessibilityRefractionCap(policy: RefractionPolicyView): RefractionQuality {\n switch (policy.refraction) {\n case \"nominal\":\n return \"true\";\n case \"reduced\":\n return \"approximate\";\n case \"none\":\n return \"none\";\n }\n}\n\n/** The lower of the two caps. Symmetric — neither argument is privileged. */\nexport function effectiveRefraction(\n a: RefractionQuality,\n b: RefractionQuality,\n): RefractionQuality {\n return refractionRank(a) <= refractionRank(b) ? a : b;\n}\n\n/** How much of a depth simulation each rung allows, keyed by the ladder. */\nexport type RefractionScale = Readonly<Record<RefractionQuality, number>>;\n\n/**\n * The rung scales both tiers start from.\n *\n * `approximate` is not \"half of true\": it is the rim-lensing approximation, a\n * shallower bend confined nearer the edge, which is what a group sampling a CSS\n * proxy can honestly claim. Reduced transparency lands here too, which is the\n * point of the ladder having three rungs and not two.\n *\n * **Advisory and calibration-delegated (C7), like every other optical constant.**\n * This is the *default*, not the running value: `@vitrea/renderer-webgpu`'s\n * `MaterialProfile.refractionScale` is what the shaders read and what\n * `withMaterialOverrides` replaces, and the CSS tier's `sourceRefractionScale`\n * merges the same patch by the same rule. The literal lives here rather than in\n * either tier because it was previously authored three times over — once in the\n * profile and twice in `platform-web/src/optics.ts` — and three copies of one\n * measured number is three chances for a calibration round to move two of them.\n */\nexport const DEFAULT_REFRACTION_SCALE: RefractionScale = {\n none: 0,\n approximate: 0.45,\n true: 1,\n};\n","/**\n * X5 — the colour pipeline, CPU side.\n *\n * The contract in one line: **internal optical maths in linear light,\n * compositing premultiplied, output sRGB, v1 locked to the sRGB gamut.** Without\n * that lock golden images destabilise across GPUs and browsers and blur energy\n * drifts from the reference, which is the whole reason §Color pipeline exists.\n *\n * Three concrete consequences the rest of the renderer leans on:\n *\n * 1. **Every internal texture is `rgba16float` and holds linear light.** 8-bit\n * linear would band visibly in a blur pyramid; `rgba16float` is renderable and\n * filterable everywhere WebGPU is, so no adapter feature is required.\n * 2. **Alpha is normalised at import** (X3). `copyExternalImageToTexture`\n * delivers premultiplied; `importExternalTexture` delivers unpremultiplied.\n * Whichever arrives, level 0 of the pyramid is premultiplied linear — one\n * invariant, checked once at import, instead of an alpha mode threaded\n * through every downstream pass.\n * 3. **Output is encoded once, at the end of the last pass.** The optics and\n * highlight canvases are configured `alphaMode: \"premultiplied\"` in a plain\n * (non-`-srgb`) 8-bit format, and the browser composites those bytes as sRGB.\n * So the final step is `encode(linear)` and then `* alpha` — premultiplying in\n * the *encoded* space, which is what canvas compositing expects. Premultiplying\n * in linear and then encoding would darken every edge pixel.\n *\n * The transfer functions here are the exact piecewise sRGB curve, not the 2.2\n * approximation: the WGSL uses the same piecewise form, and a test asserts the\n * two agree, so a golden regenerated on one and asserted on the other cannot\n * drift by a code unit.\n */\n\n/**\n * The colour spaces v1 accepts on an imported backdrop.\n *\n * `display-p3` is *accepted and tagged*, never silently treated as sRGB — but v1\n * converts it into the sRGB working space rather than carrying a wide gamut\n * through the pipeline (§Color pipeline: \"Display-P3 and HDR/extended-range are\n * future profiles\"). Tagging it is what makes the future profile a data change.\n */\nexport const BACKDROP_COLOR_SPACES = [\"srgb\", \"display-p3\"] as const;\n\nexport type BackdropColorSpace = (typeof BACKDROP_COLOR_SPACES)[number];\n\n/** How a provider's pixels arrive. Normalised to `premultiplied` at import. */\nexport const BACKDROP_ALPHA_MODES = [\"premultiplied\", \"unpremultiplied\", \"opaque\"] as const;\n\nexport type BackdropAlphaMode = (typeof BACKDROP_ALPHA_MODES)[number];\n\n/** The one internal pixel format. See consequence 1 above. */\nexport const WORKING_TEXTURE_FORMAT: GPUTextureFormat = \"rgba16float\";\n\n/** The presentation format for the plane canvases and for golden readback. */\nexport const OUTPUT_TEXTURE_FORMAT: GPUTextureFormat = \"rgba8unorm\";\n\nconst SRGB_LINEAR_CUTOFF = 0.0031308;\nconst SRGB_ENCODED_CUTOFF = 0.04045;\nconst SRGB_SLOPE = 12.92;\nconst SRGB_ALPHA = 1.055;\nconst SRGB_OFFSET = 0.055;\nconst SRGB_GAMMA = 2.4;\n\n/** One channel, sRGB-encoded [0,1] → linear-light [0,1]. */\nexport function srgbToLinearChannel(c: number): number {\n if (c <= SRGB_ENCODED_CUTOFF) return c / SRGB_SLOPE;\n return Math.pow((c + SRGB_OFFSET) / SRGB_ALPHA, SRGB_GAMMA);\n}\n\n/** One channel, linear-light [0,1] → sRGB-encoded [0,1]. */\nexport function linearToSrgbChannel(c: number): number {\n if (c <= SRGB_LINEAR_CUTOFF) return c * SRGB_SLOPE;\n return SRGB_ALPHA * Math.pow(c, 1 / SRGB_GAMMA) - SRGB_OFFSET;\n}\n\nexport type Rgb = readonly [r: number, g: number, b: number];\n\nexport const srgbToLinear = (c: Rgb): Rgb => [\n srgbToLinearChannel(c[0]),\n srgbToLinearChannel(c[1]),\n srgbToLinearChannel(c[2]),\n];\n\nexport const linearToSrgb = (c: Rgb): Rgb => [\n linearToSrgbChannel(c[0]),\n linearToSrgbChannel(c[1]),\n linearToSrgbChannel(c[2]),\n];\n\n/**\n * Rec.709 luminance weights, applied to **linear** light.\n *\n * Stated explicitly because the common mistake is to weight sRGB-encoded values\n * — which gives a number that tracks perceived lightness loosely and blur energy\n * not at all. The analysis pass reduces linear luminance for the same reason the\n * blur runs in linear light: both are energy integrals.\n */\nexport const LUMINANCE_WEIGHTS: Rgb = [0.2126, 0.7152, 0.0722];\n\nexport function relativeLuminance(linear: Rgb): number {\n return (\n linear[0] * LUMINANCE_WEIGHTS[0] +\n linear[1] * LUMINANCE_WEIGHTS[1] +\n linear[2] * LUMINANCE_WEIGHTS[2]\n );\n}\n\n/**\n * Display-P3 → sRGB (linear light, both ends).\n *\n * The 3×3 is the product of P3-to-XYZ and XYZ-to-sRGB under D65. Out-of-gamut\n * results are clamped, which loses saturation on very saturated P3 content — the\n * honest v1 behaviour, and the reason the colour space is *tagged* rather than\n * assumed (a P3 profile can then convert differently without touching a shader).\n */\nconst P3_TO_SRGB: readonly Rgb[] = [\n [1.224940176280559, -0.224940176280559, 0],\n [-0.042056973821316, 1.042056973821316, 0],\n [-0.019637554590334, -0.078636046901105, 1.098273601491439],\n];\n\nexport function displayP3ToSrgbLinear(linearP3: Rgb): Rgb {\n const out: number[] = [];\n for (const row of P3_TO_SRGB) {\n out.push(\n Math.min(1, Math.max(0, row[0] * linearP3[0] + row[1] * linearP3[1] + row[2] * linearP3[2])),\n );\n }\n return [out[0] as number, out[1] as number, out[2] as number];\n}\n\n/**\n * The colour-space conversion the import pass must apply, as data.\n *\n * Returned as a matrix (row-major 3×3) so the shader takes one uniform and has\n * no branch on colour space. Identity for sRGB — the overwhelmingly common case\n * costs three dot products, which is cheaper than the branch would be.\n */\nexport function importColorMatrix(space: BackdropColorSpace): Float32Array {\n if (space === \"srgb\") {\n return new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);\n }\n const rows = P3_TO_SRGB;\n return new Float32Array([\n ...(rows[0] as Rgb),\n ...(rows[1] as Rgb),\n ...(rows[2] as Rgb),\n ]);\n}\n\n/**\n * The alpha normalisation the import pass must apply, as a scalar flag.\n *\n * `0` = already premultiplied, `1` = divide the colour by alpha first, `2` =\n * force alpha to 1. Three modes and one uniform, resolved on the CPU where the\n * provider's contract is known, so no shader ever guesses (X3).\n */\nexport function alphaNormalisationMode(mode: BackdropAlphaMode): number {\n switch (mode) {\n case \"premultiplied\":\n return 0;\n case \"unpremultiplied\":\n return 1;\n case \"opaque\":\n return 2;\n }\n}\n\n/**\n * Encode a linear-light colour and its alpha the way the output pass does, for\n * tests and for golden-image expectations computed on the CPU.\n */\nexport function encodeOutput(linear: Rgb, alpha: number): readonly [number, number, number, number] {\n const a = Math.min(1, Math.max(0, alpha));\n const encoded = linearToSrgb(linear);\n return [encoded[0] * a, encoded[1] * a, encoded[2] * a, a];\n}\n\n/** The same, quantised to the 8-bit bytes a golden PNG holds. */\nexport function encodeOutputBytes(linear: Rgb, alpha: number): readonly number[] {\n return encodeOutput(linear, alpha).map((c) => Math.round(Math.min(1, Math.max(0, c)) * 255));\n}\n","/**\n * The optical constants, and the two foldings that decide what the shader\n * actually gets: the dual cap, and the size-parameterised lens.\n *\n * **Every number here is advisory and calibration-delegated (C7).** They are\n * chosen so the material is coherent out of the box — a plausible glass, not a\n * measured one — and §Calibration names exactly this kind of value as a delegated\n * unknown. They live in one profile object (`MaterialProfile`) so replacing them\n * with fitted values is a data change (`withMaterialOverrides`), and no shader\n * carries a literal of its own. The named constants below are re-exports of that\n * profile's defaults, kept because a reader wants a name for σ = 8 more often\n * than a whole profile.\n *\n * ## The dual cap (Decision Log #19)\n *\n * Two independent things cap refraction: the accessibility policy's regime\n * (`nominal | reduced | none`) and the group's resolved capability state\n * (`true | approximate | none` — what the sampling backend can actually deliver).\n * **The lower of the two wins**, and this module folds them into one scalar before\n * anything reaches a uniform, so the shader has no way to honour the wrong one.\n *\n * The ordering is `@vitrea/policy`'s, and so is the fold. It used to be restated\n * here — this package sits *below* core in the dependency graph and platform-web\n * sits above it, so for most of v1 there was no module both tiers could see and\n * the CSS tier carried a second copy. Decision Log #23(d) closed that seam by\n * putting the ladder in a pure leaf underneath everything, which the renderer can\n * depend on directly (alongside `@vitrea/geometry`) with no cycle to close. The\n * two copies can no longer disagree because there is only one.\n */\n\nimport {\n accessibilityRefractionCap,\n DEFAULT_REFRACTION_SCALE,\n REFRACTION_LADDER,\n type RefractionQuality,\n} from \"@vitrea/policy\";\n\nimport type { Rgb } from \"./color\";\nimport { linearToSrgbChannel, relativeLuminance, srgbToLinear, srgbToLinearChannel } from \"./color\";\n\n// Re-exported under the names this package and its tests already know them by,\n// so nothing downstream has to learn where the ladder went.\nexport {\n accessibilityRefractionCap,\n effectiveRefraction,\n REFRACTION_LADDER,\n refractionRank,\n type RefractionQuality,\n} from \"@vitrea/policy\";\n\n/**\n * The slice of core's `ResolvedAccessibilityPolicy[\"material\"]` the renderer\n * reads. core's type is assignable to this; a test pins that.\n */\nexport interface MaterialPolicyView {\n readonly glass: \"material\" | \"none\";\n readonly frost: \"nominal\" | \"increased\" | \"none\";\n readonly refraction: \"nominal\" | \"reduced\" | \"none\";\n readonly occlusion: \"nominal\" | \"increased\" | \"opaque\";\n readonly border: \"nominal\" | \"strong\";\n readonly ambientTint: \"nominal\" | \"reduced\" | \"none\";\n readonly foreground: \"adaptive\" | \"near-monochrome\";\n}\n\n/** Nominal accessibility material policy — nothing capped. Mirrors core's. */\nexport const NOMINAL_MATERIAL_POLICY: MaterialPolicyView = {\n glass: \"material\",\n frost: \"nominal\",\n refraction: \"nominal\",\n occlusion: \"nominal\",\n border: \"nominal\",\n ambientTint: \"nominal\",\n foreground: \"adaptive\",\n};\n\n/** The two variants, declared as data so a profile merge can walk them. */\nexport const MATERIAL_VARIANTS = [\"regular\", \"clear\"] as const;\n\nexport type MaterialVariant = (typeof MATERIAL_VARIANTS)[number];\n\nexport interface MaterialOptics {\n /** Body blur σ in CSS px. Matches `platform-web`'s `MATERIAL_OPTICS.blurRadius`. */\n readonly blurSigma: number;\n /** Tint over the blurred backdrop, linear light. */\n readonly tint: Rgb;\n readonly tintAlpha: number;\n /** Rim band half-width in CSS px, and its ambient brightness. */\n readonly rimWidth: number;\n readonly rimAlpha: number;\n /**\n * **The rim band's half-width at dpr 2** (W23; claims §5.100 §5, Decision\n * Log 2 (d)) — `rimWidth`'s second reading, on the precedent of\n * `sizeScatterGainMax2x` and its siblings and interpolated by the same\n * `rampAtScale`.\n *\n * The rim's amplitude below is one law for both scales, and it cannot be: read\n * at the contour, vitrea's per-CSS-px band integral RISES 19 % between 1x and\n * 2x (0.068 → 0.081) while the reference's FALLS 10 % (0.229 → 0.205), so the\n * same amplitude that lands the 1x dark-backdrop solids at −0.003…−0.007 lands\n * the 2x rows at +0.037…+0.051. The mismatch is the band's shape and not its\n * height: at 1x over a dark backdrop the two rims are already the same\n * one-pixel line (the reference's second contour row carries 8 % of the peak\n * and vitrea's −7 %), and at 2x vitrea spreads 35 % of its peak onto the second\n * row where the reference puts 55 % of a NARROWER line. So `rimWidth` does not\n * move — the 1x rows do not ask it to — and the 2x band narrows instead.\n *\n * At dpr ≤ 1 this constant is not read at all (`rimWidthAtScale`), so a profile\n * that carries it renders the 1x material unchanged by construction.\n */\n readonly rimWidth2x: number;\n /**\n * Specular exponent and gain on the rim — **RETIRED from the rim (W24 G2;\n * claims §5.108 §1, W24 Decision Log 2 (a)), and the note is set beside the\n * W22 fit below rather than over it.**\n *\n * The term was `max(dot(normal, lightDirection), 0)^specularPower ×\n * specularGain`, one-sided, added to the rim's amplitude. W24 read the\n * reference's rim around the whole contour instead of per side and found the\n * variation it was reaching for — but symmetric about the diagonal, not\n * one-sided: the two ends of that diagonal are drawn EQUAL to a thousandth\n * (2x dark tl 0.0418 against br 0.0418; 2x light 0.2786 against 0.2823), and\n * over the nineteen untinted solid rows the one-sided form reaches a\n * normalised RMS of 0.288 against the symmetric form's 0.148, degenerating in\n * the fit to the ceiling of both its exponent and its floor trying to become\n * symmetric. So the shape was wrong, which is the deeper reason W22 G1 rightly\n * fitted the gain to 0 on the regular variant (claims §5.94 §3): no amount of\n * a term with the wrong shape helps. `rimLitExponent` below is the shape the\n * rows chose, and it replaces this one.\n *\n * Nothing on either canonical bed moves: the shipped profiles carry\n * `specularGain` 0 on `regular` since W21/W22, and no scene on either bed or in\n * the golden suite declares `clear`. What DOES change is the `clear` variant's\n * unfitted structural 0.45, which drew a one-sided highlight this material is\n * now measured not to have; it is recorded rather than replaced, because the\n * lit factor is inert on `clear` for want of rows.\n *\n * The two constants stay on the profile so that the W22 fit's record and the\n * profile documents that carry it remain readable, and so that removing them\n * is one reviewable change of the profile's SHAPE rather than a side effect of\n * a material gate. Nothing reads them.\n */\n readonly specularPower: number;\n readonly specularGain: number;\n /**\n * **The rim's amplitude law (W23; claims §5.100 §4, Decision Log 2 (a))** — the\n * term that lets the rim depend on what it is drawn over, which `rimAlpha`\n * alone cannot.\n *\n * `rimAlpha` was an additive constant: the shader added `rimWeight × rimAlpha`\n * and nothing scaled it. The reference's rim is not a constant. Read at the\n * contour (claims §5.99, §5.100 §2; W23 X1) the light reference's rim is\n * +0.23…0.26 of linear luminance over a dark solid, +0.13…0.21 over a\n * structured backdrop and clipped to white over `light-solid`, while vitrea\n * drew the same +0.060…0.078 everywhere; and the dark reference's rim GROWS\n * with what is behind it, +0.026 over `dark-solid` and +0.103 over\n * `light-solid`, at a body that moves by only a twelfth as much.\n *\n * `rimLevelGain` is the coefficient of the surface's OWN rendered level: the\n * rim becomes `rimAlpha + rimLevelGain × luminance(surface)`. Four candidate\n * forms were fitted on the reference's own solid, unclipped, uncollapsed sides\n * — 44 in light and 36 in dark, from both canonical scales and both probe grids\n * — and this one wins in both schemes on mean |residual|: 0.0081 / 0.0013\n * against 0.0249 / 0.0253 for the additive constant, 0.0168 / 0.0259 for a pure\n * screen and 0.0105 / 0.0042 for screen plus an environment term.\n *\n * The gain is SIGNED, and its sign is the whole finding. A negative gain is the\n * screen form — a white line composited source-over at a fraction of the body's\n * headroom, which is what the CSS tier's inset `box-shadow` already is — and\n * the light material's rows want one. A positive gain is a rim that rides its\n * own body up, and the dark material's rows want that, strongly.\n *\n * **The environment term is not here, and its absence is a measurement.** W23\n * chartered `rimEnvGain` — a coefficient on the backdrop source's own average\n * luminance — as the candidate (L3) for what makes the reference's rim clip\n * over a bright backdrop while its body is nowhere near white. It is declined\n * and REMOVED rather than shipped at 0: it is worse than this law on the\n * reference in both schemes, and no row of either bed separates it on vitrea's\n * side (a rendered ladder point at +0.10 of gain moved every solid cell by 0 or\n * 0.0005, because `light-solid` clips and the dark solids have no environment\n * to speak of). C9a §6.2's rule is that a constant whose rows do not separate\n * it is not carried. What the reference does there is real and is recorded in\n * the wave's Deferred list with its numbers: a bed with a mid-bright solid\n * backdrop under a light-scheme thick surface would tell the environment apart\n * from the body, and no bed that exists can.\n */\n readonly rimLevelGain: number;\n /**\n * **The lit edge (W24; claims §5.107)** — the exponent of the directional\n * factor `(√2 · |n · L|)^rimLitExponent` the rim's whole amplitude is\n * multiplied by, with `L` the profile's `rimLitAxis`.\n *\n * W23 gave the rim the right AMOUNT and the wrong SHAPE. Read around the whole\n * contour rather than per side (`results/2026-09-09-w24-lit-edge/g0/\n * read-angular.py`), Apple's rim is not constant: on the 2x dark\n * `dark-solid__rrect-md` the bins whose normal points north-west and\n * south-east read 0.0408 and 0.0418 against 0.0016 for north-east and\n * south-west, with the four straight sides at 0.0312–0.0328; the same cell in\n * the light scheme reads 0.284 / 0.286 against 0.038, sides 0.233–0.247.\n * vitrea drew one number everywhere — a drawn line, which is what the user's\n * eye called an aesthetic regression on the W23 landing sheet.\n *\n * No per-side reader could see it, and the reason is geometric: a light on the\n * 45° diagonal projects EQUALLY on all four straight sides, so `L−R` and\n * `T−B` are 0 for the reference exactly as they are for vitrea. The variation\n * lives in the corner arcs, which W23's contour reader excludes by\n * construction and W21's band reader averages into its corner overshoot.\n *\n * **The form is symmetric and it is not a Lambert.** Fitted on the reference's\n * own bins over the 19 untinted solid cells of both canonical beds and both\n * probe grids, `(√2 · |n · L|)^p` reaches an RMS of 0.148 of each cell's own\n * peak against 0.288 for the one-sided `max(n · L, 0)^p` that W22's `spec`\n * term draws and 0.312 for the flat rim vitrea ships. The one-sided form\n * cannot reach both ends of a diagonal whose two corners the reference draws\n * equal to a thousandth, and that — not its gain — is why W22 rightly fitted\n * `specularGain` to 0.\n *\n * **There is no ambient floor.** The wave chartered `a + (1 − a)|n · L|^p` with\n * `a` expected around 0.15 dark and 0.25 light. Every grouping of the rows fits\n * `a` to 0.000 (the search ran 0…0.6 in steps of 0.005), because the bin mean\n * of `|cos|^p` over the 22.5° straddling the null is already 0.10–0.16 and\n * supplies everything the null bins carry. A constant every row fits to zero is\n * a constant the material does not have (C9a §6.2), so it is not here.\n *\n * **The `√2` is the amplitude's re-expression, in closed form.** W23 fitted\n * `rimAlpha` and `rimLevelGain` on the STRAIGHT SPANS, which under this factor\n * sit at `(cos 45°)^p` of the peak. Normalising the dot product by `cos 45°`\n * inside the power makes the factor exactly 1 wherever the normal is\n * horizontal or vertical, at every exponent — so no fitted amplitude moves,\n * W23's straight-span reads hold identically rather than approximately, and\n * only the corners and the arcs change. It is why the CSS tier, whose inset\n * shadow cannot vary around a contour, needs no re-fit either.\n *\n * At 0 the factor is `pow(x, 0)` = 1 for every normal, so a profile that does\n * not carry this constant renders the W23 material byte for byte.\n */\n readonly rimLitExponent: number;\n /**\n * **The lit edge's along-side field (W25; claims §5.113, W25 Decision Log 3\n * (c))** — the slope of the position field the rim's amplitude is graded by\n * across the surface, riding `sizeThickness`.\n *\n * W24 gave the rim a factor of the NORMAL, which is one number on a whole\n * straight side. W25 G0 read the rim's peak excess by POSITION along each\n * straight side instead and found it graded on every thick cell of both probe\n * grids, on flat solid backdrops where a lens has no gradient to refract: the\n * 1x dark `dark-solid__rrect-md` reads slopes of −0.000192 (top), +0.000192\n * (bottom), −0.000379 (left) and +0.000379 (right) luma per CSS px, and the\n * corner-to-corner range 0.0187 / 0.0226 / 0.0345 on `light-solid` /\n * `dark-solid` / `mid-dark-solid` at span 96 falls to 0.0000 / 0.0016 at spans\n * 32 and 44 and saturates above 96 — the signature of a term on\n * `sizeThickness` and not of the lens.\n *\n * **The field is the product of the two normalised coordinates, and that is\n * what the four slopes say.** A field linear in position — `a·x + b·y` — gives\n * the top and the bottom side the SAME slope in x; the reference's are equal\n * and opposite. `(x / halfWidth) · (y / halfHeight)` gives exactly the measured\n * antisymmetry, is +1 at the top-left and bottom-right corners and −1 at the\n * other two — the same diagonal `rimLitAxis` is symmetric about, which is why\n * this is the position half of one light and not a second one — and predicts\n * the two sides' slope ratio as the box's aspect: 160/96 = 1.67 against the\n * measured 0.000379 / 0.000192 = 1.97, where a metric diagonal would predict\n * 1.0. Reading the reference's two sides through it gives 0.62 (top) and 0.73\n * (left) for this constant, which is the agreement a 56 CSS px straight side\n * on a six-code contrast supports.\n *\n * The factor is `1 + rimAlongSideSlope · sizeThickness(span) · field`, applied\n * beside W24's `lit` factor and outside W23's amplitude bracket. Two\n * consequences are exact rather than approximate. **The field's mean over every\n * straight side is zero**, because the product is odd in the coordinate that\n * runs along the side, so W23's and W24's straight-span amplitudes keep their\n * fitted meaning and the CSS tier — whose one inset shadow cannot vary around a\n * contour — is coherent with the GPU tier's side mean without carrying the term\n * at all. **It is exactly 0 at or below `sizeSpanMin`**, so `rrect-sm` and every\n * thin control are untouched by construction; the capsule's span of 44 takes\n * 0.0923 of it, which is the thin end's whole exposure.\n *\n * At 0 the factor is exactly 1 everywhere, so a profile that does not carry\n * this constant renders the W24 material byte for byte.\n */\n readonly rimAlongSideSlope: number;\n /** Inner-shadow depth (0..1) and how much of it is applied. */\n readonly shadowDepth: number;\n readonly shadowAlpha: number;\n /** Highlight colour for the sweep and press glow, linear light. */\n readonly highlight: Rgb;\n}\n\n/** The rim a `border: \"strong\"` policy substitutes, whatever the variant asked for. */\nexport interface MaterialRim {\n readonly rimWidth: number;\n readonly rimAlpha: number;\n}\n\n/**\n * The outer shadow (W8) — the material's own occlusion of the backdrop *outside*\n * its contour, and the largest single facet the project has measured.\n *\n * Not the same quantity as `MaterialOptics.shadowDepth`/`shadowAlpha`, which are\n * the *inner* shadow: that one darkens the material's own body near its contour,\n * this one darkens what is behind and beside the surface. Profile-level rather\n * than per-variant, because the bed measures it per profile and never varied the\n * variant.\n *\n * ## The mechanism, as measured\n *\n * The reference's shadow is the component's OWN rounded silhouette, outset by\n * `spreadPx`, translated down by `offsetPx`, blurred by a Gaussian of standard\n * deviation `sigmaPx`, and applied MULTIPLICATIVELY: the backdrop keeps\n * `1 − occlusion·falloff` of its own light. Fitted in two dimensions against the\n * active bed, that model reproduces the reference to an RMS of 0.0021 in\n * occlusion over 142,550 pixels on the finest cell, and the same three lengths\n * describe every profile, backdrop, span and scale in the bed.\n *\n * ## Two terms on ONE falloff (W14 G0, claims §5.62)\n *\n * The description above holds where W8 measured it and misses two things the bed\n * has since shown, both of which live in the AMPLITUDE and neither of which\n * moves a length. Outside the coverage, in the compositing (encoded) domain:\n *\n * out = bg · (1 − α_b(backdrop, span) · F(d)) + A_v(span) · F(d) · V\n *\n * with **one** falloff `F` — W8's own, at 15.55 / 7.95 / 3.1, re-read free and\n * unmoved on both terms (σ 14.8–16.2 and offset 7.93–8.00 for the black term,\n * σ 14.1–17.1 and offset 7.6–8.4 for the lift) — and `V` the backdrop's own\n * light blurred at `liftBlurSigmaCss`.\n *\n * The first term's amplitude ADAPTS below the knee: the reference's fill alpha\n * is 0.33 over the mid backdrops, 0.127 over `light-solid` and nothing over\n * black, keyed on the SAME backdrop luminance statistic W9's face response uses\n * (the ENCODED-space mean, decoded — `backdropToneAnchorX`'s own axis), through\n * the same thickness curve that gates that regime. Above the knee it is the\n * composite's transmission by span. The second term is the lift, GPU-tier only,\n * and it is exactly zero below the knee and exactly zero over black, so the\n * facet's \"invisible over a black backdrop\" property survives both terms.\n *\n * The layer tree's `inputShadowAmount` and `inputShadowHeight` are NOT either\n * term's spatial extent — the charter's advisory was wrong there, and G0's free\n * fits overturned it. Only `inputShadowBlurRadius` 40 belongs to the lift, as\n * the blur of the backdrop it copies.\n *\n * **Multiplicative, and not additively.** Mirrored pixel pairs either side of a\n * capsule over the `photo` backdrop see the same shadow over different backdrop\n * luminances: the darkening's ratio tracks the backdrop's ratio to 4.5% while a\n * constant-subtraction model misses by 79% of the signal. So the shadow is\n * analytically INVISIBLE over black — `dark-solid` cells are byte-identical to\n * their background — and that property is what both tiers reproduce exactly,\n * because a fully transparent black composited over anything leaves it alone and\n * black times anything is black.\n *\n * ## Lengths, in points\n *\n * Every length below is in CSS px and the 2× bed proves it: `sigmaPx` measures\n * 15.5 at 1× and 31.0 at 2× device px, `offsetPx` 7.9 and 15.8. A shadow\n * specified in points is what doubles that way.\n *\n * They are also SPAN-INVARIANT, which is a positive measurement rather than an\n * absence: across spans of 32, 44, 96 and 160 px the fitted σ stays within\n * 15.4…15.9 and the offset within 6.9…8.1. The size law reaches the amplitude\n * (`sizeGain`) and nothing else.\n */\nexport interface MaterialOuterShadow {\n /** Downward translation of the shadow's silhouette, CSS px. */\n readonly offsetPx: number;\n /**\n * Gaussian σ the silhouette is blurred by, CSS px. A `box-shadow` blur is 2σ.\n *\n * Since W30 G2 this is the σ at the reference span rather than the σ full\n * stop: the three leaves below grade it with the casting span, and at their\n * inert defaults the law returns exactly this number for every span. The\n * header above records the macOS 26.5 material's own span-invariance as a\n * positive measurement, which is why that material can go on expressing\n * itself with three zeros.\n */\n readonly sigmaPx: number;\n /**\n * The σ law's slope: CSS px of σ per CSS px of casting span, dimensionless.\n *\n * macOS 27 blurs the outer shadow wider under a wider surface. Over spans 96\n * to 160 the measured σ is linear in the span on every bed of the macOS 27\n * capture — slope 0.128 to 0.134, holding to 2 % on the median and scale-\n * invariant in CSS px to 11 % at its worst cell (claims §5.156 §2) — while\n * the shipped single σ draws 4.2 to 7.2 times too wide below span 96 and\n * about a third too narrow at 128 and above. The whole law is\n *\n * σ_css(span) = sigmaPx + max(sigmaThinOffsetPx,\n * sigmaSlopePerSpan · (span − sigmaSpanRefPx))\n *\n * evaluated PER CASTER: the GPU tier reads the casting surface's own span per\n * pixel from the field pass's `shadowAux.z`, and the CSS tier writes one blur\n * radius per surface from `surface.spanPx`. It takes no device ratio, because\n * the cut rejected the device-px reading of the thin regime in both directions\n * (§5.156 §2's two signatures) — one function of CSS span is one mirror fewer\n * for the CSS tier to keep.\n *\n * **Ships at 0, which is a multiplied zero**: the whole span term is\n * `0 · (span − sigmaSpanRefPx)`, so the `max` sees two zeros and σ is\n * `sigmaPx` identically, at every span and every scale. Fitted in the macOS 27\n * documents by claims §5.159; the frozen macOS 26.5 material keeps the zero,\n * where it is the measurement.\n */\n readonly sigmaSlopePerSpan: number;\n /**\n * The casting span, CSS px, at which σ equals `sigmaPx` — the span the line\n * pivots about.\n *\n * The law has one flat direction: shifting `sigmaPx`, `sigmaThinOffsetPx` and\n * this constant together leaves σ unchanged at every span, so a fit has to\n * hold one of the three. **The fit holds this one, at 96** (W30 Decision Log\n * 3 (c)) — the span every bed carries sixteen cells at, and the span the\n * amplitude's own anchor `thickOcclusionAt96` is keyed to — and fits the slope\n * and the offset around it, refitting `sigmaPx` as the σ at span 96.\n *\n * **Ships at 0**, which is unreachable while the slope is 0 and which the\n * identity does not depend on: a pivot multiplied by a zero slope contributes\n * nothing whatever its value. 96 is the fit's value in claims §5.159, not the\n * default's.\n */\n readonly sigmaSpanRefPx: number;\n /**\n * The width the thin regime holds, CSS px, SIGNED, stated as an offset from\n * `sigmaPx` — the floor the line is clamped below at.\n *\n * A floor is structurally necessary rather than a fit of the thin cells: the\n * measured line crosses zero at a span of 23.6 to 30.4 on every bed and the\n * smallest declared span in the bed is 32, so without one the law emits\n * 0.27 CSS px on a 32 px surface and a negative σ on a 24 px one\n * (claims §5.156 §2).\n *\n * **Its unit is CSS px and its value is a declared reading rather than a fit**\n * (W30 Decision Log 2 (b)). The thin cells are a position on the instrument's\n * valley, not a measurement of Apple's blur: the reader's (amplitude, σ) pair\n * trades at a nearly constant product there, and the thin σ bifurcates on the\n * author's TINT — untinted cells read a 1x/2x ratio of 1.86–2.57 and their\n * tinted siblings 0.51–0.56 on the same geometry, which the material's blur\n * cannot depend on. So no order statistic over those cells is a measurement,\n * and §5.159 sets this by declaration with the statistic it is checked\n * against named.\n *\n * **Ships at 0**, an added zero under a `max` whose other arm is also zero.\n * The knee — where the floor gives way to the line — is DERIVED from the three\n * (`sigmaSpanRefPx + sigmaThinOffsetPx / sigmaSlopePerSpan`) rather than being\n * a fourth leaf, because a knee stated beside a slope and a floor is a third\n * name for a quantity two of them already fix.\n */\n readonly sigmaThinOffsetPx: number;\n /** Outward spread of the silhouette before the blur, CSS px. */\n readonly spreadPx: number;\n /**\n * The black term's peak occlusion below the knee, over a backdrop the material\n * cannot see (linear luminance ≤ `OUTER_SHADOW_THIN_L.inert`): zero. Inert\n * over `dark-solid` and `impulse`, which is what the reference does — it\n * removes at most one or two of 255 codes there (claims §5.62 §5).\n */\n readonly thinOcclusionDark: number;\n /**\n * The black term's peak occlusion below the knee over the MID plateau —\n * backdrop linear luminance `OUTER_SHADOW_THIN_L.midFrom` … `midTo`.\n *\n * MEASURED (claims §5.62 §5): linear occlusion 0.347 over `mid-dark-solid`,\n * 0.334–0.339 over `photo`, 0.327–0.328 over the checkerboard and 0.329 over\n * `hc-text` — flat across a backdrop luminance range of 0.06…0.74, and a\n * constant 1.16–1.19× the fill alpha §5.50 §2 read off the layer tree.\n */\n readonly thinOcclusionMid: number;\n /**\n * The black term's peak occlusion below the knee over a BRIGHT backdrop, at\n * `OUTER_SHADOW_THIN_L.bright` and above.\n *\n * MEASURED (claims §5.62 §5): 0.127 over `light-solid` (linear luminance\n * 0.891), against the layer tree's tabulated 0.05 — so the reference's shadow\n * there is 0.39 of its shadow over the checkerboard, not one sixth. W8's\n * single 0.285 everywhere is 2.24× this, which is the whole of the user's\n * by-eye \"the shadow is darker on the light-solid capsule\" and, by the free\n * geometry fit on that cell (σ 14.81 / offset 7.97 / spread 3.17), no part of\n * it is shape.\n */\n readonly thinOcclusionBright: number;\n /**\n * The COMPOSITE occlusion above the knee at a casting span of 96 CSS px.\n *\n * FITTED in the renderer (claims §5.65), from G0's measurement of the\n * composite's transmission (0.379 on the checkerboard at span 96) to **0.370**.\n * It had to be fitted rather than adopted, because what G0 could identify at\n * the bed's noise floor is the composite transmission and the lift's peak\n * amplitude, not the split into (black alpha, vibrant alpha, vibrant colour):\n * both terms ride one falloff and their shapes correlate at 0.9998. So this\n * constant is the BLACK term of a two-term composite whose second term\n * (`liftAmplitude`) was fitted beside it, on X7's affine pair, and the pair is\n * what the referee reads.\n */\n readonly thickOcclusionAt96: number;\n /** The same at a casting span of 128 CSS px — FITTED to 0.448 from G0's\n * measured 0.497, for `thickOcclusionAt96`'s reason (claims §5.65). */\n readonly thickOcclusionAt128: number;\n /**\n * The same at a casting span of 160 CSS px — **UNFITTED**, and the one anchor\n * in this block that no calibration cell reaches.\n *\n * Every span above 128 in the bed is holdout, so 0.479 is carried by the stated\n * derivation from the two fitted anchors and not by a fit. The holdout, read\n * once and fitted to nothing, says it is 15% heavy (band `1 − a` 0.2436 against\n * the reference's 0.2117) and implies about 0.437 — which is BELOW the fitted\n * At128 and which no extrapolation from the calibration cells would have\n * produced. That reading is recorded and deliberately not adopted (claims §5.65\n * §4(b) and §6(iv)); closing it needs a calibration cell above span 128.\n */\n readonly thickOcclusionAt160: number;\n /**\n * **The lift (W14)** — the peak amplitude of the second term, in LINEAR light,\n * as a fraction of the backdrop's own blurred luminance. GPU tier only.\n *\n * The reference's thick shadow does not only remove light: on the\n * checkerboard's black squares, where a multiply is inert by construction, it\n * ADDS 7.4 of 255 (claims §5.62 §2). Pooled over six backdrops the addition\n * regresses on the σ-40 blurred backdrop at slope 0.0444 with intercept\n * −0.0042 and R² 0.983 — it is the backdrop's own light, blurred, composited\n * under the shadow, with no fixed colour left over. Zero over `impulse`, zero\n * over `dark-solid`, and zero below the knee, so the facet stays exactly inert\n * over black the way W8's multiply is.\n *\n * FITTED to **0.0100** in the renderer over seventeen sweep passes, read on\n * X7's affine pair together with the three thick anchors (claims §5.65). The\n * provisional 0.0073 was G0's +0.0038 of LINEAR lift at span 160 divided by\n * the ≈ 0.52 linear luminance the checkerboard's σ-40 blur sits at, and the fit\n * is 37% larger. The space matters and this wave names it everywhere (claims\n * §5.62 §3): §5.60's +0.039 is the same lift read in ENCODED luma.\n */\n readonly liftAmplitude: number;\n /**\n * Where the lift starts, in casting span, CSS px — the thin/thick knee, and it\n * is exact: the lift reads 0.0000 at spans 32 and 44 and is present at 96\n * (claims §5.62 §2). The layer tree's own `VibrancyContribution` clamps from\n * the same 64.\n */\n readonly liftSpanMin: number;\n /**\n * Where the lift saturates, in casting span, CSS px.\n *\n * FITTED to **118** (claims §5.65), from a provisional 128. The measured rise\n * is 0.52 / 0.96 / 1.00 of the span-160 value at spans 96 / 128 / 160, against\n * the layer tree's clamp((span − 64)/96) = 0.33 / 0.67 / 1.00 — so the lift is\n * NOT proportional to `VibrancyContribution`; it rises and saturates, reaching\n * 96% by span 128 (claims §5.62 §2), which a smoothstep from `liftSpanMin`\n * reproduces and the clamp does not. The holdout says the reach saturates a\n * little early — the lift's own residual there is one-signed and small, 5% low\n * at span 130 and 9% at 160 (claims §5.65 §4(d)) — and it was not refitted\n * after that reading.\n */\n readonly liftSpanFull: number;\n /**\n * The σ, in CSS px, of the blur the lift copies the backdrop through.\n *\n * MEASURED at 40 ± 8 CSS px on `rrect-lg` at both scales and in two rings, by\n * the probes' pitch axis — the pooled residual has a real minimum there, 12%\n * below the flat-copy residual (claims §5.62 §3). It is the layer tree's\n * `inputShadowBlurRadius` 40 read as a Gaussian standard deviation. NOT\n * identifiable on the mid spans (flat to 0.7%), and reported as such rather\n * than fitted there.\n */\n readonly liftBlurSigmaCss: number;\n /**\n * The shadow's amplitude UNDER reduced transparency — one absolute linear\n * occlusion that replaces both regimes, not a factor on either. MEASURED,\n * which is what the charter asked for before the fold was written.\n *\n * **0.197 (measured 0.192–0.202).** W14 G0 read the preference on the wider\n * bed and what it found is a flat number: the reference's exterior is\n * 0.192–0.202 under increased contrast and reduced transparency alike, **thin\n * and thick together** and over every backdrop it can be read on (claims §5.62\n * §5). The preference removes the material's adaptation, so the shadow it\n * leaves has neither the thin regime's backdrop keying nor the thick regime's\n * span law in it — one amplitude for every surface over every backdrop, which\n * is what `outerShadowUnderPolicy` writes into all six anchors. The lift goes\n * with it: a composite whose two regimes read the same number has no second\n * term left in it.\n *\n * It is stated as an ABSOLUTE occlusion rather than as a ratio because W8's\n * 0.70 multiplier was fitted when the amplitude was one span-flat number and a\n * ratio was the same thing as a level. It is not any more: multiplying six\n * unequal anchors keeps exactly the backdrop and span variation the preference\n * removes, and a span-160 surface over a mid-tone backdrop folded to 0.38\n * against the reference's 0.20. The number the reference states is a level, so\n * this constant is a level.\n *\n * Nothing is special-cased for a dark backdrop and nothing needs to be: an\n * occlusion is a fraction of the backdrop's own light, so a flat 0.197 over\n * black still removes nothing, and the facet stays as inert there as the thin\n * regime's own zero anchor makes it without the preference.\n *\n * The `increased contrast` reference reproduces the reduced-transparency\n * amplitude to four decimals (0.1830, 0.1884, 0.1882 on the three structured\n * backdrops at a 44 px span, with σ, offset and spread unmoved), which is\n * Decision Log 8's finding again: macOS force-couples the two toggles, so the\n * contrast reference IS the reduced-transparency state and the bed cannot\n * separate them. The fold therefore keys on `frost`, the axis reduced\n * transparency alone sets, rather than on the contrast axes it would be\n * indistinguishable on here.\n */\n readonly reducedTransparencyOcclusion: number;\n /**\n * The size law's grip on the amplitude: the fraction of the REMAINING\n * transparency a full-thickness surface's shadow closes, on\n * `sizeOcclusionGain`'s relative form.\n *\n * Ships at 0 — the identity — and the reason is a measurement rather than an\n * absence of one. Fitted per scene at a frozen geometry, the amplitude's span\n * dependence points in OPPOSITE directions in the two colour schemes: light\n * standard falls from 0.326 to 0.196 between a 44 px and a 96 px span over\n * `photo` (and 0.331 → 0.285 over `checkerboard`, 0.331 → 0.245 over\n * `hc-text`), while dark standard RISES from 0.060 to 0.177 to 0.274 across 44,\n * 96 and 160 px. Under reduced transparency it is flat (0.183, 0.192, 0.165).\n * One monotone gain on one thickness curve cannot be all three, and any\n * non-zero value fitted to one scheme is wrong in the other — the same shape of\n * finding Decision Log 13 recorded for W7's curve (\"surface size is its own\n * axis\"). The seam ships so the cascade can fit it if a two-axis rework lands;\n * the value stays at the identity until something can identify it.\n */\n readonly sizeGain: number;\n}\n\n/**\n * Every number the material runs on, in one place.\n *\n * The same seam `@vitrea/motion`'s `MotionProfile` opens for the drivers, for the\n * optics: C7's harness measures these against `apple-macos-26.5-*` fixtures and\n * replaces what is here, so nothing downstream may hard-code an optical constant\n * of its own. A profile overrides every one of them (`withMaterialOverrides`),\n * which makes landing a calibrated set a data change rather than a code change.\n *\n * Units: CSS px for distance, linear light for colour, viewport coordinates with\n * y pointing down for direction.\n */\nexport type BackdropToneKnotRow =\n | readonly [number, number, number]\n | readonly [number, number, number, number];\n\nexport interface MaterialOcclusionLiftByPolicy {\n readonly reduceTransparency: number;\n readonly increaseContrast: number;\n}\n\nexport interface MaterialProfile {\n /** Per-variant optics. `clear` is persistently more transparent than `regular`. */\n readonly optics: Readonly<Record<MaterialVariant, MaterialOptics>>;\n\n /** The two ends of adaptation: what the tint becomes over a dark and a light backdrop. */\n readonly adaptiveTintDark: Rgb;\n readonly adaptiveTintLight: Rgb;\n /** Luminance band the tint crosses over. Hysteresis in time is the driver's job. */\n readonly adaptiveLuminanceLow: number;\n readonly adaptiveLuminanceHigh: number;\n\n /**\n * How much of the lens the shader is allowed to apply, per rung.\n *\n * `approximate` is not \"half of true\": it is the rim-lensing approximation, a\n * shallower bend confined nearer the edge, which is what a group sampling a CSS\n * proxy can honestly claim. Reduced transparency lands here too, which is the\n * point of the ladder having three rungs and not two.\n */\n readonly refractionScale: Readonly<Record<RefractionQuality, number>>;\n\n /**\n * **The size law's one curve** — the span band over which the material stops\n * reading as a thin sheet and starts reading as a thick slab (W2).\n *\n * Apple states one mechanism and lists its consequences: as glass \"morphs to\n * larger sizes… its material characteristics change to simulate a thicker, more\n * substantial material. It casts deeper, richer shadows, has more pronounced\n * lensing and refraction effects, and a softer scattering of light\" (S219). One\n * mechanism means one curve: `sizeThickness(span)` is a smoothstep from\n * `sizeSpanMin` to `sizeSpanMax`, and the thickness-derived facets are gains\n * on it — the lens (`lensSizeGainMax`), the occlusion (`sizeOcclusionGain`)\n * and the inner shadow (`sizeShadowGainMax`). The scattering was one of them\n * until W11c measured its curve to be a different one (a floor at small\n * spans, a rise past 96) and W13 measured that curve to be the projection of a\n * ramp in depth — see `sizeScatterFloor` and `sizeScatterRampStartThin1x`; the\n * scattering now rides its own law entirely, and this band is untouched by it.\n *\n * A smoothstep rather than a straight ratio, so two surfaces of nearly the same\n * size never read as differently thick, and so every gain saturates instead of\n * growing without bound on a full-width platter. Below `sizeSpanMin` the whole\n * law is **exactly inert**: a small control renders as it did before the law\n * existed, which is what makes the law additive rather than a global retune.\n *\n * MEASURED (W2, on the settled bed): the band is where the reference's own\n * size-dependence happens. Over a fixed checkerboard backdrop the light-standard\n * reference passes 0.244 of the backdrop's contrast at a 32 px span, 0.230 at\n * 44 px and 0.144 at 96 px, and its backdrop correlation falls 0.634 → 0.606 →\n * 0.475 across the same three — so the movement is essentially complete by 96 px\n * and has barely started at 32. See the claims doc's size-law section.\n */\n readonly sizeSpanMin: number;\n readonly sizeSpanMax: number;\n\n /**\n * The inner shadow's depth gain on the size curve — and, until W12 G2, the\n * lens's too.\n *\n * The inner shadow's depth is `thickness × (1 + (lensSizeGainMax − 1) ×\n * sizeThickness)`, clamped to the shorter *half* extent, and its profile is\n * `(1 − depth)²` on that depth: the landed law of W2, kept byte-for-byte for the\n * occlusion because nothing measured it as wrong. The LENS no longer reads it —\n * the reference's own lens height is a clamped linear function of the span\n * (`lensHeightPerSpan`, `lensHeightMax`), read straight from its layer tree\n * (claims §5.50), and the lens takes that law from W12 G2 on. The name stays so\n * the profile documents keep naming the constant they measured.\n */\n readonly lensSizeGainMax: number;\n\n /**\n * The scattering gain — \"a softer scattering of light\". How many times wider\n * the material's body blur runs at full size.\n *\n * **The facet the settled bed identifies most directly.** Two backdrops\n * disagree in exactly the way a widening kernel predicts and an opacity change\n * does not. Over the checkerboard — all of whose structure sits at one 16 px\n * period, and whose surroundings carry the same mean as its interior — the\n * reference's retained contrast falls 41% from a 32 px span to a 96 px one while\n * its interior *level* stays put (0.607 → 0.641). Over the synthetic photo —\n * broadband, and with surroundings whose mean differs from the mask's — the\n * retained contrast barely moves between 44 px and 96 px (0.546 → 0.544) while\n * the level converges toward the neighbourhood (0.585 → 0.628). A larger alpha\n * would have moved both backdrops' contrast together and pulled both levels\n * toward the tint; a wider kernel moves exactly what moved.\n *\n * Both tiers carry it, from one function (`sizeScatterSigma`): the CSS tier\n * multiplies its `blur()` σ, and the GPU tier lerps its body sample toward the\n * chain level whose blur is that σ.\n *\n * MEASURED (W11c G1, claims §5.41), and no longer a gain on `sizeThickness`\n * alone — see `sizeScatterFloor` and `sizeScatterRampStartThin1x` below for the\n * law it rides. 8: the heavy component of the reference's interior sits near\n * σ 10 device px against a body σ of 1.25, and the gain sweep has a clear\n * minimum at 8 (RMS 0.0164 against 0.0180 at 6 and 0.0191 at 10 on the probe\n * bed).\n *\n * **INERT on the GPU tier at any material that names a heavy width** (W26;\n * claims §5.122 §6a). This constant reaches the deep sample only through\n * `scatterLod`, and where `sizeHeavyTapSigma` is non-zero the optics pass\n * overwrites that sample with the heavy texture — measured, not argued: fifty\n * rows byte-identical between `sizeScatterGainFar2x` 9.9 and 4.8 at the landed\n * width. It is KEPT and not retired because retiring it means deciding what a\n * profile naming NO heavy width draws, which is a code-removal wave with no\n * fidelity content (W26 Decision Log 6 (b)); the tracker carries it. The CSS\n * tier still reads it for the same reason — the collapsed single-`blur()` form\n * and the sampling-padding projection, where no heavy width applies.\n */\n readonly sizeScatterGainMax: number;\n\n /**\n * **The scattering facet's frost** (W11c G1, claims §5.41; re-read by W13 G1).\n *\n * The reference's interior over structured content is two components, read\n * off the W9 probe bed across four checkerboard pitches and five spans: a\n * sharp one near σ 1.25 device px and a heavy one near σ 10, mixed by a share\n * that is already ≈ 0.4 at spans of 32–44 and still rising at 160. W11c\n * carried that mix as one number per span, a floor rising by a smoothstep to\n * a band top (`sizeScatterSpanMax`); W13 G0 measured the mix **per depth** on\n * both probes and found a ramp under the contour that the span law had been\n * summarising (claims §5.61 §2). W13 G1's first form replaced the span law\n * with the ramp outright and its runtime sweep refuted that: the ramp's own\n * projection onto one number per surface runs 0.43–0.56 where the span law it\n * replaced runs 0.41–1.00, so a ramp with a start and a reach is nearly\n * span-flat where the bed is strongly span-graded, and no point in 81 reached\n * the wave's stops (`results/2026-09-03-w13-ramp/g1/sweep/g1-sweep.md` §4,\n * §7). So the two are kept **together**: the span law is the ramp's DEEP\n * value and the ramp is a near-contour excursion above it. This floor is\n * unchanged in value and in meaning under either: the mix a surface carries\n * at any size, the material's own frost.\n *\n * It keeps its fold semantics, and they are now written on the ramp rather\n * than on a span curve:\n *\n * ```\n * kScatter(u) = floor + (k(u) − floor) · fold\n * ```\n *\n * — so at fold 1 the ramp is rendered exactly and at fold 0 the material sits\n * at this floor exactly, which is what the landed law did at fold 0 too. The\n * floor is the frost the material has whatever its size, and is **not**\n * folded under an accessibility preference; the excursion away from it is\n * depth, and is. Fitted with `rrect-lg` held out (W11c G1): 0.40 (0.0175 at\n * 0.3, 0.0174 at 0.45).\n */\n readonly sizeScatterFloor: number;\n\n /**\n * **The scattering facet's span curve** (W11c G1, claims §5.41) — the top of\n * the band the frost rises to, and, since W13 G1's re-forming, the span law\n * that supplies the depth ramp's DEEP value:\n *\n * ```\n * kDeep(span) = floor + (1 − floor) · smoothstep(sizeSpanMin, sizeScatterSpanMax, span)\n * ```\n *\n * — byte for byte the curve W11c fitted and W13 G1's first form retired. It\n * came back because the sweep measured what retiring it cost (§4 of\n * `results/2026-09-03-w13-ramp/g1/sweep/g1-sweep.md`): the span dependence of\n * the bed is real and strong, and the ramp's four constants cannot carry it\n * at the same time as the band's near-contour excursion. What the ramp adds\n * is what this curve never could — the depth structure inside one surface —\n * and it now adds it on top of this rather than instead of it, so the deep\n * interior of every span is exactly where W11c and W12 put it.\n *\n * `sizeThickness` — zero at `sizeSpanMin` and saturated at `sizeSpanMax` = 96\n * — can express neither the floor nor a band top past 96, and moving\n * `sizeSpanMax` would move the lens, the occlusion, the inner shadow and W9's\n * thin/thick response rows with it, which is why the scatter mix has its own\n * curve at all. Fitted with `rrect-lg` held out (W11c G1): band top 256\n * (0.0182 at 224, 0.0174 at 320); the held-out cell's residual 0.0366 →\n * 0.0174.\n */\n readonly sizeScatterSpanMax: number;\n\n /**\n * **The body's second scale** (W15 G1, from the measurement of claims §5.69\n * §1–§2) — the heavy width's gain, the deep value's floor and the deep\n * value's span top, each read again at dpr 2.\n *\n * At 2x the reference's body is a different object from the one the three\n * constants above describe, and §5.69 measured all of it: the deep interior\n * is FULLY heavy on the two largest spans and 0.90–0.95 heavy on `rrect-md`\n * (§2), where the 1x span curve leaves a sharp share of 0.24–0.36 there, and\n * the heavy component's own width is 8–11 device px against the 1x law's 10\n * CSS px (§1). One curve fitted at 1x cannot be both, so the deep value's two\n * constants and the gain get a second reading rather than a scale factor —\n * the same shape the ramp's anchors already have.\n *\n * Each is interpolated by `rampAtScale`: held at the 1x constant at dpr ≤ 1,\n * at this one from dpr 2 up, linear between. **At dpr 1 every one of them is\n * inert by construction, whatever it says** — W15's binding rule — so the 1x\n * material is byte-identical to the W13 bed and the landing's confirmation\n * measured exactly that: 49 of 49 1x GPU cells identical to the bed with\n * every capture byte-identical (claims §5.70 §8).\n *\n * Consumed at draw time, not folded into a constant: `scatterDeepThickness`\n * takes the ratio for the floor and the span top, the renderer resolves all\n * three from the viewport's own ratio and hands them to the optics pass\n * through the uniforms the shader already reads (`scatter.x`, `lensOval.w`\n * and `size.x`), and `scatterThickness`, `scatterSharpShare` and the ramp's\n * area-average projection read the resolved deep value.\n *\n * **FITTED** by W15 G1's runtime sweep at\n * `--profile apple-macos-26.5-2x-light-standard` on the calibration set, the\n * holdout untouched, and landed at the values below (claims §5.70 §2 and §8;\n * the four sweeps `results/2026-09-04-w15-body-2x/g1/stage1..stage3` and the\n * confirmation `confirm-3`, whose 2x holdout was read once for this\n * configuration). The rule W13 wrote after the paper model over-credited the\n * mip chain's heavy tap (§5.58 §1) held: no constant here lands on a paper\n * prediction, and the sweep contradicted the paper estimate.\n *\n * **The gain, 4.8.** Stage 2c swept it over 4.0 / 4.4 / 4.8 / 5.2 at the\n * chosen base and found an INTERIOR MINIMUM at 4.8 — the interior spread\n * against native reading 0.0335 / 0.0214 / 0.0120 / 0.0217 with the band's\n * rise at its top too. Through `bodySigmaCssFor` that is a heavy width of\n * **6 device px** at dpr 2, NARROWER than the 8–11 device px §5.69 §1\n * bounded as a Gaussian: the estimator carries ±40% on a real capture of a\n * known law (§5.69 §3) and the mip chain's tap is not a Gaussian, so the\n * renderer is the fitting instrument and 6 is the width it draws best.\n *\n * **The floor, 1.0** — the deep value FULLY heavy at dpr 2, which is what\n * G0's deep windows read on the two largest spans (§5.69 §2). `kDeep` is\n * therefore 1 at every span at this ratio, and the depth ramp above it is the\n * whole body (§5.70 §1).\n *\n * **The span top, 256** — the 1x value, unchanged, because a floor of 1\n * leaves the deep value nothing to rise to and the top has no work at this\n * ratio. Stage 1 swept it against 128 and the bed did not ask for the change.\n *\n * **The gain is INERT on the GPU tier at any material that names a heavy\n * width** (W26; claims §5.122 §6a), for `sizeScatterGainMax`'s reason and with\n * the same measurement behind it. The floor and the span top above are NOT —\n * they grade the deep value's SHARE, which the heavy texture does not touch.\n */\n readonly sizeScatterGainMax2x: number;\n readonly sizeScatterFloor2x: number;\n readonly sizeScatterSpanMax2x: number;\n\n /**\n * **The heavy width's gain at the TOP of the scatter span curve, at dpr 2**\n * (W15 G1's re-form, from claims §5.70 §4 and §7 and the measurement of\n * §5.69 §1) — the second-scale term that lets the 2x heavy width GROW with\n * the span instead of being one number for the whole bed.\n *\n * `sizeScatterGainMax2x` above is one gain at dpr 2, and the sweep that fitted\n * it read the calibration cells, whose spans are 32–128. The reference's heavy\n * kernel is not one width: §5.69 §1's bounded per-span fit reads 8.0 / 7.5 /\n * 8.0 / 9.0 / 11.0 device px across the bed's spans, a ratio of 1.375 between\n * span 160 and span 96. Landing the single gain accordingly left the largest\n * span's deep interior about 40% too structured (`rrect-lg` at 2x, spread\n * 0.1134 against the reference's 0.0810, claims §5.70 §4) while every smaller\n * cell rose. So the gain takes a second grading, in SPAN:\n *\n * ```\n * gain(span, dpr) = gainAtScale(dpr)\n * + (gainFar(dpr) − gainAtScale(dpr))\n * · smoothstep(sizeSpanMax, sizeScatterSpanMax(dpr), span)\n * ```\n *\n * with `gainAtScale` the existing `scatterGainAtScale` and `gainFar` this\n * constant interpolated by `rampAtScale` from `sizeScatterGainMax`. The curve\n * is not a new span statistic: it is the same smoothstep the fourth form's\n * far-anchor decline already rides (`scatterRampStart`), so the width and the\n * ramp's start move along one curve above the thickness knee.\n *\n * **Inert at dpr 1 by construction.** `gainFar` interpolates from\n * `sizeScatterGainMax` — the 1x gain, not this constant — so at dpr ≤ 1 the\n * far gain IS the base gain and the whole term is a flat no-op whatever this\n * says. That is W15's binding rule (the 1x material does not move) discharged\n * by the shape of the formula rather than by a capture.\n *\n * **LANDED at 9.9** (claims §5.70 §8; W15 Decision Log 3, the user's landing\n * \"the re-form\"), and the value is G0's rather than the holdout row's: §5.69\n * §1's bounded per-span reading is 8 device px at span 96 and 11 at 160, a\n * ratio of 1.375, and this curve reads 0.352 at span 160, so 4.8 + (9.9 −\n * 4.8) · 0.352 reproduces that ratio over the base gain of 6 device px. The\n * heavy width at dpr 2 is therefore 6.0 device px at spans ≤ 96, 6.7 at 128,\n * 8.2 at 160 and 12.4 at 256 and beyond. The calibration cells neither chose\n * the value nor rejected it — `stage3` swept 4.8 / 7.5 / 9.9 / 12.5 and only\n * `rrect-ml` (span 128, a tenth of the grading) moves, its interior spread\n * 0.1125 → 0.0993 against native 0.1018 at 9.9, which is the sweep's best on\n * its own objective. The confirmation's holdout `rrect-lg` rose 0.9661 →\n * 0.9762 with its interior spread 0.0721 against native 0.0810.\n *\n * **INERT on the GPU tier at any material that names a heavy width**, and this\n * is the one of the three whose silence costs something (W26; claims §5.122\n * §§3, 6a). It is the constant that graded the 2x heavy width with the span,\n * and the heavy texture is one width per SOURCE, so where a heavy width is\n * named there is nothing left for it to grade: fifty rows byte-identical\n * between 9.9 and 4.8 at the landed width. What that gives up is measured on\n * the instrument of record rather than estimated — the reference wants **1.66\n * device px more heavy width at span 160 than at span 96 at dpr 2**, 20 % of\n * the smaller, and W26 lands one number inside 11 % of each instead. That is\n * W26 Decision Log 2 (f)'s recorded gap, now with a size; the constant is kept\n * against the profile that names no heavy width and against the wave that\n * makes the width per surface.\n */\n readonly sizeScatterGainFar2x: number;\n\n /**\n * **The body's depth ramp** (W13 G1, from the measurement of claims §5.61 §2\n * and the re-forming its runtime sweep forced) — a near-contour excursion on\n * the sharp component's share, riding on top of the span law\n * `sizeScatterSpanMax` supplies rather than replacing it.\n *\n * ```\n * kDeep(span) = sizeScatterFloor + (1 − sizeScatterFloor)\n * · smoothstep(sizeSpanMin, sizeScatterSpanMax, span)\n * sDeep(span) = 1 − kDeep(span)\n * s₀(span) = startThin + (startThick − startThin) · sizeThickness(span)\n * s(u, span) = sDeep + max(0, s₀(span) − sDeep) · max(0, 1 − u / U(dpr))\n * k(u, span) = 1 − s(u, span)\n * ```\n *\n * with `u` the pixel's depth under the contour and `U` the reach, both in\n * DEVICE px. `s₀` is the sharp share **at the contour** and `U` is where the\n * excursion vanishes into the deep value — not where a line from the start\n * would hit zero, which is what the first form's reach meant. Deep inside any\n * surface the body is exactly the W11c/W12 material; within `U` of the\n * contour the sharp component is lifted toward `s₀`, which is the band the\n * reference has and the uniform share does not.\n *\n * **Why the start grades with the span, in the third form.** The second form\n * gave the excursion one start per scale and its runtime sweep refuted that\n * too, arithmetically rather than for want of a better point (claims §5.64\n * §2): `rrect-sm`'s span is exactly `sizeSpanMin`, so its deep sharp share is\n * exactly `1 − sizeScatterFloor` = 0.600 and no start at or below 0.600 can\n * touch it, while `rrect-ml`'s band only improves below a start near 0.583.\n * The window where both hold is empty, and the reach cannot open it — the\n * reach decides how much of a surface the excursion covers, never which\n * surfaces it touches, because `max(0, s₀ − sDeep(span))` has no reach in it.\n * G0 read the reference's start as strongly graded by span (0.637 / 0.642 on\n * the thin cells against 0.512 / 0.501 / 0.410 on the thick ones at 1x), so\n * the start is given exactly that grading — across `sizeThickness`, the\n * material's OWN thin/thick curve with its knee at 64, the one the face's\n * tone response and the outer shadow already blend across. Reusing it is the\n * point: it introduces no new span statistic, and `sizeSpanMax` stays where\n * every other facet reads it.\n *\n * **Why this form and not the ramp alone.** W13 G0 measured a ramp with a\n * free start, reach and floor (H2) and the first implementation took the free\n * start and reach with a floor of zero, retiring the span law. Its runtime\n * sweep — 81 points, both scales, the real renderer — could not reach the\n * wave's stops at any point, and named the mechanism: the ramp's projection\n * onto one number per surface runs 0.43–0.56 at 1x where the retired span law\n * ran 0.41–1.00, so the family is nearly span-flat and the bed is strongly\n * span-graded; small spans want a high start and large spans a low one and no\n * pair can be both (`.../g1/sweep/g1-sweep.md` §4). §7 of the same report\n * asked for exactly this: \"the ramp's DEEP value wants to be the span-graded\n * heavy share the retired law supplied, and its near-contour excursion the\n * sharp term the band asks for.\" The floor H2 left free is therefore not one\n * more constant but the span law itself, which is already fitted.\n *\n * The reach stays a LENGTH in device pixels, which is the reading that did\n * survive the sweep: the free fits' reaches in absolute depth spread by 1.3×\n * across the spans (108 / 115 / 144 CSS px at 1x on `rrect-lg` / `-ml` /\n * `-md`) where the reaches as a fraction of the half-span spread by 2.2×, and\n * between the two scales that length roughly halves in CSS px — one length in\n * device pixels, the same reading as the widths (§5.55 §1, §5.56 §1).\n *\n * The start and the reach are anchored at the two scales the reference was\n * measured at rather than given a scale term: `…1x` is the value at dpr 1,\n * `…2x` at dpr 2, the pair interpolated linearly in dpr and held constant\n * outside [1, 2] (`scatterRampStart`, `scatterRampReachDevicePx`).\n *\n * **The FOURTH form: the start keeps falling past the thickness knee (W13\n * Decision Log 6; claims §5.67 §4, §6).** The third form's holdout failed on\n * one row for the form's own arithmetic: `sizeThickness` saturates at\n * `sizeSpanMax` 96, so spans 96, 128, 130 and 160 all received the identical\n * thick start while G0 read the reference's start FALLING across exactly\n * those spans (0.512 → 0.501 → 0.410), and because the deep value keeps\n * falling to `sizeScatterSpanMax` the excursion GREW with span (0.039 →\n * 0.156 → 0.284) where the reference's shrinks — `rrect-lg` overshot its\n * interior by 33%. So the start gets a slow decline along the scatter\n * facet's own curve above the knee, `startFar` being its value at span ≥\n * `sizeScatterSpanMax`:\n *\n * s₀(span) = thin + (thick − thin) · sizeThickness(span)\n * + (far − thick) · smoothstep(sizeSpanMax, sizeScatterSpanMax, span)\n *\n * Two curves the material already has, one more constant per scale, and no\n * new span statistic. At 2x the decline is switched off rather than inverted:\n * `far` and `thick` carry the same number since W15 G1, because G0 read the\n * reference's 2x start FLAT across the thick spans (claims §5.69 §2, §5.70 §6\n * (iv)) — the decline is a 1x feature of this form.\n *\n * The 1x three are FITTED (W13 G1's third and fourth sweeps) and the 2x four\n * are FITTED or read from G0 by W15 G1 (claims §5.70 §2 and §8); no constant\n * here lands on a paper prediction, because the paper model over-credited the\n * mip chain's heavy tap once already (§5.58 §1). What they carry:\n *\n * **1x — thin 0.64, thick 0.52, reach 120 device px.** G0's own start\n * readings are 0.637 on `rrect-sm` and 0.642 on the capsule at the thin end\n * and 0.512 / 0.501 / 0.410 on `rrect-md` / `-ml` / `-lg` at the thick end.\n * A thick anchor fitted to all three thick cells jointly comes out near 0.47,\n * and 0.47 sits 0.011 *below* `rrect-md`'s own deep sharp share of 0.481,\n * which would clamp the excursion to zero on that one cell. 0.52 is above it\n * and is also G0's reading on that cell, so the fit is not traded against the\n * form's own arithmetic.\n *\n * **2x — thin 0.46, thick 0.21, far 0.21, reach 100 device px, and the ramp\n * is now the WHOLE body above the deep value** (W15 G1, claims §5.70 §1–§2).\n * W13 left these inert for the deep value's sake: at `sizeScatterFloor2x` 0.4\n * every anchor sat below its cell's deep sharp share and `max(0, s₀ − sDeep)`\n * was bit-exactly zero on the whole bed. W15 G1 fitted that deep value fully\n * heavy (`sizeScatterFloor2x` 1.0), so the deep sharp share at dpr 2 is 0 and\n * the anchors act on the numbers they were carrying — which is why the wave's\n * three gaps turned out to be one gap (§5.70 §6 (i)).\n *\n * The values are G0's readings where the sweep was flat and the sweep's where\n * it was not. **Thin 0.46** is G0's u 6 reading exactly (0.494 / 0.468 on the\n * thin cells) and stage 2b's best, over a top nine points within 0.002 of\n * each other. **Thick and far 0.21**: G0's 2x starts on the thick cells are\n * 0.163 / 0.199 / 0.210 at their own widths and 0.192 / 0.199 / 0.195 at one\n * common width — flat with span, not declining — so the two anchors take one\n * number and the fourth form's decline is off at this scale; stage 2a\n * measured the objective flat over 0.17–0.25 and worse at 0.33. **Reach 100\n * device px** = 50 CSS px against G0's measured 49 / 53 / 56, and stage 2b\n * found 100 and 130 indifferent.\n *\n * **far — 0.20 at 1x (FITTED on the W14 bed), 0.21 at 2x.** The fourth\n * sweep (`results/2026-09-03-w13-ramp/g1/sweep-4/`) swept far over eight\n * points from 0.52 (the third form) down to 0.15: S1 and S4 pass at every\n * one, only `rrect-ml`'s rows move and they improve monotonically as far\n * falls, and the band is flat within the bed's noise below 0.30. The cell\n * the constant exists for is holdout, so the tie inside the noise is broken\n * by the reference's own reading — G0's `rrect-lg` start of 0.410 at span 160\n * is far = 0.207 through this form — and 0.20 is the measured grid point that\n * carries it. The confirmation read `rrect-lg` at `ssimMean` +0.0056 against\n * the W14 bed (the third form: −0.0026) with its interior 12% over the\n * reference (from 33% over). At 2x far equals the thick anchor, so the start\n * is flat past the knee at that scale — G0's own reading (§5.69 §2), and the\n * holdout's band supports it (`rrect-lg` +0.0106, claims §5.70 §8).\n *\n * At dpr 1 none of the 2x four is read at all: `rampAtScale` holds every one\n * of them at its 1x anchor below dpr 1, so the 1x material is byte-identical\n * to the W13 bed and the landing's confirmation measured that on 49 of 49 1x\n * GPU cells (claims §5.70 §8).\n */\n readonly sizeScatterRampStartThin1x: number;\n readonly sizeScatterRampStartThick1x: number;\n readonly sizeScatterRampStartFar1x: number;\n readonly sizeScatterRampStartThin2x: number;\n readonly sizeScatterRampStartThick2x: number;\n readonly sizeScatterRampStartFar2x: number;\n readonly sizeScatterRampReach1xPx: number;\n readonly sizeScatterRampReach2xPx: number;\n\n /**\n * **The heavy share's thick end** (W25; claims §5.113, W25 Decision Log 3 (a))\n * — how much heavier the deep value runs on a thick surface than the span\n * curve above makes it, riding `sizeThickness` and read once per scale.\n *\n * W25 G0 measured the reference's kernel as TWO components and found that what\n * separates the thick surface from the thin one is neither width: read on the\n * same cell at 1x the reference's single-Gaussian width is 1.30 device px\n * against a 16 CSS px checkerboard, 4.75 against 32 and 6.25 against 64, where\n * one Gaussian returns one number at every pitch. The dot's own two-component\n * fit on `impulse__rrect-md` reads sharp σ 2.79 and heavy σ 19.52 device px at\n * 1x and 1.40 / 11.29 at 2x — both components HALVING in device px — with the\n * heavy SHARE moving 0.47 → 0.69 the other way, and 0.00 on the collapsed\n * capsule. vitrea's own pair on the landed material reaches 0.69 at 2x and\n * carries 0.23 at 1x. So the share is the quantity, and this is where the wave\n * puts it.\n *\n * ```\n * kDeep(span, dpr) = floor(dpr) + (1 − floor(dpr))\n * · smoothstep(sizeSpanMin, sizeScatterSpanMax(dpr), span)\n * + heavyShareThick(dpr) · sizeThickness(span) ← this\n * ```\n *\n * **What stays, and why the thin capsule cannot move.** `sizeScatterFloor`,\n * `sizeScatterSpanMax` and the ramp's start anchors are NOT re-derived: the\n * W11c curve stays as the law's thin end and this constant is the lift the\n * thick end takes above it. That is X5 discharged by the form rather than by a\n * capture — `sizeThickness` is exactly 0 at and below `sizeSpanMin`, so\n * `rrect-sm` and every smaller control are bit-identical whatever this says,\n * and the capsule at span 44 takes 0.0923 of it, which is the whole of the\n * thin end's exposure and is what the ladder's thin-invariance rung reads. The\n * alternative — re-expressing the whole curve on a thin/thick anchor pair —\n * would have made the capsule's own share a fitted quantity of this wave, and\n * the reference does not ask for that: its sharp σ is 2.62 device px on the\n * collapsed capsule against 2.79 on the thick rrect, span-flat to 6 %.\n *\n * **Inert at 0**, which is what ships until G3 declares the fit: the term is\n * one multiplication by zero added to the curve W11c fitted, so the resolved\n * material and every golden are byte-identical to the W24 bed.\n *\n * At dpr 2 the 2x anchor is additionally inert on the landed material for a\n * second reason: `sizeScatterFloor2x` is 1, so `kDeep` is already 1 at every\n * span and the clamp absorbs any lift. The 2x share is therefore not a\n * quantity this bed can carry, and it waits for G1's 2x probe fixtures.\n */\n readonly sizeScatterHeavyShareThick1x: number;\n readonly sizeScatterHeavyShareThick2x: number;\n\n /**\n * **The body's level above the thickness knee** (W25; claims §5.113, W25\n * Decision Log 3 (b)) — an OFFSET on the interior level a surface settles at,\n * in the tone response's own encoded units, reached at `sizeScatterSpanMax`.\n *\n * W25 G0 answered clause 4 in the landed law's favour and found one residual\n * it cannot carry. `sizeThickness(short side)` at knee 96 scores r 0.95–0.998\n * against 0.68–0.96 for the long side, the area, √area and the radius, on the\n * width and on the level, in both probe grids and both schemes — so the\n * argument and the knee stay. But the reference's body LEVEL keeps grading\n * above 96: on the W9 light grid over `checkerboard` it reads 0.61484 /\n * 0.61299 / 0.67915 / 0.69083 / 0.70458 across spans 32 / 44 / 96 / 128 / 160,\n * where `sizeThickness` has been flat since 96. The width does not grade there\n * on any pitch; only the level does.\n *\n * ```\n * R(x, span, dpr) = R₀(x, sizeK)\n * + sizeToneLevelFar · smoothstep(sizeSpanMax,\n * sizeScatterSpanMax(dpr), span)\n * ```\n *\n * **Where it enters.** On the tone response's OUTPUT — the settled interior\n * level `backdropToneResponse` returns, which is the law that owns the\n * interior mean (claims §5.33) — and not in the blur, not on a gain on the\n * mix, and not (this is the correction) on the response's own thin-to-thick\n * blend.\n *\n * **Why not on the blend, which is what the wave chartered.** G0's reading\n * that the residual's \"sign follows the backdrop\" is a reading of the\n * REFERENCE's absolute grading, and the quantity a term has to close is the\n * residual AGAINST vitrea, whose own deep value keeps rising to\n * `sizeScatterSpanMax` over the same spans. G2's ladder measured both shapes\n * on the same rows (`fit-level.txt`): carrying the blend past the thick row\n * explains 0.3 % of the above-knee residual and its per-row gains run\n * −1.13 … +0.24 with the two grids disagreeing in sign, because the blend's\n * direction is different at every backdrop level and the residual's is not. An\n * offset explains 11 % of it and the light grid's rows agree: `resid(160) −\n * resid(96)` is +2.2 … +4.2 codes over `checkerboard` at four pitches,\n * `dark-solid`, `mid-dark-solid`, `hc-text` at two pitches and `photo`, over\n * backdrops spanning 0.012 to 0.89 linear. Backdrop-independent is what the\n * rows say, so backdrop-independent is the shape.\n *\n * The curve is the one the ramp's far anchor declines along and the 2x heavy\n * gain rises along, so no new span statistic enters the material, and it is\n * **exactly 0 at and below `sizeSpanMax`** — nothing at or under span 96 moves\n * at any value of this constant, which is what let G2 probe it against the\n * frozen bed with 77 control rows reading a lever of 0.000000 codes per unit.\n *\n * Folded with `sizeK`, like the response it offsets: under reduced\n * transparency the material has stopped transmitting and the level it settles\n * at is the preference's, not the size law's.\n *\n * **Inert at 0**, which is what ships until G3 declares the fit. What G2's\n * ladder read is in `fit-level.txt`; the constant is weakly conditioned on the\n * bed as it stands and G1's probe set at both scales is what would condition\n * it (G0 §6: 118 level rows on the 1x grids, 202–238 with the 2x captures).\n */\n readonly sizeToneLevelFar: number;\n\n /**\n * **The heavy blur's width, in device px per scale** (W26; W26 Decision Log 1\n * and 2, from the measured cause in claims §5.116 §2) — the constant that makes\n * the deep sample's width a continuous parameter instead of a chain level.\n *\n * W25 could not raise the heavy share because vitrea's heavy component is\n * 13.3 device px at 1x against the reference's 19.5, and raising the share at\n * the wrong width adds narrow structure the reference does not have. The width\n * was not a lever: `sizeScatterGainMax` 8 → 10.3 left reader A at 13.29. W26 G0\n * measured why, and it is arithmetic rather than material\n * (`results/2026-09-10-w26-heavy-width/g0/tap-today.txt`). The body's deep\n * sample is\n *\n * ```\n * scatterLod = clamp(bodyChainLod + log2(gain), 0, chainMaxLod)\n * ```\n *\n * `chainMaxLod` is `planPyramid`'s `levelCount − 1`, and the chain stops when\n * the shorter side would fall below `MIN_LEVEL_EXTENT` = 8. On the bed's\n * 320 × 200 backdrop raster the chain is five levels, so `chainMaxLod` is **4**\n * at dpr 1, and `bodyChainLod + log2(8)` is 4.06 — **already past the clamp**.\n * Every gain at or above 7.5 draws the same level 4, whose own kernel is\n * 13.4 level-0 texels wide (`CHAIN_LEVEL_SIGMA`) — which is the 13.3 the ledger\n * recorded. G0 rendered the three impulse rows at gains 8, 10.3, 16 and 32 and\n * read them identical to the last digit, moving only at gain 4, which asks for\n * level 3.06 and gets it. So `sizeScatterGainMax`, `sizeScatterGainMax2x` and\n * `sizeScatterGainFar2x` grade a quantity the clamp then discards, and a\n * fractional level or a blend of two levels cannot widen anything at dpr 1 —\n * G0 measured both **inert to the bit** there and removed them again (W26\n * Decision Log 2 (a); the branch and `results/…/g0/` are their record).\n *\n * What widens is a Gaussian, and it is built where the chain is built. The\n * pyramid takes the chain level whose own blur is nearest below this σ and runs\n * the two separable passes it already runs for the body until the total is this\n * σ exactly (`heavyTapPlan`, `PyramidResources.heavy`), so the width is\n * continuous and is bounded by nothing the chain's depth decides — the residual\n * carries whatever octave the chain lacks. The optics pass then reads that\n * texture in place of the chain tap.\n *\n * **Per scale**, resolved by `rampAtScale` on the pattern `sizeScatterGainMax2x`\n * established, because the reference's heavy component is a device-px quantity\n * that does not simply halve between the scales (19.52 at 1x, 11.29 at 2x;\n * claims §5.113 §2) — so a profile naming only the 1x end drags the 2x end\n * toward the 2x constant's own default, and a document that means both names\n * both.\n *\n * **At 0 the mechanism does not exist**: no texture is allocated, no pass is\n * encoded, and the optics pass takes the single `textureSampleLevel` of the\n * chain the material has always taken. That is what makes the landed 0.14.0\n * goldens byte-identical.\n *\n * **What it costs, and what it gives up.** One texture and two passes per\n * source per frame — 0.070 ms on the mobile bench row, against +1.1 ms for the\n * in-shader grid G0 measured (W26 Decision Log 2 (b)). The width is then one\n * per SOURCE rather than one per pixel, so the span grading `sizeScatterGainFar2x`\n * carried does not reach the deep sample where this is on. The reference's heavy\n * width does not grade with the span at 1x (claims §5.113 §4), which is what\n * says the material can afford that; at 2x it does (the `-lg` row reads 16.92\n * against `-md`'s 11.29), and that is a recorded gap rather than an answered\n * one (W26 Decision Log 2 (f)).\n *\n * ---\n *\n * **WHAT WAS THEN MEASURED, and it moved the target as well as the width**\n * (W26 G1b and G1c; claims §5.121 and §5.122; W26 Decision Log 5 and 6 (a)).\n * The readings quoted above — 19.52 at 1x, 11.29 and 16.92 at 2x — are\n * two-Gaussian fits to ONE backdrop each, and the same reference reads 8.4\n * through `checkerboard-64` where it reads 19.5 through the impulse tile. They\n * stand as recorded, with these beside them.\n *\n * The instrument of record is the family reader: the composite this renderer\n * actually computes, fitted to the pixels jointly across every thick untinted\n * backdrop of one surface, with a per-backdrop gain. It is the only reader in\n * this wave that was held against a control — it returns vitrea's OWN drawn\n * width to 0.6 % — and on it **Apple's heavy width is 8.6–9.2 device px at\n * dpr 1 and 8.7–9.6 at dpr 2**, on both surfaces and in both schemes, with the\n * share already right to 0.07. So the 13.418 the clamped tap drew at dpr 1 was\n * half again too wide, and the reason two waves could not raise the share is\n * that more of a too-wide heavy component is more of the wrong thing.\n *\n * **The landed 9 and 9**, fitted through a ladder the reader sees one for one\n * (slope 0.995–1.111, rms 0.03–0.06 device px over seven rungs from 8 to\n * 13.418), inverted per cell: 9.48 / 8.63 / 9.19 at dpr 1 and 8.13 / 9.79 /\n * 8.37 at dpr 2. At dpr 1 the spread is 9.8 % and one number serves both spans;\n * at dpr 2 it is 20.4 % and one number does not, which is the span grading of\n * the paragraph above, now measured at 1.66 device px.\n *\n * **The mechanism has no small values** (W26 Decision Log 6 (c)). The paragraph\n * above says the mechanism does not exist at 0; the counterpart is that it does\n * exist at 0.001, where `heavyTapPlan` selects chain level 0 with a residual of\n * a thousandth of a texel and the deep sample becomes the UNBLURRED backdrop.\n * A near-zero σ is therefore the opposite of \"almost off\" — it is the widest\n * possible departure from the material — and a profile must name 0 or a real\n * width and nothing between. The domain is 0 or at least the chain's level-1\n * width; a floor in `heavyTapPlan` would make it continuous, and the tracker\n * carries it.\n */\n readonly sizeHeavyTapSigma: number;\n readonly sizeHeavyTapSigma2x: number;\n\n /*\n * ## W30's spanning set: the diffusion, made selective in the backdrop's scale\n *\n * The five leaves below are the wave's second operator, landed at inert values\n * before anything is fitted (W30 Decision Log 1 (b) and 2 (d); claims §5.156\n * §3, §5.158). They exist because the residual the operator has to move is\n * **non-monotone in the backdrop's pitch** — vitrea passes 1.21× the native\n * structure over a 16 px checkerboard and 0.76–0.83× over 4 and 8 px ones and\n * over a photograph, on the same material and the same span — and a positive\n * mix of two Gaussians, which is monotone in frequency, cannot do that. Its\n * sign also turns on the colour scheme and, on structured backdrops only, on\n * the device ratio.\n *\n * Two mechanisms can express a notch and G0's cut could not choose between\n * them, because the macOS 27 generation of the matrix carries **no probe row**\n * and the pitch ladder is entirely probe — so the curve the operator fits is\n * not in committed evidence and the one discriminator the bed does carry is\n * confounded by the tone response (§5.156 §3). Rather than spend a second\n * exemption mid-fit, the wave lands a set that SPANS both and turns on\n * whichever the ladder, once read, supports:\n *\n * (i) a second heavy tap at its own width with a SIGNED weight\n * (`sizeHeavySecondSigma`, `…2x`, `sizeHeavySecondShare`), which makes\n * the kernel non-monotone in frequency — a negative weight subtracts a\n * wider Gaussian, which is the notch;\n * (ii) a mix conditioned on the SOURCE's own measured spatial scale\n * (`sizeScatterScaleGain`, `sizeScatterScaleRef`), keyed on the\n * analysis pass's per-source `stats` — `[encoded mean, linear variance,\n * edge density, sample count]` — of which edge density is a reciprocal\n * length and therefore the scale statistic, in the only place a\n * per-source quantity can be read.\n *\n * The two SIGNED amounts are the scheme-conditioned leaves, which on this\n * project means two values of one leaf across the light and the dark document:\n * the dark document is a patch and the renderer has no scheme input. The\n * widths and the reference are not scheme-conditioned, because a spatial scale\n * is a property of the source raster and that is the same raster in both\n * schemes.\n *\n * `sizeToneLevelFar` is NOT part of this set and stays at 0: its sign is\n * stable per scheme but the two light backdrops disagree by 5.5× on its\n * magnitude, so it is declined rather than fitted (W30 Decision Log 2 (d)).\n */\n /**\n * The second heavy tap's Gaussian width in CSS px, per scale — candidate (i)'s\n * width, on `sizeHeavyTapSigma`'s own pattern and resolved by the same\n * `rampAtScale`.\n *\n * It is a second `PyramidResources` texture and a second separable pair, not a\n * uniform the optics pass evaluates, for `sizeHeavyTapSigma`'s measured\n * reason: a grid of taps at the fragment costs +1.1 ms on the mobile bench row\n * against 0.070 ms for two separable passes the chain already runs (W26\n * Decision Log 2 (b)). So the width, like the first one, is one per SOURCE.\n *\n * **Ships at 0, and the width is not what makes it inert** —\n * `sizeHeavySecondShare` is. At share 0 no texture is allocated, no pass is\n * encoded and the optics pass never reads one, so this width is unread\n * whatever it holds; 0 is chosen because it is the value at which\n * `heavyTapPlan` would also decline. A profile that names a width and leaves\n * the share at 0 gets nothing, deliberately: the share is the single gate, so\n * that the off path has exactly one condition.\n */\n readonly sizeHeavySecondSigma: number;\n readonly sizeHeavySecondSigma2x: number;\n /**\n * The second heavy sample's weight in the deep mix — a SIGNED fraction, and\n * the scheme-conditioned leaf of candidate (i).\n *\n * The deep sample becomes `heavy + share · (heavy2 − heavy)`, so a positive\n * share widens the deep component toward the second width and a NEGATIVE one\n * subtracts it — an unsharp mask on the backdrop, which is a kernel that\n * passes the middle pitch less than both ends and is the only shape on offer\n * that can do what the residual asks. The sign is what the colour scheme\n * flips: on the gated 16 px cell vitrea passes 1.57× the native structure in\n * 1x light and 0.75× in 1x dark, so the light document wants structure removed\n * at that pitch and the dark document wants it added (claims §5.156 §3, §6).\n *\n * **It is also the GATE.** The second heavy texture is built, bound and read\n * only where this is non-zero, so at 0 the mechanism costs no allocation, no\n * pass and no sample, and the deep mix is the expression W26 left — which is\n * what the 34 renderer goldens prove, since they render an explicit patch over\n * the default and every one of them is byte-identical across this commit.\n *\n * **Ships at 0, a multiplied zero**: the lerp's second term is\n * `0 · (heavy2 − heavy)`, and the branch that would read `heavy2` at all is\n * not taken.\n */\n readonly sizeHeavySecondShare: number;\n /**\n * The gain on `kScatter` per unit of the source's measured scale statistic\n * about `sizeScatterScaleRef` — candidate (ii)'s scheme-conditioned leaf, a\n * fraction per unit of statistic, signed.\n *\n * `kScatter` is the share of the deep component in the body's mix, and this\n * adds `sizeScatterScaleGain · (stat − sizeScatterScaleRef)` to it before the\n * clamp — so a backdrop whose structure sits at a finer scale than the\n * reference takes a different share of the heavy component from one whose\n * structure is coarser, which is a transmission that depends on the backdrop's\n * scale rather than only on the surface's span. The statistic is the analysis\n * pass's per-source EDGE DENSITY (mean luminance-gradient magnitude per texel,\n * a reciprocal length), resolved on the CPU where the readback is and handed\n * to the optics pass as one number per group.\n *\n * The sign is the scheme's, for `sizeHeavySecondShare`'s reason and read off\n * the same cell.\n *\n * **Ships at 0, a multiplied zero**: the added term is\n * `0 · (stat − sizeScatterScaleRef)` and `kScatter` is already clamped to\n * [0, 1], so the clamp that follows is the identity on it.\n */\n readonly sizeScatterScaleGain: number;\n /**\n * The reference value of the per-source scale statistic the gain above is\n * measured about — the backdrop scale at which the operator does nothing.\n *\n * Not scheme-conditioned: a spatial scale is a property of the source raster\n * and the raster is the same in both schemes. Fitted in §5.159 as the edge\n * density of the pitch the two sides of the residual straddle, once the ladder\n * has a macOS 27 reading.\n *\n * **Ships at 0**, and the argument for its inertness is not a multiplied zero\n * but a different one and sufficient on its own: the gain that multiplies the\n * difference from it is 0, so no value of this constant can reach the mix.\n */\n readonly sizeScatterScaleRef: number;\n\n /**\n * The occlusion gain — \"a larger size is more opaque. A smaller size is\n * clearer\" (S284). The fraction of the *remaining* transparency the size law\n * closes at full size.\n *\n * Relative rather than absolute, for `increasedOcclusionLift`'s reason: a floor\n * dies silently the moment nominal passes it, and a fraction of the headroom\n * cannot. It also composes correctly with the accessibility lift — under reduced\n * transparency nominal is already near 1, so the size law has almost no headroom\n * left to close, which is exactly what the reference does there (its transmission\n * reads 0.011 at a 44 px span and 0.014 at 96 px — no size dependence, because\n * there is none left to have).\n */\n readonly sizeOcclusionGain: number;\n\n /**\n * The inner shadow's gain — \"casts deeper, richer shadows\". A multiplier on\n * `shadowDepth` at full size.\n *\n * **Coupled by construction, not fitted, and the difference is stated rather\n * than hidden.** The fixtures cannot identify it: the reference's peak darkening\n * outside its contour measures 0.0000–0.0001 on almost every calibration scene\n * and vitrea's measures the same order (C9a, `shadowFalloff`), so there is no\n * measured gap for a sweep to close, and what this renderer's `shadowDepth`\n * scales is an *inner* shadow whose contribution to the interior level is\n * degenerate with the tint's — two constants, one observable. So the direction\n * comes from Apple's sentence and the magnitude is held to what the objective is\n * flat over, with that flatness recorded. GPU tier only: the CSS tier's shadow is\n * an outer `box-shadow` the reference does not cast at all (Decision Log #32(c)).\n */\n readonly sizeShadowGainMax: number;\n\n /**\n * The lens (W12 G2, claims §5.51) — one steep power on the reference's own\n * span law, along a direction the reference ovalizes.\n *\n * The reference's `glassBackground` filter takes an inner refraction *amount*\n * and *height* that are clamped linear functions of the shape's shorter side\n * (claims §5.50: amount −min(0.8·span, 60), height min(0.25·span, 20)). What\n * those two numbers do spatially is not in the tree; measured as a field on\n * the captures (§5.49) and ranked on the pixels (§5.51), the band is\n *\n * D(u) = S · max(0, 1 − u / L′)^p, S = lensRefractionGain · A(span),\n * L′ = lensExtentGain · lensDepth,\n *\n * with `lensDepth = (thickness / lensThicknessReference) × H(span)` the\n * reference's height law scaled by the author's thickness (8 is the default\n * and the reference's unit — at 8 the depth IS Apple's height, 8 / 11 / 20 on\n * spans 32 / 44 / ≥ 80), `A(span)` the amount law scaled the same way, and\n * `p = lensProfileExponent`. Apple's own two-term profile at its literal\n * amounts was ranked too and lost on the pixels and the holdout; its span law\n * is adopted, its shape is not (§5.51 §2).\n *\n * `lensRefractionGain` is therefore re-based: it was 1.6 lens depths on the\n * W11c square profile (S = 1.6 × 20.8 = 33.3 at saturation), it is now the\n * scale on the reference's amount (S = 0.745 × 60 = 44.7), fitted on\n * `rrect-md` + `-ml` at 1x with `rrect-lg` held out.\n */\n readonly lensRefractionGain: number;\n /** The reference's inner refraction height law: `min(lensHeightPerSpan · span, lensHeightMax)`. */\n readonly lensHeightPerSpan: number;\n readonly lensHeightMax: number;\n /** The reference's inner refraction amount law: `min(lensAmountPerSpan · span, lensAmountMax)`. */\n readonly lensAmountPerSpan: number;\n readonly lensAmountMax: number;\n /**\n * The author `thickness` at which the lens depth equals the reference's own\n * height — the host's default, and what the bed was captured at. A thicker\n * authoring scales the depth and the magnitude together.\n */\n readonly lensThicknessReference: number;\n /** The profile's extent over the lens depth: D reaches zero at `lensExtentGain × lensDepth`. */\n readonly lensExtentGain: number;\n /** The profile's exponent — the square of W11c became a steeper power (§5.49 §2). */\n readonly lensProfileExponent: number;\n /**\n * The direction's ovalization (§5.49 §3, §5.50): the reference's SDF element\n * carries `gradientOvalization`, and the band is magnified *along* the edge by\n * up to 1.31× as a result. The shader displaces along the gradient of the\n * blended field `(1 − ω)·d_rrect + ω·d_oval`, `d_oval` the signed distance of\n * the ellipse inscribed in the surface's box, with the magnitude fixed. The\n * reference's value is 0.5 on thick shapes and 0 on thin ones; 0.6 is what the\n * pixels want on the box-inscribed ellipse (Apple's oval is more curved at the\n * edge midpoint than that ellipse). The switch is a step in the reference\n * between spans 64 and 72; here it is a smoothstep over that band, the same at\n * both ends and continuous through a morph.\n */\n readonly lensOvalization: number;\n readonly lensOvalizationSpanMin: number;\n readonly lensOvalizationSpanMax: number;\n\n /**\n * What each accessibility regime does to the numbers above. The multipliers\n * match `platform-web`'s CSS tier so the two renderers degrade the same way\n * under the same preference.\n */\n readonly reducedTransparencyFrost: number;\n /**\n * How much of the *remaining* transparency reduced transparency closes.\n *\n * **Relative, not absolute (Decision Log #32(d)).** This was\n * `increasedOcclusionAlpha`, an absolute floor of 0.62 applied as\n * `Math.max(nominal, floor)` — a real lift while nominal was the advisory 0.28,\n * and a no-op from the moment C9a measured nominal at 0.62. The policy died\n * without being touched and nothing noticed for a whole child. A fraction of the\n * headroom cannot die that way: it lifts strictly for every nominal below 1,\n * whatever a later tuning pass moves nominal to.\n *\n * The fraction is the pre-C9a lift, restored rather than invented:\n * (0.62 − 0.28) / (1 − 0.28) = 0.4722, which reproduces the old floor exactly at\n * the old nominal. At today's nominal it reads 0.62 → 0.799.\n *\n * Mirrored by `@vitreajs/vitrea-web`'s `INCREASED_OCCLUSION_LIFT`, and pinned in\n * both directions by `packages/calibration/test/tier-coherence.test.ts`.\n */\n readonly increasedOcclusionLift: number;\n /** Optional policy-specific levels. Absent keeps the shared lift exactly. */\n readonly increasedOcclusionLiftByPolicy?: MaterialOcclusionLiftByPolicy;\n readonly strongBorderRim: MaterialRim;\n readonly reducedTintAdaptation: number;\n\n /**\n * The author tint's shade law (W10) — Apple's \"range of tones **mapped to\n * content brightness underneath**\" (S219), measured per pixel on the frozen\n * bed and the W9 probe (claims §5.36).\n *\n * The tinted material is an OPAQUE, hue-preserving shade of the seed: the seed\n * times a scalar, and the scalar is linear in the luminance the untinted\n * material shows at the same pixel — `mix(tintShadeDark, tintShadeLight, u)`,\n * clamped so a shade is never brighter than the seed. Over black content the\n * reference shows about half the seed's light; over white it shows the seed\n * itself; over a checkerboard it shows both, cell by cell, with the seed's\n * chromaticity intact to three decimals at every pitch measured. That layer\n * composites over the material at the AUTHOR's opacity (the colour's alpha) in\n * the encoded space — the half-strength cell is the 0.501 encoded-space mix\n * of its untinted and full-tinted twins, per channel — so the material's own\n * alpha is not what a tinted surface shows.\n *\n * `tintShadeStrength` is the law's provenance gate: 1 where the constants were\n * measured (the light scheme), 0 where they were not — the dark scheme\n * renders the pure seed over every backdrop it was measured on, which is\n * consistent with \"a shade relative to the material's own body level\" but is\n * not yet separable from \"no shading in the dark scheme\". The collapse (W7)\n * folds the shade out the same way, because a collapsed material IS a dark\n * body and the reference renders the pure seed there too.\n *\n * MEASURED, both scales, twelve light-standard cells across three pitches:\n * fitted on the five probe cells only (17 700 px, RMS 0.0035) and refereed by\n * every canonical tinted row. Mirrored by `@vitreajs/vitrea-web`'s\n * `TINT_SHADE`, pinned in both directions by\n * `packages/calibration/test/tier-coherence.test.ts`.\n */\n readonly tintShadeDark: number;\n readonly tintShadeLight: number;\n readonly tintShadeStrength: number;\n\n /**\n * The fraction of the author's seed saturation retained before the shade law.\n * The neutral endpoint is the seed's maximum linear channel, not its luminance:\n * W27c's orange and blue checkerboard capsules at both 1x and 2x lose their hue\n * to the SAME grey, despite the seeds having different luminances (§5.130).\n * Strength still composites the resulting layer; it is not discarded.\n * Absence means 1, the identity. Identity values are omitted from resolved\n * documents so the frozen active profiles keep their existing fingerprints.\n */\n readonly tintChromaScale?: number;\n\n /**\n * The fraction of the tint shade retained when backdrop adaptation collapses\n * the body. W27c's 1x light dark-solid tinted capsule requires Y 0.03678 while\n * its checkerboard counterpart requires Y 0.45128. A chroma-only seed change\n * cannot supply both: collapse forces the old shade to 1. Retention lets the\n * same shade law follow the collapsed body's level instead of exposing the\n * unshaded seed. Absence means 0, preserving the active law and its fingerprint.\n */\n readonly tintShadeCollapseRetention?: number;\n\n /**\n * **Backdrop tone adaptation (W7)** — the axis Apple's material has and this\n * one did not: over a dark enough backdrop the material stops being a lighter\n * thing in front of it and takes the backdrop's own tone.\n *\n * The mechanism is one mix, and it is deliberately the *tint colour* rather\n * than the tint alpha: `backdropToneMax` at full strength makes the tint equal\n * the sampled backdrop, so `mix(backdrop, tint, tintAlpha)` collapses to the\n * backdrop exactly and the surface is left with its rim, its inner shadow and\n * its lensing and nothing else. That is what the settled reference does —\n * `dark-solid__capsule-button__rest` is byte-identical to its own background\n * in every standard profile, at both scales, in both colour schemes.\n *\n * `backdropToneLow`/`backdropToneHigh` are the backdrop luminances (linear)\n * the two ends are reached at, crossed with a smoothstep for the same reason\n * `tintToneLow`/`High` are.\n *\n * `backdropToneSizeBias` is the size gate, and it is not decoration: the same\n * backdrop moves a small surface and a large one by very different amounts.\n * Over `dark-solid` the reference's 44 px capsule adapts completely while its\n * 96 px rrect keeps three quarters of its own appearance, measured on both\n * scales independently and agreeing to three decimals. The bias enters the\n * curve's *argument* rather than its amplitude — a thicker surface behaves as\n * though its backdrop were brighter, which is what more material between the\n * viewer and the backdrop means — because an amplitude gate cannot reproduce\n * the second dark backdrop (`impulse`) and this does.\n *\n * The axis is WITHIN a colour scheme. The scheme picks the neutral; this moves\n * the material away from that neutral toward what is actually behind it. So the\n * dark profile runs the same law with the same constants and does not\n * double-adapt: over `dark-solid` its capsule collapses onto the backdrop too,\n * and the light and dark references become the same pixels there.\n */\n readonly backdropToneMax: number;\n readonly backdropToneLow: number;\n readonly backdropToneHigh: number;\n readonly backdropToneSizeBias: number;\n\n /**\n * **The transmission the collapse keeps (W24 G1)** — and the correction, set\n * BESIDE the paragraph above rather than over it, of what \"texture collapse\"\n * was measured on.\n *\n * W7 fitted the collapse on `dark-solid`, a backdrop with no texture in it,\n * and the paragraph above therefore says the collapse converges the interior\n * on the backdrop's mean COLOUR. On a solid backdrop the mean and the pixel\n * are the same number, so the fit could not tell the two apart; the impulse\n * bed can, and it says they are not the same. Through the reference's\n * collapsed `impulse__capsule-button` the centre dot still comes through at\n * +0.0065 linear over a body of 0.0065 at 1x and +0.0254 over 0.0065 at 2x,\n * where vitrea's collapsed capsule passes exactly 0.0000 (claims §5.107 §2).\n * The reference's collapsed material is a dark glass that still transmits what\n * lies beneath it, blurred — it collapses the LEVEL, not the structure.\n *\n * The arithmetic the collapse already has makes the correction one constant.\n * Writing `M` for the unadapted composite this pass would otherwise produce,\n * the (colour, alpha) pair the shader solves reduces exactly to\n * `colour = (1 − k)·M + k·target`, and `target` is today the group's mean\n * backdrop colour — one number for the whole surface, which is precisely what\n * flattens the dot away at `k` 1. So `collapseTransmission` lerps the TARGET\n * from that mean (0) to the per-pixel blurred backdrop sample the refraction\n * path already computed (1):\n *\n * target = mix(toneColour.rgb, backdrop, collapseTransmission)\n *\n * The tone axis's ARGUMENT is untouched — `k` is still read from the group's\n * mean luminance and the size bias, and the response law still solves against\n * `toneAnchor.w` — so the collapse collapses exactly as far as it did and\n * only stops flattening what is under it. The blurred sample's mean under the\n * surface is the group's mean to within the difference between a local and a\n * global average, so the body's LEVEL moves by less than a code where the\n * backdrop is anything like uniform, and not at all where it is solid: over\n * `dark-solid` the sample IS the mean and every collapsed cell of that bed is\n * byte-identical at any value of this constant. That is the stop the fit is\n * checked against.\n *\n * At 0 the target is the mean and the shader's arithmetic is W7's to the bit,\n * which is why this can be added without moving a pixel anywhere.\n *\n * What it cannot carry is the reference's WIDTH. Fitted on the reference's own\n * dot the transmitted profile is a 4 CSS px box convolved with σ 2.63 device\n * px at 1x and σ 1.38 device px at 2x — the same kernel the reference's\n * UNCOLLAPSED cells show (σ 2.86 / 1.40 device px on `impulse__rrect-md`), so\n * the collapse does not change Apple's blur, but that kernel is neither\n * CSS-invariant nor device-invariant and vitrea's is neither of those numbers.\n * This constant sets how MUCH comes through; how WIDE it arrives is the\n * material's own scatter law and is recorded as a gap, not fitted here\n * (W24 G1 findings).\n */\n readonly collapseTransmission: number;\n\n /**\n * **The collapse's transmission at dpr 2** (W24 G1), the second anchor of the\n * constant above, on the pattern `sizeScatterGainMax2x` established for the\n * body's own second scale (claims §5.69 §1).\n *\n * It is a per-scale reading and not a per-scheme one, and the evidence is the\n * fixtures': the light and dark captures of the collapsed cells are the same\n * bytes, so the collapsed appearance is one appearance in both schemes, while\n * the width the reference transmits through is a different number at each\n * scale. Fitted on the reference's own dot, its kernel is a 4 CSS px box\n * convolved with σ 2.63 device px at 1x and σ 1.38 device px at 2x — a width\n * that is invariant in neither CSS nor device pixels — so the SHARE that comes\n * through cannot be one number over a kernel that is two.\n *\n * Defaults to the 1x constant, so a profile that names only that one renders\n * it at every ratio and this anchor is the identity on the landed material.\n */\n readonly collapseTransmission2x: number;\n\n /**\n * **How much of the blurred backdrop's CHROMATICITY the body restores** (W31;\n * claims §5.161 §5, fitted in §5.164) — a fraction in [0, 1], inert at 0.\n *\n * The body is a neutral plate composited over the blurred backdrop, so what a\n * photograph's hues survive the composite at is `1 − sizedAlpha` — 0.513 on the\n * macOS 27 light document and 0.095 on the dark one, against a reference that\n * reads 0.90–0.97 of its own backdrop's chroma on the same cells. Apple's body\n * at the same LEVEL keeps the hue, which is what a darkening acting on the\n * backdrop's luma while leaving its chromaticity alone does and what a plate\n * does not. No constant the material had could close that (W29 Decision Log\n * 6 (c)): it is a mechanism, and this is the one leaf that adds it.\n *\n * Applied immediately after `colour = mix(backdrop, adapted, presentAlpha)`\n * and before the tint composition, so an author's tint still displaces the\n * result. The colour is mixed toward `backdrop · (Y / Y_backdrop)` — the\n * backdrop's chromaticity carried to the colour's OWN linear luma — by this\n * fraction, so **luma is preserved by construction rather than by\n * correction**: both endpoints of the mix have linear luma exactly `Y`,\n * `dot(rgb, (0.2126, 0.7152, 0.0722))` is a linear functional, and the mix has\n * luma `Y` in exact arithmetic. (OKLab `L` is NOT linear luma, which is why the\n * formulation is in linear RGB: holding `L` while moving toward a saturated\n * chromaticity moves `Y` by −22 % at sRGB blue and +10 % at green.) Gamut is\n * taken by scaling chroma toward the neutral at fixed luma, never by clipping\n * per channel.\n *\n * **No `toneAdapt` gate**, and the reason is measured rather than assumed\n * (claims §5.161 §11, finding N1). A retention toward the backdrop's\n * chromaticity is the identity wherever the backdrop is achromatic, and the\n * only region `backdropToneAdaptation` can fire in on the macOS 27 documents\n * is `x < backdropToneHigh` = 1e-4 of linear light — achromatic to within the\n * capture's own quantisation. A future document that re-opens\n * `backdropToneHigh` must re-examine that, and must read it at a span at or\n * below `sizeSpanMin` where `backdropToneSizeBias` is not there to help.\n *\n * Conditioned by SCHEME (two values across the light and dark documents) and\n * by POSE: each receded document carries its own, read on the inactive cells,\n * because the recede's untinted body has no chroma law at all otherwise —\n * W27c's collapse acts on the tint SEED inside `if (tintK > 0.0)`. The\n * accessibility documents inherit the light value.\n *\n * **Ships at 0, a multiplied zero**: the mix's second term is `0 · (target −\n * colour)` and `colour` leaves the composite exactly as\n * `mix(backdrop, adapted, presentAlpha)` produced it, which is why the 34\n * renderer goldens are byte-identical across the commit that added it and why\n * `MATERIAL_IDENTITY_TABLE` can drop it from the fingerprint.\n *\n * One place it cannot act, declared rather than discovered: on the unsampled\n * layer path (`flags.x <= 0.5` and not `domMaterial`) the shader overwrites\n * `colour` with `adapted` and writes a layer for the browser to composite, so\n * there is no backdrop in hand and no chromaticity to restore toward. The\n * retention is silently the identity there.\n */\n readonly bodyChromaRetention: number;\n\n /**\n * **The rim that survives the collapse (W23)** — the one mark the collapsed\n * appearance keeps.\n *\n * The paragraph above is right about the body and wrong about the rim. W7 read\n * the settled reference's `dark-solid__capsule-button` as \"byte-identical to\n * its own background, rim included\", and at the contour it never was: the\n * fixture carries a body one code BELOW its backdrop and a contour rim of\n * +0.020 linear per CSS px (55/255 on a 28/255 backdrop at 2x), in every\n * standard profile, at both scales, in both schemes (claims §5.99). vitrea\n * folds that rim out with everything else through the shader's one\n * `present = 1 − toneAdapt`, and the user's eye named the result: \"not one of\n * our glasses is visible on black, where Apple's clearly show their presence.\"\n *\n * So the shader's rim becomes\n * `rimWeight × (rimAmplitude × present + rimCollapsed × toneAdapt)`: the\n * scheme's own rim fading out with the adaptation as it does now, and an\n * absolute rim the collapsed appearance owns rising with it. At `toneAdapt` 0\n * nothing changes at all, which is why this constant can be added without\n * moving a single uncollapsed pixel.\n *\n * It lives on the profile and NOT in the dark patch, because the collapsed\n * appearance is scheme-independent and the fixtures say so: the light and dark\n * fixtures of `dark-solid__capsule-button` are byte-identical at both scales\n * (W23 X4). A reading that separates the schemes under collapse is a finding\n * about the wave, not a second constant. G0 strengthened the evidence: the\n * identity survives an AUTHOR TINT — `dark-solid__capsule-button__rest-tint-\n * orange` is the same bytes in both schemes at both scales — so what the\n * collapse draws is one appearance however the surface was painted.\n *\n * It is expressed in its own units and not in the dark rim's, because the two\n * were measured apart: see the value's own note on the default profile.\n */\n readonly rimCollapsed: number;\n\n /**\n * **The rim a PAINTED surface keeps under the collapse** (W23 G1; claims\n * §5.100 §5, Decision Log 2 (c)) — `rimCollapsed`'s sibling, at the author\n * tint's full coverage, with the two lerped by the coverage between them.\n *\n * The reference's collapsed capsules keep +0.020 of contour rim bare and\n * **+0.115 painted** (`dark-solid` and `impulse` `capsule-button`\n * `rest-tint-orange`, both schemes, both scales, on fixtures that are the same\n * bytes in the two schemes). An author tint over black is painted, not\n * adapted: the tone collapse takes the material's own appearance to its\n * backdrop and the colour the author put on it does not go with it.\n *\n * It is ABSOLUTE, in its own units, for the same reason `rimCollapsed` is and\n * on the same evidence — and G1 measured what the alternative would have cost.\n * Decision Log 2 (c) proposed gating the collapse itself on the tint's\n * coverage, so that a painted surface keeps its APPEARANCE's own rim; rendered,\n * that mechanism needs a gate of 0.534 on the light bed and 0.294 on the dark\n * one to reach +0.115 on a cell whose reference fixture is byte-identical\n * between the schemes, because it makes the kept rim proportional to each\n * scheme's own amplitude law and those differ by 1.8× there. A proportional\n * form cannot draw one appearance from two materials; an absolute one does,\n * which is X4 again and the reason this constant has the shape it has.\n *\n * It is fitted on orange alone, and that is a stated limit: the reference's\n * collapsed tint-blue capsule reads +0.176 against orange's +0.115, so the\n * quantity depends on the tint's own colour, and every collapsed blue cell on\n * the bed is holdout. What lands here is the orange rows' answer with the\n * colour dependence recorded as future work.\n */\n readonly rimCollapsedTinted: number;\n\n /**\n * **How much of an author tint's own colour the rim's light is spent in**\n * (W23 G3; claims §5.102) — 0…1, multiplied by the surface's tint coverage.\n *\n * Apple's rim on a painted surface is the paint LIFTED, not white added over\n * it. Read on the contour row's straight-span mean colour at 2x in light, an\n * orange paint of (255, 148, 0) rises to (254, 188, 0) with its blue channel\n * still at 0, and a blue paint of (8, 120, 236) to (59, 199, 248); vitrea drew\n * (255, 192, 130) and (145, 183, 255) — the same rim in white, which turns an\n * orange edge peach and a blue edge lilac. No luminance clause sees it: the\n * rim's amplitude is right and its colour is not.\n *\n * So the rim's light is spent in `mix(white, paint / max(paint), chroma × s)`.\n * The paint is normalised by its own brightest channel rather than by its\n * luminance, so a dark paint darkens the rim's HUE and not its amount, and the\n * factor is the pixel's own tint strength, so an untinted surface keeps a white\n * rim at every value of this constant — which is what makes the mechanism reach\n * painted pixels only and every untinted capture byte-identical (W23 S10).\n */\n readonly rimTintChroma: number;\n\n /**\n * **The backdrop tone response (W9)** — the law that owns the interior MEAN,\n * where the four constants above own texture collapse and nothing else.\n *\n * The W9 probe falsified the mix-toward-backdrop form outright (claims\n * §5.33): six cells need mix strengths outside [0, 1], because the\n * reference adapts toward the material's own light/dark appearance, which\n * coincides with the backdrop's tone only over `dark-solid` — the one\n * background the mix was fitted on. What the probe measured instead is a\n * LAW: at equal encoded-space backdrop mean the reference's settled\n * interior is the same number regardless of the backdrop's structure\n * (checker vs text rows, 0.81 both at input 0.69), so the interior level is\n * a function `R(encodedMean, thickness)` and these constants are that\n * function's anchors.\n *\n * `backdropToneAnchorX` is the three solid anchors' encoded-space means —\n * measured backdrop luminances, not tuned. `backdropToneResponseThin` and\n * `...Thick` are the reference's settled interior levels at those anchors\n * for a thin surface (`sizeThickness` 0, the 32 px rrect) and a thick one\n * (saturated, the 96 px+ rrects pooled — their residual spread ±0.012 is\n * the accepted cost of `sizeSpanMax` saturation, claims §5.33). Between\n * the rows: smoothstep in thickness; between the anchors: monotone\n * (Fritsch–Carlson) interpolation in the ENCODED input, the space the\n * probe validated to RMS 0.034 with zero fitting.\n *\n * Below the dark anchor the surface has no data (the probe's grid floor\n * is `dark-solid`), and the one validation cell down there —\n * `impulse__rrect-md`, backdrop 0.0039, reference 0.4358 — reads DARKER\n * than the dark anchor's thick row, so clamping would regress it. The\n * solve's authority fades to zero from the dark anchor downward\n * (smoothstep over the anchor's own lower half, no new constant); the\n * extreme-dark region stays with the collapse constants that were fitted\n * on it.\n */\n /** W28: absent/source preserves the source solve; silhouette reduces raw pixels per surface. */\n readonly backdropToneAbscissa?: \"source\" | { readonly kind: \"silhouette\" };\n readonly backdropToneAnchorX: BackdropToneKnotRow;\n readonly backdropToneResponseThin: BackdropToneKnotRow;\n readonly backdropToneResponseThick: BackdropToneKnotRow;\n\n /**\n * How much authority the response law has in THIS profile, 0…1 (W9).\n *\n * The anchors above are measurements of the LIGHT reference's settled\n * appearance. The dark scheme's material settles at its own levels over the\n * same backdrops (0.809 light against 0.055 dark over one checkerboard,\n * §5.8), so a dark profile running the light response surface brightens the\n * dark material toward the wrong scheme's appearance — measured on the\n * canonical dark bed as ΔE p95 0.08 → 0.58 before this constant existed.\n * The dark profiles set it to 0: the collapse (whose target is the\n * backdrop, not a scheme's appearance) still runs there, and a dark\n * response surface is follow-up work that needs the dark reference probed,\n * not an assumption.\n */\n readonly backdropToneResponseStrength: number;\n\n /** The outer shadow (W8) — see `MaterialOuterShadow`. */\n readonly outerShadow: MaterialOuterShadow;\n\n /**\n * Advisory light direction, in viewport coordinates with y pointing down: a\n * little left of straight overhead, which is where Apple's material reads its\n * specular from.\n */\n readonly lightDirection: readonly [number, number];\n /**\n * **The lit edge's axis (W24; claims §5.107)** — the unit direction `L` the\n * rim's directional factor is symmetric about, in the same viewport\n * coordinates as `lightDirection`, y pointing down.\n *\n * It is a SEPARATE constant from `lightDirection` and not a second reading of\n * it, for two reasons the rows give. First, they are measured to differ: the\n * rim's axis fits at 136° of compass bearing over the 19 solid rows (135.0° ±\n * 0.7° over the dark rows alone, 137.7° ± 1.5° over the light ones), where\n * `lightDirection` [−0.3714, −0.9285] is a bearing of 338.2°, an axis of\n * 158.2° — 22° away, and it was fitted for the inner shadow and the sweep, not\n * for the contour. Second, `light.xy` reaches the one-sided `spec` term this\n * factor replaces, and re-pointing it to fit the contour would move the\n * shadow's own light with it; a constant of its own keeps that seam where W2\n * and W22 left it.\n *\n * The default is the exact diagonal (−1, −1)/√2 — a bearing of 135° — and not\n * the fitted 136°: the rows do not separate the two (the joint fit's RMS moves\n * by less than a thousandth between them), and only the exact diagonal makes\n * the factor equal on all four straight sides, which is what lets the\n * amplitude's re-expression be exact rather than a 2 % trade against W23's\n * straight-span reads. `rimLitExponent` is 0, so the axis draws nothing until a\n * profile carries an exponent.\n */\n readonly rimLitAxis: readonly [number, number];\n /** Specular sweep band width in radians, and the press glow's reach in CSS px. */\n readonly sweepBandRadians: number;\n readonly glowRadiusCss: number;\n readonly glowGain: number;\n readonly sweepGain: number;\n}\n\n/*\n * There is no longer a dark counterpart to this constant. The old\n * `SRGB_DARK_TINT` ([0.09, 0.09, 0.1]) existed only as the light-backdrop end of\n * the adaptive crossover, and C9a measured that the reference does not invert its\n * tint against the backdrop at all — see `adaptiveTintLight` below. The\n * dark-SCHEME tint is a different quantity and lives with the profile that\n * carries it: packages/calibration/profiles/apple-macos-26.5-1x-dark-standard.json.\n */\nconst SRGB_WHITE_TINT: Rgb = [1, 1, 1];\n\n/**\n * How much of the remaining transparency an `occlusion: \"increased\"` policy\n * closes. **FITTED (round two, 2026-08-31) — 0.4722 → 0.75.**\n *\n * The old number was never a measurement. It was the pre-C9a lift re-expressed as\n * a fraction, (0.62 − 0.28) / (1 − 0.28), chosen so the derivation reproduced the\n * old floor exactly at the old nominal — and no stage of the recalibration\n * cascade had refitted it, which is the gap claims §5.14 records against itself.\n * Against the active bed it under-occluded badly: the reference's interior sits\n * at 0.893 under reduced transparency and 0.957 under increased contrast where\n * vitrea reached 0.777 and 0.783.\n *\n * ## One constant, two references that want different things\n *\n * macOS force-couples the accessibility toggles (Decision Log 8), so BOTH\n * accessibility profiles resolve to `occlusion: \"increased\"` and both are served\n * by this one number. Fitted on each profile's own untinted calibration cells\n * against the declared objective, they disagree: increased contrast wants 0.80\n * (0.36045 → 0.23366 across the grid, a 1.54× spread) and reduced transparency\n * wants 0.70 (0.10940 → 0.04875, 2.76×). Their implied alphas differ too — 0.945\n * and 0.864 — which is a property of the two references, not of the fit.\n *\n * 0.75 is the minimiser of the two profiles' objectives summed at equal weight,\n * which is the honest tie-break when one constant serves two equally-gated\n * profiles: 0.70 → 0.31022, **0.75 → 0.29742**, 0.80 → 0.30347. Both checks agree\n * (ΔE 0.01087 and 0.00279 at the chosen point) and both profiles improve enormously\n * against the shipped 0.4722, which reads 0.46985 on the same sum.\n *\n * Mirrored by `@vitreajs/vitrea-web`'s `INCREASED_OCCLUSION_LIFT`, and pinned in\n * both directions by `packages/calibration/test/tier-coherence.test.ts`.\n */\nexport const INCREASED_OCCLUSION_LIFT = 0.75;\n\n/**\n * The occlusion alpha a resolved policy asks for, given whatever nominal the\n * material carries. Mirrors `@vitreajs/vitrea-web`'s `occlusionAlphaUnderPolicy`.\n */\nexport function occlusionAlphaUnderPolicy(\n nominal: number,\n occlusion: MaterialPolicyView[\"occlusion\"],\n lift: number = INCREASED_OCCLUSION_LIFT,\n): number {\n switch (occlusion) {\n case \"nominal\":\n return nominal;\n case \"increased\":\n return nominal + lift * (1 - nominal);\n case \"opaque\":\n return 1;\n }\n}\n\nexport function occlusionLiftForPolicy(\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n if (policy.occlusion !== \"increased\") return profile.increasedOcclusionLift;\n const levels = profile.increasedOcclusionLiftByPolicy;\n return policy.ambientTint === \"reduced\"\n ? levels?.increaseContrast ?? profile.increasedOcclusionLift\n : levels?.reduceTransparency ?? profile.increasedOcclusionLift;\n}\n\n/**\n * **The retention stands down under an occlusion lift** — W31 Decision Log 3 (d),\n * the fix for the regression claims §5.164 §8 (b) recorded and §5.164 §13\n * measures.\n *\n * `bodyChromaRetention` restores a fraction of the backdrop's chromaticity into\n * a body that lost it to a neutral plate, and the amount the plate took is `α`.\n * Under an accessibility occlusion lift the plate takes more —\n * `occlusionAlphaUnderPolicy` sends `α` to `α + lift·(1 − α)`, so what is left\n * of the backdrop is `1 − α_eff = (1 − α)·(1 − lift)` — and the leaf as W31 G3\n * shipped it was applied at its nominal value there, restoring a fraction of a\n * chromaticity the preference had just asked to have covered up. Measured on\n * the untinted `photo` beds of the two light accessibility profiles, `R` went\n * 0.9096 → 3.0514 (reduced transparency, active), 0.8294 → 2.1195 (reduced\n * transparency, inactive) and 0.8147 → 3.1700 (increased contrast, active),\n * three beds that sat inside the wave's own 0.80–1.20 band before the leaf.\n *\n * **The rule here is the HARD GATE, and that is a measurement rather than a\n * preference** (claims §5.164 §13). Decision Log 3 (d) ruled the smaller rule\n * first — the retention acting on the plate's un-lifted share,\n * `r_eff = r · (1 − lift)` — and ruled the hard gate as its fallback if the\n * measured `R` did not come back inside the band. It did not: under the lift\n * rule the same three beds read **1.7897**, **1.1507** and **1.8324**, two of\n * them still nearly twice the reference. `1 − α` is so small under a lift of\n * 0.75–0.98 that even a retention scaled by `(1 − lift)` is a large relative\n * gain on what little chroma the plate leaves, which is the same reading\n * Decision Log 3 (b) records as the operator's structural defect: the retention\n * restores a constant fraction of the FULL backdrop chromaticity regardless of\n * what the plate transmits.\n *\n * So under any lifted occlusion the operator is the identity — which restores\n * 0.20.0's rendering on those beds EXACTLY, not approximately, because the\n * retention is the only thing this wave moved there. Decision Log 3 (c) defers\n * giving the two accessibility documents retentions of their own; until a wave\n * measures them, an inherited constant is not applied to a plate it was not\n * fitted against.\n *\n * Two properties, and each of them is why this is a rule rather than a tuning:\n *\n * - **It is an EXACT identity where no preference is set**, which is what lets\n * every standard row, every golden and every document digest be unmoved\n * across the fold.\n * - **It is written as an exhaustive switch on the occlusion axis**, not an\n * `if (increased)`. `occlusion: \"opaque\"` is `α_eff = 1` and arrives only\n * with `glass: \"none\"`, so it draws nothing either way today — but the branch\n * that is unreachable now is the one a later policy row makes reachable\n * silently, and a new axis value should surface here as a missing branch.\n *\n * It is folded HERE, on the CPU at the uniform's pack site, and not in the\n * shader: the optics pass's uniform carries no policy at all — `opticsUnderPolicy`\n * has already folded the lift into `tintAlpha` — so the shader could learn it\n * only from a new lane, and W30's rule forbids packing an operator into a\n * neighbour's padding. A whole vec4 for a factor the CPU already holds is a\n * layout change for nothing.\n */\nexport function bodyChromaRetentionUnderPolicy(\n retention: number,\n policy: MaterialPolicyView,\n): number {\n switch (policy.occlusion) {\n case \"nominal\":\n return retention;\n case \"increased\":\n case \"opaque\":\n return 0;\n }\n}\n\nexport const DEFAULT_MATERIAL_PROFILE: MaterialProfile = {\n optics: {\n // σ = 8 for the regular variant, which keeps this package's blur and\n // `platform-web`'s CSS-tier blur on the same number — and makes core's 24 px\n // `samplingPadding` advisory exactly the 3σ S1 measured.\n regular: {\n /*\n * REFITTED (recalibration cascade, 2026-08-31) against the ACTIVE-pose bed.\n * C9a's 0.62 and σ = 8 were fitted against the inactive material and are\n * kept in git history, not here.\n *\n * `blurSigma` 3 is the first value this constant has ever had that the\n * fixtures could identify. §6.1 called it unidentifiable because the\n * inactive reference passed almost no backdrop structure; the active one\n * passes a great deal (interior standard deviation 0.1358 over the\n * checkerboard against vitrea's 0.0176 at σ = 8), so the objective's spread\n * term now bites — it triples from σ = 3 to σ = 6 at a fixed alpha.\n *\n * `tintAlpha` 0.46 is the minimiser over the eight tone-inert untinted rest\n * calibration cells, a genuine interior optimum (0.38 → 0.16945, 0.46 →\n * 0.15704, 0.54 → 0.17248) with ΔE and SSIM agreeing. It remains true that\n * no single value is right for every scene: a lerp toward one tint colour\n * implies an alpha of 0.24 over the checkerboard and 0.47 over the photo at\n * the same 44 px span, which is the lerp-versus-multiply question C9a\n * recorded and nobody has acted on. Claims §5.13.\n */\n // 1.25 since W11c G1 (claims §5.41): the reference's interior over\n // structured content is a sharp component near σ 1.25 plus a heavy one\n // the scatter facet now supplies (`sizeScatterFloor`); the cascade's 3\n // (claims §5.16) was the one Gaussian that best split the difference on\n // a bed with no pitch axis to tell the two apart.\n blurSigma: 1.25,\n tint: srgbToLinear(SRGB_WHITE_TINT),\n tintAlpha: 0.46,\n rimWidth: 1.5,\n /*\n * REFITTED 0.18 → 0.844 (W23 G1; claims §5.100 §4, W23 Decision Log 2 (a)),\n * as the intercept of the amplitude law below rather than as the whole rim.\n *\n * It is not the same quantity it was. Before W23 this constant WAS the rim,\n * and 0.18 drew the same +0.060…0.078 of linear luminance at the contour on\n * every cell of the light bed against a reference of +0.10…+0.26; now it is\n * one of two terms, and on a light surface whose own level is 0.48 the pair\n * draws `0.844 − 0.628 × 0.48 = 0.542` of amplitude — three times the old\n * constant, for a rim about a third brighter than the old one at the\n * contour, because the amplitude is not the rim: the band weight `W` the\n * first two CSS px carry is 0.38…0.46 (claims §5.100 §4).\n *\n * Fitted on vitrea's OWN captures, not on a prediction: the shader's rim is\n * linear in each constant, so a base capture at the shipped `rimAlpha`\n * gives each cell's band weight and one rendered `rimLevelGain` point gives\n * `W × L`, and the pair is solved by least squares over 40 rendered solid\n * rows on 10 cells. **The canonical bed cannot fit it** — over a solid\n * backdrop, unclipped, uncollapsed and outside the holdout the light bed\n * leaves exactly two cells at bodies 0.48 and 0.43, and two nearly collinear\n * rows separate no slope from an intercept (solved on 1x alone they give\n * (0.302, +0.569) and on 2x alone (0.383, +0.183), a factor of three apart\n * and both with the wrong sign) — so W9's light probe grid, whose bodies\n * span 0.43…0.93, is what conditions the solve (9.7). That the routine\n * harness captures no probe grid is recorded as a gap, not fixed here.\n *\n * Rendered, on the rows the wave's acceptance names: the light 1x solid\n * cells go from 0.087 to 0.016 mean |rim − reference| per side (worst 0.168\n * → 0.033) and `dark-solid__rrect-md` from 0.068 to 0.227 against the\n * reference's 0.229.\n *\n * W22 G1 declined this constant on the same rows and that decline is not\n * rewritten (claims §5.94 §3): it was read through the declared box's 3 CSS\n * px band, whose peak-row mean over a dark backdrop carries the corners'\n * backdrop and dilutes a one-pixel line, and it was the right answer to the\n * question that instrument asked. The contour read is a different question.\n */\n rimAlpha: 0.844,\n /*\n * FITTED 1.35 (W23 G1; claims §5.100 §5, Decision Log 2 (d)) — the band at\n * dpr 2, about 10 % narrower than at dpr 1.\n *\n * Two clauses of the wave meet on this constant and they pull opposite\n * ways, which is why it is not simply the minimiser of one of them. The\n * uncollapsed 2x solids want the band NARROW: at 1.5 `dark-solid__rrect-md`\n * reads +0.2467 against the reference's +0.2052 on the light bed, and the\n * rendered ladder point at 1.2 reads +0.1883, so the row's own answer is\n * 1.29. The COLLAPSED cells want it wide, because `rimCollapsed` was\n * fitted through this same band: at 1.5 they read −0.0017 from the\n * reference and at 1.2 −0.0059, which is outside the wave's 0.005.\n *\n * 1.35 leaves the solids at +0.0123 against a bound of 0.03 and the\n * collapsed sides at 0.0038 against a bound of 0.005 — each clause inside\n * its own bound with margin in proportion to how tight that bound is. The\n * joint minimiser over the twelve rows is 1.30, and it is not taken: at\n * 1.30 the collapsed sides read 0.0045 against a 0.005 bound, a margin of\n * 0.0005 on an instrument whose 8-bit resolution at that level is 0.00067.\n *\n * The dark bed does not identify it — its one 2x solid row moves by 0.0061\n * across the whole ladder and is inside the bound at every value — so this\n * is the light bed's constant, checked against the dark bed rather than\n * fitted on it.\n */\n rimWidth2x: 1.35,\n specularPower: 6,\n /*\n * FITTED 0.55 → 0 (W22 G1; claims §5.94 §3, W22 Decision Log 2 (b)). The\n * light reference's rim has no vertical light in it, and the constant that\n * said it did had been fitting a defect.\n *\n * What was measured: the declared-geometry rim per side (the box's outer\n * 3 CSS px, a peak per side) on the five untinted solid calibration cells\n * of the light bed — `light-solid__{capsule-button,rrect-md,rrect-ml}` and\n * `dark-solid__{capsule-button,rrect-md}` — at both backing scales, over\n * eight rendered documents differing in this constant alone.\n *\n * Why per contrast rather than per side: a side's peak under the declared\n * box mixes rim with the background the rounded shape leaves inside a\n * rectangle's band, and the mixture's weight differs between the horizontal\n * and the vertical pair, so only `T−B` and `L−R` — two sides of identical\n * geometry — are clean. A mean pooled over sides is worse than unclean: it\n * PREFERS 0.55, because the specular lifts `dark-solid__rrect-md`'s top row\n * from −0.061 to +0.062 against a reference of +0.047 while leaving its\n * bottom at −0.061 against the same +0.047. It buys one side of a pair by\n * breaking the other, and only the contrast can see that.\n *\n * The rows, and what they say: eleven of the twenty contrast rows separate\n * the constant, and every one of them minimises at 0. The objective is\n * monotone in the gain on both contrasts — mean |Δ| over the separating\n * rows 0.00097 at 0 rising to 0.03102 at 0.55 — and the separating row is\n * `dark-solid__rrect-md` `T−B` at both scales, where the reference splits\n * top from bottom by +0.0002 and this constant at 0.55 splits them by\n * +0.1237 (1x) and +0.1817 (2x).\n *\n * Why it survived three waves of rim work: until W22 gated the specular\n * sweep on a shimmer amplitude, the highlight pass parked a stationary band\n * on the left edge of every resting surface, so `L−R` was unreadable and\n * `T−B` was being fitted beside a defect worth 0.12–0.15 of luminance. With\n * the band gone the reference's own structure is legible — left equal to\n * right to 0.0002, top over bottom by +0.0002 over a dark backdrop and\n * +0.0086…+0.0162 over a bright one — and this term is an order of\n * magnitude larger than anything it was supposed to be reproducing.\n *\n * The `clear` variant's 0.45 does not move: no scene on the calibration bed\n * declares that variant, so it has no rows and nothing to be fitted on.\n * `lightDirection` and `rimAlpha` were read on the same rows and declined\n * (claims §5.94 §3); the direction still feeds the inner shadow through\n * `platform-web`'s `light.xy`, and it is only on the RIM that this fit\n * makes it inert.\n */\n specularGain: 0,\n /*\n * FITTED −0.628 (W23 G1; claims §5.100 §4, W23 Decision Log 2 (a)) — the\n * light rim is a fraction of the body's HEADROOM, and the negative sign is\n * the measurement.\n *\n * On the reference's own solid, unclipped, uncollapsed light sides — 44 of\n * them, bodies 0.4287…0.9326, from both canonical scales and W9's probe\n * grid — the rim falls as the surface brightens: `0.3559 − 0.2752 × base`,\n * mean |residual| 0.0081 where an additive constant reads 0.0249 and a pure\n * screen 0.0168. A pure screen would need the slope to be exactly −α; it is\n * −0.275 against the −0.43 the screen form requires, which the canonical\n * bed's two cells at 0.43 and 0.48 could not have told apart and the probe\n * grid's range can. So the light rim is a white line composited source-over\n * — the form the CSS tier's inset `box-shadow` has always drawn — with an\n * additive part beside it, and this is that composite written once.\n *\n * The gain is steeper here (−0.628) than on the reference (−0.2752) for the\n * same reason `rimAlpha` is larger than the rim: this constant multiplies\n * the shader's per-pixel `rimLuma` before the band weight, and the fit is\n * the one solved on rendered rows.\n */\n rimLevelGain: -0.628,\n /*\n * ADOPTED 1.15 (W24 G2, on G0's fit; claims §5.108 §1, W24 Decision Log 2\n * (a)) — one exponent for both schemes and both scales, and the value at\n * which the most rows meet the wave's clause.\n *\n * The rows, and what they separate. Fitted on the reference's own angular\n * bins over the nineteen untinted solid cells of both canonical beds and\n * both probe grids (285 bins, each cell normalised by its own brightest\n * bin), the joint minimiser is 1.05; the 2x rows — whose arcs the raster\n * actually resolves — give 1.10 light and 1.30 dark, and vitrea's own\n * rendered rows read against the reference give 1.10 ± 0.22 light and\n * 1.24 ± 0.17 dark. The schemes OVERLAP, so what the rows separate is one\n * constant and not two, and 1.15 is where four of the twelve solid rows\n * meet both halves of clause 1 against two at 1.00, two at 1.30 and none\n * at 1.45.\n *\n * What it is not. It is not a per-scale pair: every 2x row wants 1.30–1.45\n * and every 1x row 0.85–1.10, which is a real scale dependence in the\n * reference's own angular contrast (its lit-diagonal bins over its\n * straight-side bins read 1.07 at 1x against 1.39 at 2x on the dark\n * `dark-solid` capsule). A `rimLitExponent2x` sibling on the precedent of\n * `rimWidth2x` would be a third constant fitted on four rows, so the\n * dependence is recorded (W24's Deferred list) rather than carried.\n *\n * The `clear` variant keeps 0 below: no scene on either bed declares it, so\n * it has no rows and nothing to be fitted on (C9a §6.2).\n *\n * RE-FITTED 1.15 → 0.85 (W25 G3b, on the parent's ruling; claims §5.115,\n * W25 Decision Log 6), JOINTLY with `rimAlongSideSlope` below and not\n * separately, because the two multiply the same rim amplitude and both peak\n * on this same diagonal. W24 fitted this exponent with the position term\n * ABSENT, over 285 bins that include the corner arcs, so it absorbed part of\n * a grading that is not a function of the normal at all — and W25 G0's\n * along-side reader, which walks only the STRAIGHT part of a side where this\n * factor is exactly 1, could not see the overlap from its side either.\n * W25 G3's dry run measured the consequence: at slope 0.45 under exponent\n * 1.15 the NW and SE bins of the 1x light `dark-solid__rrect-md` went 0.142\n * → 0.203 against a reference of 0.122, and the thick solids' mean bin error\n * rose on 26 rows of 28.\n *\n * The joint fit is a rendered GRID over the plane — 46 points, each a real\n * render of the solid rows of all four standard profiles, read by W24's\n * angular reader and W25's along-side reader together\n * (`results/2026-09-09-w25-thick-span-composite/g3/g3b-fit.txt`). The pair\n * below is the joint objective's minimum among the pairs that keep the thick\n * solids' angular error at or under the 0.13.0 bed's — the ruling's own\n * acceptance condition — AND that leave every cell of the bed measurable:\n * thick bin error 0.17527 → 0.17208 and thick range error 0.43269 → 0.37472,\n * on 16 rows improving against 12. The objective's own minimum over the\n * allowed set is (0.70, 0.15), and it is refused for a reason no metric\n * carries: at that pair the collapsed `dark-solid__capsule-button` loses its\n * contour on the GPU tier at 1x in both schemes — the capsule's band is\n * entirely corner arc, which is where both of these factors dim it, and the\n * extractor reads a 0.00 px contour and drops two calibration cells out of\n * the bed. A change that narrows the instrument is not a fidelity gain.\n */\n rimLitExponent: 0.85,\n /*\n * W25's along-side field, FITTED (claims §5.113 and §5.115; W25 Decision\n * Log 3 (c), landed at G3's declaration).\n *\n * Its own readers want more of it: G2 fitted 0.45 on the 64 straight sides\n * of the two 1x probe grids' flat solids and G3 re-fitted 0.425–0.479 on the\n * probe set's 64 sides at both scales in both schemes, and at 0.45 the\n * corner-to-corner range reaches 0.743 of the reference's against 0.227\n * without it. What the along-side reader cannot see is the corner ARCS,\n * where this factor multiplies a rim that `rimLitExponent` has already\n * brightened on the same diagonal — so the value here is not that fit's, it\n * is the JOINT one (W25 G3b; W25 Decision Log 6): the minimum over a\n * rendered grid of the two readers' errors together, among the pairs that\n * keep the thick solids' angular error at or under the 0.13.0 bed's.\n *\n * At (0.70, 0.15) the thick solids' bin error falls 0.17527 → 0.17000 and\n * their range error 0.43269 → 0.34919 — a fifth of the grading, where 0.45\n * under the old exponent bought three quarters of it and cost half again as\n * much bin error. The remaining four fifths are not this constant's to buy:\n * the arcs' amplitude is W23's rim law, fitted on the straight spans both of\n * these factors leave alone, and until it moves the two of them are trading\n * against each other rather than against Apple.\n *\n * The `clear` variant keeps 0 below, as the lit edge does: no scene on\n * either bed declares it, so it has no rows (C9a §6.2).\n */\n rimAlongSideSlope: 0.1,\n shadowDepth: 0.35,\n /*\n * REFITTED 0.55 → 0.05 (2026-08-31), and it is the largest single\n * improvement in the cascade: the objective falls 0.14615 → 0.09333 with\n * ΔE and SSIM both improving.\n *\n * The active reference's contour is BRIGHTER than its own body — a rim peak\n * of 0.025…0.129 above baseline, always at one pixel deep. vitrea's read\n * 0.0000 with its peak 8-12 px in, meaning it had no edge feature at all:\n * the inner shadow at 0.55 was darkening the contour faster than the rim lit\n * it. The rim constants themselves did not move; the thing suppressing them\n * did. On the inactive bed the reference's rim was 0.0000…0.0041 and this\n * was invisible, which is what §6.2 recorded as \"below quantisation\".\n */\n shadowAlpha: 0.05,\n highlight: srgbToLinear(SRGB_WHITE_TINT),\n },\n // Persistently more transparent, so it frosts less and tints less.\n clear: {\n blurSigma: 4,\n tint: srgbToLinear(SRGB_WHITE_TINT),\n tintAlpha: 0.1,\n rimWidth: 1.25,\n rimAlpha: 0.14,\n // No scene on the calibration bed declares this variant, so its rim has no\n // rows: the amplitude law stays at the additive form and the band stays\n // ungraded across the scales (W22's rule for `clear`, C9a §6.2).\n rimWidth2x: 1.25,\n specularPower: 8,\n specularGain: 0.45,\n rimLevelGain: 0,\n // No scene declares this variant, so the lit edge has no rows here either\n // and the factor stays inert (C9a §6.2, as `rimLevelGain` above).\n rimLitExponent: 0,\n // Nor does the along-side field have rows here, for the same reason.\n rimAlongSideSlope: 0,\n shadowDepth: 0.22,\n shadowAlpha: 0.4,\n highlight: srgbToLinear(SRGB_WHITE_TINT),\n },\n },\n\n /*\n * MEASURED (C9a): both ends are the same tint, which makes the crossover inert\n * by default. That is a finding, not a shortcut.\n *\n * The two ends used to straddle the backdrop — white over a dark backdrop,\n * near-black over a light one — so the material always contrasted with what was\n * behind it. Apple's Regular material does not do that. Its interior rises\n * monotonically with the backdrop across the whole canonical range (0.680 at a\n * backdrop of 0.003, 0.932 at 0.891, light scheme), which is a fixed tint at\n * partial transmission. What it keys on instead is the COLOUR SCHEME: over the\n * same bright checkerboard the reference sits at 0.809 in light and 0.055 in\n * dark. Leaving the inversion on cost more than the whole tint tune was worth —\n * it drove the light-scheme error from 0.348 to 0.449 on the interior-level\n * term alone.\n *\n * So the scheme picks the tint, and the calibration profiles carry one set of\n * numbers per scheme (packages/calibration/profiles/). The crossover mechanism\n * is untouched and still available to a profile that wants it; the default\n * simply no longer claims a behaviour the reference does not have.\n *\n * Two limits worth naming. The ends are global rather than per-variant, so the\n * clear variant inherits this — and clear has no calibration scenes at all, so\n * it is uncalibrated either way. And nothing yet selects a profile from the\n * scheme; that is C9a's parent-impact item.\n */\n adaptiveTintDark: srgbToLinear(SRGB_WHITE_TINT),\n adaptiveTintLight: srgbToLinear(SRGB_WHITE_TINT),\n adaptiveLuminanceLow: 0.12,\n adaptiveLuminanceHigh: 0.42,\n\n // Authored in `@vitrea/policy` alongside the ladder it is keyed by, because the\n // CSS tier needs the same table and used to hold two more copies of it\n // (Decision Log #23(d)). The profile is still what the shaders read and still\n // what `withMaterialOverrides` replaces — only the *default* literal moved, and\n // it moved unchanged.\n refractionScale: DEFAULT_REFRACTION_SCALE,\n\n /*\n * MEASURED (W2), against the settled apple-macos-26.5 bed, and set from the\n * REFERENCE's own size-dependence rather than from the objective's minimum.\n *\n * The band was 28…420 while it served the lens alone and nothing had measured\n * it, which put the whole canonical range (32…160 px) inside the first 17% of\n * the curve. What the settled reference actually does, over a fixed checkerboard\n * backdrop: it passes 0.244 of the backdrop's contrast at a 32 px span, 0.230 at\n * 44 px and 0.144 at 96 px. So 6% of the movement happens between 32 and 44 and\n * the rest between 44 and 96, and it is finished by 96 — which is what these two\n * numbers are. `sizeSpanMin` is also the smallest canonical component's span, so\n * that component is the law's exact zero by construction.\n *\n * The tuning objective would rather have 64 (0.1568 against 0.1637 on the rest\n * cells, a 4% win inside a grid that spans 1.07×). Declined, and the reason is\n * recorded rather than the win taken: the gain comes entirely from the interior\n * *level* term, whose residual is the backdrop tone-adaptation gap that wave\n * child W7 is chartered to close — so a band fitted to 64 would be using the\n * size law as a proxy for a mechanism vitrea does not have yet, against the\n * reference's own measurement of where its size-dependence lives, and W7 would\n * have to unpick it. See the claims doc's size-law section.\n */\n sizeSpanMin: 32,\n sizeSpanMax: 96,\n // The inner shadow's depth gain since W12 G2 (the lens reads its own law\n // below); the value is W2's, unchanged.\n lensSizeGainMax: 2.6,\n\n /*\n * MEASURED (W2), each with its own status — see the fields' notes.\n *\n * `sizeScatterGainMax` = 1: implemented on both tiers and inert, because the\n * canonical fixtures cannot resolve it. The objective is flat to 1.00× over\n * gains 1…6, and that is not the backdrop chain's depth talking: re-run with the\n * chain deepened (MIN_LEVEL_EXTENT 8 → 4, which lifts the reachable σ on the\n * 320×200 canvas from 1.2× to 2.4×) the grid is still flat to 1.00× and still\n * best at 1. A number the fixtures cannot see is a number that will be met by\n * accident, so this ships at the identity with the mechanism in place.\n *\n * `sizeOcclusionGain` = 0: fitted, and the fit is a boundary optimum with real\n * leverage against it — the objective rises monotonically, 0.168 → 0.224 across\n * 0…0.5, a 1.33× spread. The diagnosis is not a tuning failure: vitrea's\n * interior sits 0.16–0.19 above the reference's at every span because the\n * reference's level is set by backdrop tone adaptation toward roughly 0.63 while\n * vitrea lerps toward a white tint, so making a large surface *more* opaque can\n * only take it further from the reference. The facet is Apple's (\"a larger size\n * is more opaque\"); the axis that would let it fit is W7's.\n *\n * `sizeShadowGainMax` = 1.4: fitted on the calibration REST cells, where the\n * grid 1.0/1.2/1.4/1.6/1.8/2.2 reads 0.1577/0.1551/0.1533/0.1530/0.1529/0.1531.\n * 1.4 through 2.2 are one flat region (0.25% apart); 1.4 is the point inside it\n * that costs the checks least (ΔE 0.01282 against the baseline's 0.01290, SSIM\n * 0.9671 against 0.9689) and it is the per-cell minimum on both well-conditioned\n * span-96 rest cells. The pressed cells prefer 2.4 monotonically and are\n * excluded from the fit on §6.3's grounds — their native side carries no press\n * pose, so they compare two different states and cannot arbitrate a material\n * constant.\n *\n * ## Re-fitted against the ACTIVE bed (2026-08-31)\n *\n * `sizeScatterGainMax` stays 1 and is now POSITIVELY identified rather than\n * flat: with `blurSigma` refitted to 3 the objective rises 6-7% at gains 2 and\n * 4, so the identity is the optimum instead of a tie.\n *\n * `sizeOcclusionGain` stays 0, a boundary result for the fourth time and for a\n * fourth distinct reason. The reasoning above is retired: the per-cell residual\n * now points the gain's way in every backdrop (web − reference falls with span\n * — checkerboard +0.105/+0.112/+0.046 at 32/44/96 px, photo −0.004/−0.087,\n * light-solid −0.028/+0.001), so the facet finally has the right sign. What it\n * does not have is magnitude: over 0/0.05/0.10/0.15 × spans ending 96/128/160\n * the whole grid is flat to 1.04×, and a 0.2% preference is not evidence. It\n * ships at the identity because the bed cannot identify it, not because the\n * mechanism is wrong.\n *\n * ## Re-fitted against the FROZEN bed (2026-09-01)\n *\n * `sizeOcclusionGain` 0 → **0.05**, and this is the first time the bed could\n * see it. Every earlier fit was a boundary result because calibration held no\n * span above `sizeSpanMax`, so the curve this gain rides was saturated at every\n * cell that could vote. The frozen bed adds three span-128 `rrect-ml`\n * calibration cells, and with them the grid stops being flat: 0.05 is the\n * optimum at **both** backing scales independently — 1× 0.08288 against the\n * identity's 0.08374, 2× 0.09338 against 0.09557 — and ΔE and SSIM move the\n * same way at both.\n *\n * It is still a small number and it is reported as one: a 1.0% preference at\n * 1×, against the 0.2% this doc rightly refused a round ago. What changed is\n * not the margin's size but that it now reproduces on an independent profile\n * instead of resting on one flat grid.\n *\n * `sizeSpanMax` stays 96, and that is now a measurement rather than an\n * assumption. With a span-128 cell voting, the grid rises monotonically —\n * 96/112/128/144/160/192 reading 0.0837/0.0858/0.0943/0.1060/0.1171/0.1300 —\n * so the band's top is where it was, and the suspicion that the bed simply\n * could not see above it is answered rather than inherited.\n *\n * `sizeShadowGainMax` 1.4 → 1. Its evidence dissolved rather than reversing:\n * this is a gain on the INNER SHADOW, and the inner shadow was refitted from\n * `shadowAlpha` 0.55 to 0.05, so there is almost nothing left for it to gain\n * on. The grid 1.0/1.4/2.2 is flat to 0.2%. Carrying a fitted-looking 1.4 whose\n * measurement no longer exists would be the worse of the two errors.\n */\n // MEASURED (W11c G1, claims §5.41): the scatter facet off the identity, on\n // its own curve — see `MaterialProfile.sizeScatterFloor`. The paragraph\n // above records why the identity was the right answer while `blurSigma`\n // was 3 and the bed had no pitch axis; the W9 probe's pitch axis is what\n // identified the two-component interior this expresses.\n sizeScatterGainMax: 8,\n sizeScatterFloor: 0.4,\n sizeScatterSpanMax: 256,\n // The second scale, FITTED by W15 G1's runtime sweep at dpr 2 and landed\n // (claims §5.70 §2 and §8): the gain 4.8 — a heavy width of 6 device px, the\n // sweep's own interior minimum and narrower than G0's Gaussian estimate — the\n // deep value fully heavy, and the span top left at the 1x value because a\n // floor of 1 leaves it nothing to rise to. Read only above dpr 1, so the 1x\n // material is byte-identical to the W13 bed (see\n // `MaterialProfile.sizeScatterFloor2x`).\n sizeScatterGainMax2x: 4.8,\n sizeScatterFloor2x: 1,\n sizeScatterSpanMax2x: 256,\n // The 2x gain's own span grading (W15 G1's re-form, claims §5.70 §8; W15\n // Decision Log 3), set from G0's independent per-span reading — 8 device px\n // at span 96 and 11 at 160 — and not from the holdout row it fixes.\n sizeScatterGainFar2x: 9.9,\n // The 1x three FITTED in the renderer (W13 G1's third sweep, 44 points over\n // the calibration bed: `results/2026-09-03-w13-ramp/g1/sweep-3/g1-sweep-3.md`\n // §3); the 2x three PROVISIONAL still, because at them the excursion is\n // bit-exactly zero on the whole bed and a sweep cannot fit what does not\n // move (§4). The thin anchor 0.72 is above G0's read-off of 0.637–0.642: the\n // grid runs 0.60 / 0.64 / 0.68 and the refinement 0.72 / 0.76, and 0.72 is an\n // interior optimum of both the interior objective and the interior gap. The\n // thick anchor 0.52 is G0's `rrect-md` reading and is above that cell's deep\n // sharp share of 0.481, where the joint thick fit of 0.47 would have clamped\n // it to nothing. The 2x three are G0's readings, LANDED by W15 G1 (claims\n // §5.70 §2): thin is G0's u 6 reading and stage 2b's best, thick and far are\n // one number because G0 read the 2x start flat across the thick spans, and\n // with the deep value now fully heavy at that ratio the ramp is the whole\n // body above it rather than the null W13 recorded. See\n // `MaterialProfile.sizeScatterRampStartThin1x`.\n sizeScatterRampStartThin1x: 0.72,\n sizeScatterRampStartThick1x: 0.52,\n sizeScatterRampStartFar1x: 0.2,\n sizeScatterRampStartThin2x: 0.46,\n sizeScatterRampStartThick2x: 0.21,\n sizeScatterRampStartFar2x: 0.21,\n sizeScatterRampReach1xPx: 80,\n sizeScatterRampReach2xPx: 100,\n\n // W25's three mechanisms, all INERT at the defaults (claims §5.113; W25\n // Decision Log 3). The heavy share's thick lift and the level term above the\n // knee are zero, so `kDeep` and the tone response's blend are the curves W11c\n // and W9 fitted, to the bit; the along-side field's slope lives on the optics\n // beside `rimLitExponent` and is zero there. G2 fits them and G3 declares\n // them; what the fits read is recorded in\n // `results/2026-09-09-w25-thick-span-composite/g2/`.\n sizeScatterHeavyShareThick1x: 0,\n sizeScatterHeavyShareThick2x: 0,\n sizeToneLevelFar: 0,\n\n // The heavy blur, FITTED (W26; claims §5.121 for the identification and §5.122\n // for the fit; W26 Decision Log 6 (a)). Apple's heavy width is 8.6–9.5 device px\n // at BOTH scales, read by the family reader — the one instrument in this wave\n // that passed a control, reproducing vitrea's own drawn width to 0.6 % — and\n // inverted through a ladder whose slope is 0.995–1.111 at an rms of 0.03–0.06\n // device px. What the 0.14.0 material drew at dpr 1 was `CHAIN_LEVEL_SIGMA[4]` =\n // 13.418, the pyramid's LAST level, because `scatterLod` was clamped there: half\n // again too wide, and the share the two previous waves tried to raise was already\n // right to within 0.07. The reference asks 9.48 / 8.63 / 9.19 at dpr 1 (spread\n // 9.8 %, so one number serves both spans) and 8.13 / 9.79 / 8.37 at dpr 2 (spread\n // 20.4 %, so one number does not — the 1.66 device px between spans 96 and 160 is\n // the grading `sizeScatterGainFar2x` used to carry, and one width per source\n // cannot; W26 Decision Log 2 (f) chose that knowingly). Nine is within 1.1 % of\n // the 1x mean and 0.4 % of the 2x light pair's, and it takes\n // |log(read / reference)| from 0.275 to 0.069 over six cells.\n //\n // THE MECHANISM HAS NO SMALL VALUES (W26 Decision Log 6 (c)). `pyramid.ts` builds\n // the heavy texture whenever `heavySigmaCss > 0`, and at σ 0.001 `heavyTapPlan`\n // selects chain level 0 with a residual of a thousandth of a texel — which makes\n // the deep sample the RAW backdrop and moves every 2x row. So 0.001 is not\n // \"almost off\"; it is the opposite of off. The inert value is exactly 0, and\n // neither anchor may ever carry a small non-zero. The domain is 0 or at least the\n // chain's level-1 width, and the tracker carries the floor that would close it.\n sizeHeavyTapSigma: 9,\n sizeHeavyTapSigma2x: 9,\n // W30 G2's spanning set for the scale-selective scatter, at the values that\n // make every term of it exactly zero (claims §5.156 §3, §5.158). The share is\n // the single gate: at 0 no second heavy texture is allocated, no pass is\n // encoded and no sample is taken, so the two widths are unread and the\n // reference is unreachable behind its own zero gain. The two signed amounts\n // are the scheme-conditioned leaves §5.159 fits; the widths and the reference\n // are one raster's property and are not.\n sizeHeavySecondSigma: 0,\n sizeHeavySecondSigma2x: 0,\n sizeHeavySecondShare: 0,\n sizeScatterScaleGain: 0,\n sizeScatterScaleRef: 0,\n sizeOcclusionGain: 0.05,\n sizeShadowGainMax: 1,\n\n /*\n * The lens (W12 G2, claims §5.51; Decision Log 3 of the W12 spec).\n *\n * MEASURED from the reference's own layer tree (§5.50): the inner refraction\n * amount and height laws, verified on spans 32 / 44 / 48 … 112 / 128 / 160\n * and the nested base at 130, and the ovalization's knee (0 through span 64,\n * 0.5 from 72). FITTED on the pixels (§5.51, a 2-D band renderer validated on\n * this renderer's own capture): the gain, the extent and the exponent, on\n * `rrect-md` + `-ml` at 1x pitches 16 and 32 with `rrect-lg` held out at both\n * scales; the ovalization's effective value on the box-inscribed ellipse.\n * Predicted before the landing capture: checkerboard SSIM 1x md / ml / lg\n * 0.954 / 0.931 / 0.929 → 0.970 / 0.946 / 0.942, 2x 0.939 / 0.902 / 0.901 →\n * 0.950 / 0.918 / 0.918, the capsule 0.977 → 0.985.\n *\n * What W11c G2 recorded here — 1.6 lens depths on the square profile, fitted\n * per depth shell — was the band's mean, not its shape (§5.48, §5.49); it is\n * kept in git history and in claims §5.43.\n */\n lensRefractionGain: 0.745,\n lensHeightPerSpan: 0.25,\n lensHeightMax: 20,\n lensAmountPerSpan: 0.8,\n lensAmountMax: 60,\n lensThicknessReference: 8,\n lensExtentGain: 1.337,\n lensProfileExponent: 3.69,\n // 0.8 by eye (W12 Decision Log 6). The pixels preferred 0.6 by a hair — every\n // texture row that can see ω scores 0.001–0.002 lower at 0.8 (claims §5.54) —\n // but the field's measured tilt sits at 0.8–1.0 (§5.49 §3) and the user read\n // the 0.8 sheet as much closer to macOS; the eye overrides a margin that small,\n // and §5.54 §1's rows are the recorded cost.\n lensOvalization: 0.8,\n lensOvalizationSpanMin: 64,\n lensOvalizationSpanMax: 72,\n\n reducedTransparencyFrost: 1.75,\n increasedOcclusionLift: INCREASED_OCCLUSION_LIFT,\n strongBorderRim: { rimWidth: 2, rimAlpha: 0.95 },\n reducedTintAdaptation: 0.35,\n\n /*\n * MEASURED (W10, 2026-09-02) — per-pixel least squares of the reference's\n * tinted pixel against its own untinted pixel on the five W9-probe tinted\n * checkerboard cells (pitch 4…64 px, 17 700 px): shade = 0.5289 + 0.4886·u,\n * RMS 0.0035. Out of sample on the canonical bed the orange cells fit at\n * RMS 0.003 with zero bias; blue sits 0.011 darker (the second hue's\n * residual, recorded and unmodelled). The light end extrapolates past 1 and\n * is clamped in `tintShade`. Claims §5.36.\n *\n * §5.13's earlier \"the curve is the identity\" fit was made on the material's\n * MEAN over solid backdrops, where u is either ~0.97 (shade 1.0) or the\n * collapse has already folded the shade out — the identity was the law's\n * two endpoints, seen without anything between them.\n */\n tintShadeDark: 0.5289,\n tintShadeLight: 1.0175,\n tintShadeStrength: 1,\n\n /*\n * MEASURED (W7), against the settled apple-macos-26.5 bed, on the light and\n * dark standard profiles jointly and at both scales.\n *\n * The observable these four are set from is the one quantity in this bed that\n * isolates adaptation from everything else: the *separation* between the light\n * and dark references over the same backdrop, on the same component. Under this\n * mechanism that separation is `(1 − tintAlpha)(1 − a)(tintLight − tintDark)`,\n * so the material's transmission, the backdrop's structure and each scheme's\n * own tint all cancel and what is left is `a`. Normalised at the checkerboard,\n * where nothing adapts, it reads:\n *\n * span 44: 0.000 at backdrop 0.500, 0.030 at 0.205, 1.000 at 0.0117, 1.000 at 0.0049\n * span 96: 0.000 at backdrop 0.500, 0.028 at 0.216, 0.256 at 0.0117\n *\n * and the 2× bed reproduces every one of those to three decimals (0.2553\n * against 0.2556 on the one that is not a boundary). Two facts follow. The\n * adaptation is off across the whole ordinary range and turns on only below\n * roughly a fifth of the backdrop scale — so it cannot disturb a cell that\n * already passes. And it is size-gated hard: same backdrop, same material, 1.000\n * against 0.256.\n *\n * The band's dark end is not identifiable from this bed and the fit says so:\n * the reference's backdrops jump from 0.0117 to 0.205 with nothing in between,\n * so `backdropToneLow` is bounded only by \"at or below the darkest calibration\n * backdrop\". What the two dark backdrops DO pin is the curve's slope near zero —\n * the 96 px surface reads 0.256 at 0.0117 and 0.356 at 0.0039, which is a\n * measured intermediate rather than a step, and it is what fixes\n * `backdropToneSizeBias` against `backdropToneHigh`. `impulse__rrect-md__rest`\n * is a VALIDATION cell and was not fitted to: the calibration set predicts\n * 0.34 there and the cell reads 0.356.\n */\n /*\n * RE-SCOPED (W9, claims §5.33). The four mix constants now own TEXTURE\n * COLLAPSE alone — the interior mean moved to the response law below — and\n * their band contracts to the one domain the collapse is real in: full at\n * `dark-solid` (0.0117) for thin surfaces including the 44 px capsule\n * (byte-identical collapse, arg 0.0164 ≤ low with margin), zero by\n * `mid-dark-solid` (0.0595), where the reference's small surface keeps a\n * textured body at 0.4561 and the old band's partial collapse (k = 0.81)\n * was the measured 0.1375-vs-0.4561 overshoot. `impulse__rrect-md`\n * (arg 0.0539) keeps k ≈ 0.003 against the old band's 0.008 — the same\n * unadapted render that cell validated.\n */\n backdropToneMax: 1,\n backdropToneLow: 0.02,\n backdropToneHigh: 0.055,\n /*\n * REFITTED 0.09 → 0.13 (2026-08-31, active bed). The law's SHAPE is untouched\n * (Decision Log 13 stands; the two-axis rework is next wave) and `max`, `low`\n * and `high` are unmoved — only the size gate widened.\n *\n * What it changes is one cell: a 96 pt surface over the darkest backdrop now\n * barely adapts, where at 0.09 it adapted by a quarter. Two independent reads\n * of the reference disagreed about that and the validation set broke the tie.\n * The light-versus-dark separation estimator §5.8 fitted on says the 96 pt\n * surface adapts by 0.30; the reference's own interior LEVEL says it does not\n * (0.4844, against 0.466 for an unadapted surface at the refitted tint alpha\n * and 0.3566 for an adapted one). Measured once on\n * `impulse__rrect-md__rest`, which is validation and was fitted to by\n * neither: 0.09 renders 0.2858 against a reference of 0.4358 at ΔE 0.02344;\n * 0.13 renders 0.4594 at ΔE 0.00378, six times better. The separation\n * estimator's algebra assumes the two colour schemes share one tint alpha,\n * and this profile pair does not (0.46 against 0.97) — recorded in §5.13 as\n * the reason it is no longer the primary evidence for this constant.\n *\n * RE-SCOPED 0.13 → 0.05 with the band above (W9): the bias's one remaining\n * job is keeping the thick surface's collapse argument above `high` at the\n * dark anchor (0.0117 + 0.05 = 0.0617 > 0.055) while the thin capsule's\n * stays below `low` — the near-binary size snap the probe measured\n * (claims §5.33). The smooth size trend on structured backdrops, which the\n * old wide band tried and failed to carry, belongs to the response law's\n * thickness axis now.\n */\n backdropToneSizeBias: 0.05,\n\n /*\n * FITTED 0.017 at dpr 1 and 0.070 at dpr 2 (W24 G1, landed by G2; claims\n * §5.108 §2, W24 Decision Log 2 (b) and (d)) — one pair for both schemes, on\n * the peak of the collapsed `impulse__capsule-button`'s centre dot.\n *\n * At `k` 1 the composite is exactly `(1 − c)·toneColour + c·backdrop`, so the\n * dot's excess is LINEAR in this constant and one non-zero rendered rung fixes\n * it: at c 0.10 vitrea's collapsed capsule passes +0.0386 at 1x and +0.0363 at\n * 2x where the reference passes +0.0066 and +0.0254, which gives 0.0171 and\n * 0.0700. Rendered back at the fit the dot lands +0.0067 and +0.0256 —\n * clause 2's peak met to ±0.0002 against a bound of 0.005 — and the structure\n * that had been passing 0.0000 passes 0.0066 at 1x and 0.0250 at 2x against\n * the reference's 0.0104 and 0.0205.\n *\n * The light and dark rungs read the same numbers to four decimals on that\n * cell, which is why this is one pair in both schemes and lives on the shared\n * default rather than in a per-scheme patch. What separates the two ANCHORS is\n * the kernel and not the scheme: the reference transmits through σ 2.63 device\n * px at 1x and 1.30 at 2x — invariant in neither CSS nor device pixels — where\n * vitrea's runs 1.68 → 4.86, so the SHARE that comes through cannot be one\n * number over a width that is two. How wide the dot ARRIVES is the material's\n * own scatter law and is a recorded gap, not a fit (the dot's FWHM lands 4.99\n * CSS px at 1x against the reference's 7.57, and 4.64 against 3.80 at 2x).\n *\n * What it costs the bed is two cells. `impulse__capsule-button` at 2x pays\n * ΔE +0.00006 and `ssimMean` −0.00096 while its `ssimMin` improves by 0.068\n * and its interior level closes 68 % of its gap; `impulse__rrect-md` at 1x\n * improves; every other capture on both beds is byte-identical, including\n * `dark-solid__capsule-button`, the collapsed stop, where a solid backdrop\n * makes the target's lerp the identity by construction.\n *\n * The correction this constant carries is set beside W7's paragraph above, not\n * over it: \"texture collapse\" was fitted on `dark-solid`, where a mean and a\n * pixel are the same number and no fit could have told them apart. Every\n * figure W7 recorded stands; what it did not measure is what happens over a\n * backdrop that HAS texture, and the impulse bed says the reference keeps it.\n */\n collapseTransmission: 0.017,\n collapseTransmission2x: 0.07,\n\n /*\n * **SHIPS AT 0** (W31 G3; claims §5.164). The identity, and a post-seal leaf's\n * default IS its identity, forever: `MATERIAL_IDENTITY_TABLE` is append-only\n * and the fingerprint drops this leaf while it holds this value, so a default\n * that moved off 0 would move every shipped document's digest at once.\n *\n * The macOS 27 documents carry their fitted values as patches; the two frozen\n * macOS 26.5 documents carry none, which is what makes their recorded digests\n * reproduce under the rule (claims §5.161 §7b).\n */\n bodyChromaRetention: 0,\n\n /*\n * FITTED 0.038 (W23 G1; claims §5.100 §3, W23 Decision Log 2 (b)) — and it is\n * NOT the dark material's rim, which is the one thing the charter thought it\n * might be.\n *\n * The reference's collapsed rim, read at the contour over 11 cells and 28\n * sides of both beds at both scales, is +0.0189 mean (+0.0196…+0.0204 over\n * `dark-solid`, +0.0149…+0.0168 over `impulse` — the spread is the backdrop,\n * not noise). The dark material's OWN rim over the same backdrop, uncollapsed,\n * is +0.0256…+0.0258. The two are 0.0068 apart, nine 8-bit codes at that level\n * on an instrument that is exact in float and resolves 0.00067 there, so the\n * collapsed rim is an absolute constant in its own units and the charter's\n * conditional resolves to no.\n *\n * 0.038 is the minimiser over every collapsed side: the worst residual reads\n * 0.0042 at 0.035, **0.0031 at 0.038**, 0.0041 at 0.040 and 0.0065 at 0.045,\n * and it is the only value that leaves every untinted collapsed side inside\n * the wave's clause 1 (0.005) with margin. Rendered, the collapsed sides go\n * from 0.0180 to 0.0021 mean |rim − reference|.\n *\n * The per-row answers span 0.0317…0.0441, which under a rule that refuses a\n * constant its rows do not separate (C9a §6.2) needs a stated reason: the rows\n * disagree because the REFERENCE's own collapsed rim differs by backdrop —\n * +0.0200 over `dark-solid` against +0.0158 over `impulse` — and not because\n * the constant is unidentified on vitrea's side, where the leverage is exactly\n * linear and every row reads the same slope.\n *\n * The collapsed BODY is read and not chased: 0.01103 native against 0.01171\n * web over `dark-solid` (+1.05 codes) and 0.00664 against 0.00367 over\n * `impulse` (−6.2 codes). This constant does not touch it.\n */\n rimCollapsed: 0.038,\n\n /*\n * REFITTED 0.337 → 0.520 (W23 G3; claims §5.102) under the painted rim's own\n * composition. The reference's collapsed tint-orange capsule keeps +0.1149 of\n * contour rim at 1x and +0.1179 at 2x where the bare one keeps +0.0200, and\n * the drawn rim is linear in this constant, so one rendered point per scale\n * gives each row its own answer.\n *\n * It moved because the LIGHT is now spent differently, not because the reading\n * did. `rimTintChroma` spends a painted surface's rim in the paint's own\n * chromaticity, and an orange paint's red channel is already at 255, so the\n * share of the light that goes there is lost to the raster: at 0.337 the\n * collapsed painted rim fell from +0.115 to +0.072 against a reference of\n * +0.118. The constant carries what the composition costs, which is what an\n * absolute constant is for.\n *\n * The per-side answers are 0.510 at 1x and 0.544 at 2x — the difference is the\n * band, which is scale-graded and this constant is not — and 0.520 is the\n * minimiser over all twelve sides, worst residual 0.0055. The three non-holdout\n * cells that carry it (`dark-solid__capsule-button__rest-tint-orange` and\n * `impulse__capsule-button__rest-tint-orange` on the light bed and\n * `dark-solid__capsule-button__rest-tint-orange` on the dark one) answer the\n * same value in both schemes, because the constant is absolute (X4).\n */\n rimCollapsedTinted: 0.52,\n\n /*\n * FITTED 1 (W23 G3; claims §5.102) — the rim's light on a painted surface is\n * spent ENTIRELY in the paint's own chromaticity.\n *\n * The rows do not merely prefer it, they ask for more than the constant can be:\n * over 52 tinted sides of both beds at both scales the per-side answer is\n * 0.921…1.732 with a mean of 1.154, and the objective is monotone up to the\n * bound. A mix weight cannot exceed 1, so 1 is both the fit and the ceiling,\n * and what the rows are really saying past it is that the tinted rows' AMOUNT\n * is short in the dark scheme — which is the amplitude law's residual and not\n * this constant's (see below).\n *\n * Rendered, mean |Δ| of the contour row's OKLab against the reference's, over\n * every tinted side of both beds at both scales: **b 0.0554 → 0.0093** and\n * **a 0.0399 → 0.0222**, with the sides outside the wave's 0.02 falling from\n * 52 of 52 to 36. The whole of the remaining 36 is `a` on the dark bed's tinted\n * rows, where vitrea's rim is 0.031 against a reference of 0.127: a rim that\n * dim cannot move its row's hue whatever colour it is spent in, so that\n * residual is the dark law's amount and is recorded as one.\n */\n rimTintChroma: 1,\n\n /*\n * MEASURED (W9 probe, claims §5.30–§5.33): the anchors are the probe bed's\n * settled reference levels, frequency-settled over seven attested runs,\n * under the probe's own native-mask interior. Thick rows pool the 96 px\n * and 160 px rrects (±0.012). Not tuned; re-measured only by a new probe.\n */\n backdropToneAnchorX: [0.1104, 0.2706, 0.9505],\n backdropToneResponseThin: [0.0126, 0.4561, 0.9713],\n backdropToneResponseThick: [0.4953, 0.5744, 0.9358],\n backdropToneResponseStrength: 1,\n\n /*\n * FITTED (recalibration cascade, 2026-08-31). W8's geometry SURVIVES the fit\n * unchanged — `sigmaPx` 15.55, `offsetPx` 7.95, `spreadPx` 3.10 — and only the\n * two amplitudes moved: `occlusion` 0.33 → 0.285 and\n * `reducedTransparencyOcclusion` 0.566 → 0.70. The dark scheme's amplitude\n * (0.09) lands as a profile patch, not as a branch here.\n *\n * The fit is `scripts/sweep.ts --objective shadow`, whose term is the mean over\n * calibration cells of |Δ meanDeparture| — the light each side removes from the\n * whole exterior, in linear light, which is the one commensurate quantity the\n * facet has. The amplitude is a genuine interior optimum over 0.18…0.44 (a\n * 2.23× spread) and flat to 1.04% across 0.255…0.315, which is exactly the\n * scene-to-scene amplitude spread the reference itself shows. The geometry is\n * NOT identifiable against this objective — σ ∈ {13.5, 15.55, 17.5} × offset ∈\n * {6.5, 7.95, 9.4} spans 1.04× with 15.55 the argmin — because an integral over\n * the exterior is insensitive to how the darkening is distributed within it.\n * W8's own two-dimensional fit against the occlusion field measures the\n * geometry far more powerfully (RMS 0.0021 over 142,550 pixels), and the\n * instrument's independent shadow axis agrees, so the geometry stands on those\n * two and this objective is not asked to re-decide it.\n *\n * `reducedTransparencyOcclusion` 0.70 was sharp where the amplitude was flat: a\n * 3.83× spread over 0.45…0.95 with a clear minimum. It also reconciled two\n * routes — 0.285 × 0.70 = 0.1995 against the reference's directly measured\n * reduce-transparency amplitude of 0.203 at a 44 px span. W8's 0.566 was the\n * ratio of the reference's two amplitudes; that was the ratio that made\n * vitrea's shadow match the reference's under the preference, and the two\n * differed because the base amplitude is a compromise across scenes whose\n * spread is much wider in the standard profile than under reduced transparency.\n * **W14 G1 re-forms the constant as the LEVEL those routes were reconciling\n * to** — 0.197 absolute, replacing both regimes rather than scaling them — for\n * the reason its doc comment gives: a ratio and a level stopped being the same\n * thing when the single amplitude became six unequal anchors.\n *\n * Extracted from the active bed's native fixtures directly —\n * `results/2026-08-31-active-bed-stage0.json` measured the gap, these numbers\n * measure the facet — and left provisional deliberately: X1 gives the fit to\n * the recalibration cascade, which owns the holdout discipline. This child owns\n * the mechanism.\n *\n * Method: for each `rest` fixture, the occlusion field `1 − L_capture/L_background`\n * in linear Rec.709 luminance, over every pixel outside the declared component\n * geometry with a backdrop bright enough to carry a signal; fitted in two\n * dimensions against `occlusion · Φ(−sd/σ)`, where `sd` is the signed distance\n * to the component's own rounded silhouette translated down by `offsetPx` and\n * outset by `spreadPx`.\n *\n * The fit and its residual, on `1x-light-standard` and `2x-light-standard`:\n *\n * backdrop span occlusion σ (1×/2×) offset (1×/2×) RMS\n * photo 44 0.323 15.5/31.1 7.9/15.8 0.0021\n * checkerboard 44 0.338 15.7/31.0 8.0/15.9 0.0016\n * hc-text 44 0.339 15.7/31.1 8.0/15.9 0.0014\n * photo 32 0.321 15.5/30.9 8.1/16.2 0.0018\n * mid-dark-solid 44 0.310 — — 0.0079\n *\n * — against a peak occlusion of 0.24, so the model carries the facet to under\n * 1% of its own amplitude, over up to 142,550 pixels per cell. The three\n * lengths are the consensus across every well-conditioned cell; `occlusion` is\n * the light-standard amplitude at a span the size law leaves alone.\n *\n * What the amplitude does NOT yet have is a mechanism for its scene-to-scene\n * spread. Over the flat near-white `light-solid` backdrop the same fit reads\n * 0.123 rather than 0.33, reproducibly and at both scales, while the other flat\n * backdrop (`mid-dark-solid`, linear 0.0595) reads 0.310 — so it is not a\n * function of the backdrop's luminance, its structure, or the material's\n * interior level, and no compositing model in either colour space produces both.\n * The dark-scheme profile is a separate amplitude entirely (0.046…0.061 at a\n * 44 px span — the dark material's shadow is nearly invisible) and lands as a\n * profile patch, not as a branch here. Both are stated in the claims doc as the\n * open question the cascade's fit inherits.\n *\n * **W14 G1 answers that open question and replaces `occlusion`.** \"Over the\n * flat near-white `light-solid` backdrop the same fit reads 0.123 rather than\n * 0.33 … it is not a function of the backdrop's luminance\" was read on a bed\n * that had no backdrop between `hc-text` (linear 0.74) and `light-solid`\n * (0.891): it IS a function of the backdrop's luminance, and the whole factor\n * of 2.6 happens inside the gap the bed cannot see (claims §5.62 §5). The\n * single amplitude becomes six anchors on two regimes — three in backdrop\n * luminance below the knee, three in span above it — plus the lift's four\n * constants. The three lengths are untouched; G0 re-read them free on both\n * terms and they came back at W8's values.\n */\n outerShadow: {\n offsetPx: 7.95,\n sigmaPx: 15.55,\n // W30 G2's σ law, at the three zeros that make it the identity (claims\n // §5.156 §2, §5.158): σ(span) = sigmaPx + max(0, 0 · (span − 0)) = sigmaPx,\n // at every span and every scale. The macOS 26.5 material's σ genuinely is\n // span-invariant — 15.4…15.9 CSS px across spans 32…160 — so these zeros are\n // that measurement and not a placeholder for it.\n sigmaSlopePerSpan: 0,\n sigmaSpanRefPx: 0,\n sigmaThinOffsetPx: 0,\n spreadPx: 3.1,\n thinOcclusionDark: 0,\n thinOcclusionMid: 0.33,\n thinOcclusionBright: 0.127,\n thickOcclusionAt96: 0.37,\n thickOcclusionAt128: 0.448,\n thickOcclusionAt160: 0.479,\n liftAmplitude: 0.01,\n liftSpanMin: 64,\n liftSpanFull: 118,\n liftBlurSigmaCss: 40,\n reducedTransparencyOcclusion: 0.197,\n sizeGain: 0,\n },\n\n lightDirection: [-0.3714, -0.9285],\n rimLitAxis: [-0.7071, -0.7071],\n sweepBandRadians: 0.55,\n glowRadiusCss: 44,\n glowGain: 0.6,\n sweepGain: 0.85,\n};\n\n/**\n * One entry of the inert-identity table the material's fingerprint is taken\n * under (W31 Decision Log 1 (a), ruled 2026-09-21; claims §5.161 §7b, §5.164).\n *\n * A gate leaf is a leaf with a declared inert identity. `gated` names the leaves\n * that entry makes UNREAD while every gate leaf holds its identity — leaves with\n * no identity of their own to be at, because what makes them inert is the gate\n * and not their own value.\n */\nexport interface MaterialIdentityEntry {\n /** The wave that added the entry. */\n readonly wave: string;\n /** Gate leaf (dotted path into the resolved material) → its inert identity. */\n readonly gate: Readonly<Record<string, number>>;\n /** The leaves the gate makes unread; empty for a plain value drop. */\n readonly gated: readonly string[];\n /** The law the entry is an identity of, as the material's own doc comment states it. */\n readonly law: string;\n /** The committed unit case that proves the drop, named file and case. */\n readonly inertLawCase: string;\n /** Why the gated leaves cannot reach the pixels while the gate is held. */\n readonly whyGated: string;\n /** The ledger sections the entry executes. */\n readonly claims: string;\n /**\n * Where the entry's prose was declared BEFORE the operator existed, kept\n * verbatim (the `$comment-superseded` idiom of `identity-table.json`).\n *\n * The gate, the gated leaves and the identity values are append-only and are\n * never edited. `law` and `inertLawCase` are prose about them, and W31's\n * declaration could not name a case for a leaf that did not exist yet; where\n * such a line is sharpened the first wording is preserved here rather than\n * overwritten, and `w31-identity-table.test.ts` requires exactly that.\n */\n readonly declaredFirstAs?: { readonly law: string; readonly inertLawCase: string };\n}\n\n/**\n * **The version of the digest rule, recorded in every document sealed under it.**\n *\n * Rule **1** is the plain fingerprint of the fully resolved material: every leaf\n * hashed, whatever it holds. Every document sealed before W31 G3 carries a rule-1\n * digest and `profiles/digest-supersessions.json` is rule 1's history.\n *\n * Rule **2** is this one — the same fingerprint with `MATERIAL_IDENTITY_TABLE`'s\n * entries dropped where their gates hold. A document sealed under it records\n * `resolvedMaterialSha256Rule: 2` beside its digest, so a recorded digest names\n * the function that produced it and a reader never has to guess which.\n */\nexport const MATERIAL_DIGEST_RULE_VERSION = 2;\n\n/**\n * **The inert-identity table the material's fingerprint is taken under** — a\n * committed, tested, APPEND-ONLY constant (W31 Decision Log 1 (a); claims\n * §5.161 §7b).\n *\n * ## The rule\n *\n * The fingerprint is taken over the fully resolved material with every entry\n * below removed whose gate leaves ALL hold their declared identity values. An\n * entry with no gated leaves is an ordinary value drop: the leaf goes when it\n * holds its identity. An entry WITH gated leaves is a **gate-group** and goes as\n * one unit; a gated leaf's own value is never dropped on its own, because a\n * gated leaf has no identity of its own to be at.\n *\n * ## Why it exists\n *\n * Every profile document's `resolvedMaterialSha256` is a digest over the fully\n * resolved material, so a material that GAINS a key moves every document's\n * digest whatever that key holds — including the two frozen macOS 26.5\n * documents, whose pixels do not move at all. W30 spent the one X1 exemption W29\n * Decision Log 7 (a) granted on exactly that, for eight leaves at algebraic\n * identities (claims §5.158). Under this rule an operator landing at its\n * identity moves no document's digest, the two frozen documents' recorded\n * digests are the live fingerprint again, and no wave spends an exemption for an\n * inert leaf.\n *\n * ## Why the table is append-only, and what that costs\n *\n * A post-seal leaf's default IS its identity, forever: the digests recorded\n * against this table are computed with these leaves dropped at these values, so\n * moving a default off its identity here would move every shipped document's\n * digest at once. Removing an entry would do the same. So entries are added and\n * never edited, and a leaf's DEFAULT is the thing that may not move rather than\n * the documents' patches — a document is free to carry any value it measures.\n *\n * ## Why only the gate-group needs the unit case\n *\n * A plain value drop is injective for free: every resolved material carries\n * every key, so two materials with the same post-drop object agree on the\n * dropped leaves too (both hold the identity) and therefore agree everywhere. A\n * gate-group drop is NOT free — it merges every material that shares a gate at\n * its identity whatever the gated leaves hold — and it is sound only because the\n * gated leaves provably cannot reach the PIXELS while the gate is at its\n * identity. That is what `inertLawCase` names, per entry.\n *\n * The pixels, and not the uniform bytes: a gated leaf still travels to the GPU\n * (the scatter reference occupies two lanes of the optics uniform), so two\n * materials the digest merges do not write identical uniform bytes. They draw\n * identical pixels, and the digest is over what draws.\n *\n * ## The holes, named rather than discovered\n *\n * (a) A **mis-declared identity** is the one with teeth, and it is the\n * gate-group's; mitigated by the `inertLawCase` each entry is required to name.\n * (b) A **default that moves to a value some document explicitly carried** drops\n * out of that document's digest if the identity moved with it; narrow, because\n * the identity is this append-only constant and not the default. (c) A **leaf\n * added without a table entry** is carried at whatever it holds, so every digest\n * moves — the loud failure, and the one W30 actually hit. (d) The **rule's own\n * version**, closed by construction through `MATERIAL_DIGEST_RULE_VERSION`.\n */\nexport const MATERIAL_IDENTITY_TABLE: readonly MaterialIdentityEntry[] = [\n {\n wave: \"W30\",\n /*\n * A TWO-LEAF gate, and the second leaf is in it rather than gated by it.\n * `sigmaThinOffsetPx` is not gated by the slope — at slope 0 a non-zero\n * offset moves σ at every span — and it is not inert on its own at a\n * non-zero slope either, where it is a real floor on the line. What the\n * committed case proves is the pair TOGETHER, and the grouping that would\n * put the offset under the slope's gate merges a macOS 26.5 light material\n * carrying `sigmaThinOffsetPx` 5 — five CSS px of extra blur on every outer\n * shadow, on both tiers — into the frozen digest itself (claims §5.161 §11,\n * finding B4 (b)).\n */\n gate: { \"outerShadow.sigmaSlopePerSpan\": 0, \"outerShadow.sigmaThinOffsetPx\": 0 },\n gated: [\"outerShadow.sigmaSpanRefPx\"],\n law: \"σ(span) = sigmaPx + max(sigmaThinOffsetPx, sigmaSlopePerSpan·(span − sigmaSpanRefPx))\",\n inertLawCase:\n 'packages/renderer-webgpu/test/w31-gate-groups.test.ts — \"gate-group 1 — ' +\n '{sigmaSlopePerSpan 0, sigmaThinOffsetPx 0} gates sigmaSpanRefPx\"; with the ' +\n \"shipped-value half in w30-inert-laws.test.ts\",\n whyGated:\n \"The pivot is multiplied by the slope, so at slope 0 no value of it can reach σ. \" +\n \"The offset is NOT gated by the slope and is in the gate for that reason.\",\n claims: \"c9a §5.156 §2, §5.158, §5.161 §7b\",\n },\n {\n wave: \"W30\",\n gate: { sizeHeavySecondShare: 0 },\n gated: [\"sizeHeavySecondSigma\", \"sizeHeavySecondSigma2x\"],\n law: \"deep = heavy + sizeHeavySecondShare·(heavy2 − heavy), heavy2 at sizeHeavySecondSigma{,2x}\",\n inertLawCase:\n 'packages/renderer-webgpu/test/w31-gate-groups.test.ts — \"gate-group 2 — ' +\n '{sizeHeavySecondShare 0} gates the two second-heavy widths\"; with the ' +\n \"shipped-value half in w30-inert-laws.test.ts\",\n whyGated:\n \"At share 0 the second heavy texture is not allocated, no pass is encoded and the \" +\n \"optics pass never samples one, so the widths are unread whatever they hold.\",\n claims: \"c9a §5.156 §3, §5.158, §5.161 §7b\",\n },\n {\n wave: \"W30\",\n gate: { sizeScatterScaleGain: 0 },\n gated: [\"sizeScatterScaleRef\"],\n law: \"kScatter += sizeScatterScaleGain·(stat − sizeScatterScaleRef)\",\n inertLawCase:\n 'packages/renderer-webgpu/test/w31-gate-groups.test.ts — \"gate-group 3 — ' +\n '{sizeScatterScaleGain 0} gates sizeScatterScaleRef\"; with the shipped-value ' +\n \"half in w30-inert-laws.test.ts\",\n whyGated:\n \"The reference is only ever read as a difference the gain multiplies, so at gain 0 no \" +\n \"value of it can reach the mix. The macOS 27 LIGHT document exercises this entry: it \" +\n \"declines the scatter with the gain at 0 and ships the reference at 0.03.\",\n claims: \"c9a §5.156 §3, §5.158, §5.161 §7b\",\n },\n {\n wave: \"W31\",\n /*\n * A plain value drop, and injective for free. The retention multiplies the\n * mix's second term, so at 0 the composite is bit-identical to the one W30\n * left — which is what the goldens and the composite-identity case below\n * assert, and what lets this leaf land without an exemption.\n */\n gate: { bodyChromaRetention: 0 },\n gated: [],\n law: \"colour = gamutAtLuma(mix(colour, backdrop·(Y/Y_backdrop), bodyChromaRetention), Y)\",\n inertLawCase:\n 'packages/renderer-webgpu/test/w31-body-chroma.test.ts — \"the composite is ' +\n 'bit-identical at retention 0\", \"linear luma is held at every retention\" and \"is the ' +\n 'shader\\'s expression, term for term\"; the drawn half in ' +\n 'packages/renderer-webgpu/e2e/gpu/w31-body-chroma.spec.ts — \"is bit-identical at the ' +\n 'shipped identity, named explicitly\" and \"ON draws differently from OFF\"; the CSS ' +\n \"tier's half in packages/platform-web/test/w30-css-declaration-identity.test.ts, \" +\n \"which compares every declaration against bytes recorded before any leaf existed\",\n whyGated:\n \"Not gated — a plain value drop. At retention 0 the mix's second term is multiplied \" +\n \"by zero and `colour` leaves the composite exactly as mix(backdrop, adapted, \" +\n \"presentAlpha) produced it.\",\n claims: \"c9a §5.161 §5, §5.164\",\n declaredFirstAs: {\n law:\n \"colour = renormaliseToLinearLuma(mix(colour, chromaticityOf(backdrop) at colour's \" +\n \"luma, bodyChromaRetention))\",\n inertLawCase:\n \"TO BE COMMITTED BY W31 G3 — the leaf does not exist yet. G0 names the shape and its \" +\n \"identity (W31 X2); the case that proves the composite is bit-identical at 0, and the \" +\n \"`test:gpu` case that the on state draws differently from off, land with the leaf.\",\n },\n },\n];\n\n/**\n * A value at a dotted path of a resolved material, or `undefined`.\n *\n * Exported because every reader of the rule needs it and three copies of a path\n * walk is three places a gate can be read from the wrong node.\n */\nexport function materialLeafAt(resolved: unknown, path: string): unknown {\n return path.split(\".\").reduce<unknown>(\n (node, key) =>\n node !== null && typeof node === \"object\" ? (node as Record<string, unknown>)[key] : undefined,\n resolved,\n );\n}\n\n/**\n * The dotted leaf paths `MATERIAL_IDENTITY_TABLE` drops from this material's\n * fingerprint, sorted.\n *\n * A gate leaf the material does not HAVE is not \"at its identity\" — it is\n * absent, and an entry naming it is a table that has drifted from the material.\n * Such an entry is not dropped, so the drift shows as a moved digest rather than\n * as a silent merge.\n */\nexport function materialDigestDroppedLeaves(resolved: unknown): readonly string[] {\n const dropped: string[] = [];\n for (const entry of MATERIAL_IDENTITY_TABLE) {\n const held = Object.entries(entry.gate).every(([path, identity]) => {\n const value = materialLeafAt(resolved, path);\n return value !== undefined && value === identity;\n });\n if (held) dropped.push(...Object.keys(entry.gate), ...entry.gated);\n }\n return dropped.sort();\n}\n\n/**\n * **The digest rule's input**: a copy of the resolved material with the dropped\n * leaves removed. Hash this, not the material.\n *\n * The one implementation of the rule. The HASH itself stays duplicated at each\n * pin site on purpose — an algorithm restated is an algorithm two places can\n * check, and the sorted-key SHA-256 has been read three ways since W7 — but the\n * rule is a table walk whose drift would be silent, so it lives here and is\n * imported.\n *\n * Removal rather than substitution, so a dropped leaf cannot be confused with a\n * leaf that happens to hold a sentinel, and so a table naming a leaf the\n * material does not have shows up as a key-set difference.\n */\nexport function materialDigestInput(resolved: unknown): unknown {\n const dropped = materialDigestDroppedLeaves(resolved);\n const strip = (value: unknown, prefix = \"\"): unknown => {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return value;\n return Object.fromEntries(\n Object.entries(value)\n .map(([key, child]) => [prefix === \"\" ? key : `${prefix}.${key}`, key, child] as const)\n .filter(([path]) => !dropped.includes(path))\n .map(([path, key, child]) => [key, strip(child, path)]),\n );\n };\n return strip(resolved);\n}\n\n// The default profile's numbers, under the names the rest of the package and its\n// tests already know them by. Derived rather than duplicated: a re-tuned default\n// moves both at once, and there is no second place for the two to disagree.\nexport const REFRACTION_SCALE = DEFAULT_MATERIAL_PROFILE.refractionScale;\nexport const MATERIAL_OPTICS = DEFAULT_MATERIAL_PROFILE.optics;\nexport const ADAPTIVE_TINT_DARK = DEFAULT_MATERIAL_PROFILE.adaptiveTintDark;\nexport const ADAPTIVE_TINT_LIGHT = DEFAULT_MATERIAL_PROFILE.adaptiveTintLight;\nexport const ADAPTIVE_LUMINANCE_LOW = DEFAULT_MATERIAL_PROFILE.adaptiveLuminanceLow;\nexport const ADAPTIVE_LUMINANCE_HIGH = DEFAULT_MATERIAL_PROFILE.adaptiveLuminanceHigh;\nexport const SIZE_SPAN_MIN = DEFAULT_MATERIAL_PROFILE.sizeSpanMin;\nexport const SIZE_SPAN_MAX = DEFAULT_MATERIAL_PROFILE.sizeSpanMax;\nexport const LENS_SIZE_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.lensSizeGainMax;\nexport const SIZE_SCATTER_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.sizeScatterGainMax;\nexport const SIZE_SCATTER_FLOOR = DEFAULT_MATERIAL_PROFILE.sizeScatterFloor;\nexport const SIZE_SCATTER_SPAN_MAX = DEFAULT_MATERIAL_PROFILE.sizeScatterSpanMax;\nexport const SIZE_SCATTER_GAIN_MAX_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterGainMax2x;\nexport const SIZE_SCATTER_GAIN_FAR_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterGainFar2x;\nexport const SIZE_SCATTER_FLOOR_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterFloor2x;\nexport const SIZE_SCATTER_SPAN_MAX_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterSpanMax2x;\nexport const SIZE_SCATTER_RAMP_START_THIN_1X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThin1x;\nexport const SIZE_SCATTER_RAMP_START_THICK_1X =\n DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThick1x;\nexport const SIZE_SCATTER_RAMP_START_THIN_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThin2x;\nexport const SIZE_SCATTER_RAMP_START_THICK_2X =\n DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartThick2x;\nexport const SIZE_SCATTER_RAMP_START_FAR_1X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartFar1x;\nexport const SIZE_SCATTER_RAMP_START_FAR_2X = DEFAULT_MATERIAL_PROFILE.sizeScatterRampStartFar2x;\nexport const SIZE_SCATTER_RAMP_REACH_1X_PX = DEFAULT_MATERIAL_PROFILE.sizeScatterRampReach1xPx;\nexport const SIZE_SCATTER_RAMP_REACH_2X_PX = DEFAULT_MATERIAL_PROFILE.sizeScatterRampReach2xPx;\nexport const SIZE_OCCLUSION_GAIN = DEFAULT_MATERIAL_PROFILE.sizeOcclusionGain;\nexport const SIZE_SHADOW_GAIN_MAX = DEFAULT_MATERIAL_PROFILE.sizeShadowGainMax;\nexport const LENS_REFRACTION_GAIN = DEFAULT_MATERIAL_PROFILE.lensRefractionGain;\nexport const LENS_HEIGHT_PER_SPAN = DEFAULT_MATERIAL_PROFILE.lensHeightPerSpan;\nexport const LENS_HEIGHT_MAX = DEFAULT_MATERIAL_PROFILE.lensHeightMax;\nexport const LENS_AMOUNT_PER_SPAN = DEFAULT_MATERIAL_PROFILE.lensAmountPerSpan;\nexport const LENS_AMOUNT_MAX = DEFAULT_MATERIAL_PROFILE.lensAmountMax;\nexport const LENS_THICKNESS_REFERENCE = DEFAULT_MATERIAL_PROFILE.lensThicknessReference;\nexport const LENS_EXTENT_GAIN = DEFAULT_MATERIAL_PROFILE.lensExtentGain;\nexport const LENS_PROFILE_EXPONENT = DEFAULT_MATERIAL_PROFILE.lensProfileExponent;\nexport const LENS_OVALIZATION = DEFAULT_MATERIAL_PROFILE.lensOvalization;\nexport const BACKDROP_TONE_MAX = DEFAULT_MATERIAL_PROFILE.backdropToneMax;\nexport const BACKDROP_TONE_LOW = DEFAULT_MATERIAL_PROFILE.backdropToneLow;\nexport const BACKDROP_TONE_HIGH = DEFAULT_MATERIAL_PROFILE.backdropToneHigh;\nexport const BACKDROP_TONE_SIZE_BIAS = DEFAULT_MATERIAL_PROFILE.backdropToneSizeBias;\nexport const COLLAPSE_TRANSMISSION = DEFAULT_MATERIAL_PROFILE.collapseTransmission;\nexport const COLLAPSE_TRANSMISSION_2X = DEFAULT_MATERIAL_PROFILE.collapseTransmission2x;\nexport const BACKDROP_TONE_ANCHOR_X = DEFAULT_MATERIAL_PROFILE.backdropToneAnchorX;\nexport const BACKDROP_TONE_RESPONSE_THIN = DEFAULT_MATERIAL_PROFILE.backdropToneResponseThin;\nexport const BACKDROP_TONE_RESPONSE_THICK = DEFAULT_MATERIAL_PROFILE.backdropToneResponseThick;\nexport const BACKDROP_TONE_RESPONSE_STRENGTH =\n DEFAULT_MATERIAL_PROFILE.backdropToneResponseStrength;\nexport const OUTER_SHADOW = DEFAULT_MATERIAL_PROFILE.outerShadow;\n\n/**\n * A profile patch: any subset, to any depth, of what a profile holds.\n *\n * A colour is one leaf, not three: patching a tint means naming the whole triple,\n * because two channels of a fitted colour and one of the default is not a colour\n * anybody measured.\n */\nexport interface MaterialProfilePatch {\n readonly optics?: Readonly<Partial<Record<MaterialVariant, Readonly<Partial<MaterialOptics>>>>>;\n readonly adaptiveTintDark?: Rgb;\n readonly adaptiveTintLight?: Rgb;\n readonly adaptiveLuminanceLow?: number;\n readonly adaptiveLuminanceHigh?: number;\n readonly refractionScale?: Readonly<Partial<Record<RefractionQuality, number>>>;\n readonly sizeSpanMin?: number;\n readonly sizeSpanMax?: number;\n readonly lensSizeGainMax?: number;\n readonly sizeScatterGainMax?: number;\n readonly sizeScatterFloor?: number;\n readonly sizeScatterSpanMax?: number;\n readonly sizeScatterGainMax2x?: number;\n readonly sizeScatterFloor2x?: number;\n readonly sizeScatterSpanMax2x?: number;\n readonly sizeScatterGainFar2x?: number;\n readonly sizeScatterRampStartThin1x?: number;\n readonly sizeScatterRampStartThick1x?: number;\n readonly sizeScatterRampStartFar1x?: number;\n readonly sizeScatterRampStartThin2x?: number;\n readonly sizeScatterRampStartThick2x?: number;\n readonly sizeScatterRampStartFar2x?: number;\n readonly sizeScatterRampReach1xPx?: number;\n readonly sizeScatterRampReach2xPx?: number;\n readonly sizeScatterHeavyShareThick1x?: number;\n readonly sizeScatterHeavyShareThick2x?: number;\n readonly sizeToneLevelFar?: number;\n readonly sizeHeavyTapSigma?: number;\n readonly sizeHeavyTapSigma2x?: number;\n readonly sizeHeavySecondSigma?: number;\n readonly sizeHeavySecondSigma2x?: number;\n readonly sizeHeavySecondShare?: number;\n readonly sizeScatterScaleGain?: number;\n readonly sizeScatterScaleRef?: number;\n readonly sizeOcclusionGain?: number;\n readonly sizeShadowGainMax?: number;\n readonly lensRefractionGain?: number;\n readonly lensHeightPerSpan?: number;\n readonly lensHeightMax?: number;\n readonly lensAmountPerSpan?: number;\n readonly lensAmountMax?: number;\n readonly lensThicknessReference?: number;\n readonly lensExtentGain?: number;\n readonly lensProfileExponent?: number;\n readonly lensOvalization?: number;\n readonly lensOvalizationSpanMin?: number;\n readonly lensOvalizationSpanMax?: number;\n readonly reducedTransparencyFrost?: number;\n readonly increasedOcclusionLift?: number;\n readonly increasedOcclusionLiftByPolicy?: Readonly<Partial<MaterialOcclusionLiftByPolicy>>;\n readonly strongBorderRim?: Readonly<Partial<MaterialRim>>;\n readonly reducedTintAdaptation?: number;\n readonly tintShadeDark?: number;\n readonly tintShadeLight?: number;\n readonly tintShadeStrength?: number;\n readonly tintChromaScale?: number;\n readonly tintShadeCollapseRetention?: number;\n readonly backdropToneMax?: number;\n readonly backdropToneLow?: number;\n readonly backdropToneHigh?: number;\n readonly backdropToneSizeBias?: number;\n readonly collapseTransmission?: number;\n readonly collapseTransmission2x?: number;\n readonly bodyChromaRetention?: number;\n readonly rimCollapsed?: number;\n readonly rimCollapsedTinted?: number;\n readonly rimTintChroma?: number;\n readonly backdropToneAbscissa?: MaterialProfile[\"backdropToneAbscissa\"];\n readonly backdropToneAnchorX?: BackdropToneKnotRow;\n readonly backdropToneResponseThin?: BackdropToneKnotRow;\n readonly backdropToneResponseThick?: BackdropToneKnotRow;\n readonly backdropToneResponseStrength?: number;\n readonly outerShadow?: Readonly<Partial<MaterialOuterShadow>>;\n readonly lightDirection?: readonly [number, number];\n readonly rimLitAxis?: readonly [number, number];\n readonly sweepBandRadians?: number;\n readonly glowRadiusCss?: number;\n readonly glowGain?: number;\n readonly sweepGain?: number;\n}\n\n/**\n * The names `outerShadow` no longer answers to, and what each was replaced by.\n *\n * `occlusion` was W8's single span-flat amplitude, and it is the leaf a caller\n * reaches for to stand the facet down (`{ outerShadow: { occlusion: 0 } }`).\n * W14 G1 retired it: the amplitude is a two-regime law now, and a patch naming\n * the retired leaf would type-check nowhere but pass through JSON, get hashed\n * into a capture cell as the configuration that ran, and render the DEFAULT\n * shadow — a silently-measured-the-defaults failure of exactly the shape\n * `capture-web.ts`'s unknown-key guard exists for, one level deeper.\n *\n * It is refused rather than mapped. A span-flat scalar is the material the\n * measurement retired: there is no value of it that reproduces 0.33 below the\n * knee and 0.544 above it, so translating one would be inventing a reading, and\n * the project carries no compatibility shims.\n */\nconst RETIRED_OUTER_SHADOW_LEAVES: Readonly<Record<string, string>> = {\n occlusion:\n \"the six amplitude anchors (thinOcclusionDark, thinOcclusionMid, \" +\n \"thinOcclusionBright, thickOcclusionAt96, thickOcclusionAt128, \" +\n \"thickOcclusionAt160) and liftAmplitude for the second term\",\n};\n\n/** Throw if an `outerShadow` patch names a leaf W14 G1 retired (claims §5.62). */\nfunction rejectRetiredOuterShadowLeaves(patch: object | undefined): void {\n if (patch === undefined) return;\n for (const [leaf, replacement] of Object.entries(RETIRED_OUTER_SHADOW_LEAVES)) {\n if (!(leaf in patch)) continue;\n throw new Error(\n `outerShadow.${leaf} was retired by W14 G1 (claims §5.62) and is replaced by ` +\n `${replacement}. Applying this patch would have rendered the default shadow ` +\n `while recording itself as configured. It is refused rather than mapped: a ` +\n `single span-flat amplitude is the material the measurement retired.`,\n );\n }\n}\n\n/**\n * Throw if the resolved backdrop tone response's three rows disagree about how\n * many knots the curve has.\n *\n * The rows are one curve — `backdropToneAnchorX` is its knots and the two\n * response rows are that curve's levels at the thin and the thick end — but they\n * are three separate patch keys, so a patch naming one of them at four knots\n * over a three-knot base used to resolve to a triplet with no single reading.\n * The CPU curve branches on the ANCHORS' length and then indexes the level rows\n * at that arity, so a four-knot anchor row over three-knot levels reads past the\n * end and returns NaN for the whole interior. The shader keys the same flag off\n * the anchors (`passes.ts`, `d[115]`) but pads the level rows with a repeat of\n * their last knot, so it draws a fourth segment nobody fitted. The CSS tier's\n * mirror in `@vitreajs/vitrea-web` reads the third of those. A patch that would\n * make the tiers draw different materials is refused here rather than resolved,\n * which is the same stance `rejectRetiredOuterShadowLeaves` takes above: a\n * configuration that cannot be rendered honestly does not get to be measured.\n *\n * The rows may move to four knots — that is what the dark receded endpoint does\n * — but only together, and the message names each row's resolved arity so it\n * says which of the three the patch left behind.\n */\nfunction rejectMixedBackdropToneArity(\n anchorX: BackdropToneKnotRow,\n thin: BackdropToneKnotRow,\n thick: BackdropToneKnotRow,\n): void {\n /*\n * Each row is an array of one of the curve's two lengths, checked before the\n * three are compared to each other.\n *\n * Equal arity alone is not enough, because the readers do not agree on what\n * \"not three\" means. A profile document is JSON cast to the patch type with\n * nothing between, so three FIVE-knot rows arrive with their arities equal: the\n * CPU curve and the CSS mirror branch on `length === 3`, fail it and run the\n * four-knot arithmetic, while the shader's gate is `length === 4` (`passes.ts`\n * `d[115]`), fails THAT and runs the three-knot branch. One document, two\n * different curves, and the fifth knot dropped by every reader. Two knots is\n * the same trap from the other end, where each branch indexes past the row.\n */\n for (const [name, row] of [\n [\"backdropToneAnchorX\", anchorX],\n [\"backdropToneResponseThin\", thin],\n [\"backdropToneResponseThick\", thick],\n ] as const) {\n if (Array.isArray(row) && (row.length === 3 || row.length === 4)) continue;\n throw new Error(\n `The backdrop tone response's ${name} is ${JSON.stringify(row) ?? String(row)}, which ` +\n `is not an array of three or four knots. The curve has exactly those two forms, and ` +\n `anything else is read as a different one by each tier: the CPU curve and the CSS ` +\n `mirror take the four-knot branch for any length but three, where the shader takes ` +\n `the three-knot branch for any length but four.`,\n );\n }\n if (anchorX.length === thin.length && thin.length === thick.length) return;\n throw new Error(\n `The backdrop tone response's three rows resolved to different knot counts — ` +\n `backdropToneAnchorX ${anchorX.length}, backdropToneResponseThin ${thin.length}, ` +\n `backdropToneResponseThick ${thick.length}. They are one curve's knots and that ` +\n `curve's levels at its two thickness ends, and the shader reads the knot count off ` +\n `the anchors alone, so a mixed triplet renders as NaN on the CPU curve and as a ` +\n `fabricated segment on the GPU. A patch moving the response to a new knot count has ` +\n `to name all three rows.`,\n );\n}\n\n/**\n * Apply a patch. This is how a calibration profile lands: C7 emits the measured\n * numbers, the host passes them here, and every constant above is replaceable\n * without touching this file.\n *\n * The nested records merge per field and per rung, so a patch naming one tint\n * alpha keeps that variant's blur, rim and specular rather than dropping them.\n */\nexport function withMaterialOverrides(\n base: MaterialProfile,\n patch: MaterialProfilePatch,\n): MaterialProfile {\n rejectRetiredOuterShadowLeaves(patch.outerShadow);\n const backdropToneAbscissa = patch.backdropToneAbscissa === undefined\n ? base.backdropToneAbscissa : patch.backdropToneAbscissa;\n if (backdropToneAbscissa !== undefined && backdropToneAbscissa !== \"source\" &&\n (backdropToneAbscissa === null || typeof backdropToneAbscissa !== \"object\" ||\n backdropToneAbscissa.kind !== \"silhouette\" ||\n Object.keys(backdropToneAbscissa).some((key) => key !== \"kind\"))) {\n throw new TypeError(\"backdropToneAbscissa must be source or { kind: silhouette }\");\n }\n\n\n const optics = {} as Record<MaterialVariant, MaterialOptics>;\n for (const variant of MATERIAL_VARIANTS) {\n optics[variant] = { ...base.optics[variant], ...patch.optics?.[variant] };\n }\n\n const refractionScale = {} as Record<RefractionQuality, number>;\n for (const rung of REFRACTION_LADDER) {\n refractionScale[rung] = patch.refractionScale?.[rung] ?? base.refractionScale[rung];\n }\n\n // Resolved before the profile is built rather than merged inline below, so the\n // three rows of one curve can be checked against each other while they are\n // still three things. See `rejectMixedBackdropToneArity`.\n const backdropToneAnchorX = patch.backdropToneAnchorX ?? base.backdropToneAnchorX;\n const backdropToneResponseThin =\n patch.backdropToneResponseThin ?? base.backdropToneResponseThin;\n const backdropToneResponseThick =\n patch.backdropToneResponseThick ?? base.backdropToneResponseThick;\n rejectMixedBackdropToneArity(\n backdropToneAnchorX, backdropToneResponseThin, backdropToneResponseThick,\n );\n\n return {\n optics,\n adaptiveTintDark: patch.adaptiveTintDark ?? base.adaptiveTintDark,\n adaptiveTintLight: patch.adaptiveTintLight ?? base.adaptiveTintLight,\n adaptiveLuminanceLow: patch.adaptiveLuminanceLow ?? base.adaptiveLuminanceLow,\n adaptiveLuminanceHigh: patch.adaptiveLuminanceHigh ?? base.adaptiveLuminanceHigh,\n refractionScale,\n sizeSpanMin: patch.sizeSpanMin ?? base.sizeSpanMin,\n sizeSpanMax: patch.sizeSpanMax ?? base.sizeSpanMax,\n lensSizeGainMax: patch.lensSizeGainMax ?? base.lensSizeGainMax,\n sizeScatterGainMax: patch.sizeScatterGainMax ?? base.sizeScatterGainMax,\n sizeScatterFloor: patch.sizeScatterFloor ?? base.sizeScatterFloor,\n sizeScatterSpanMax: patch.sizeScatterSpanMax ?? base.sizeScatterSpanMax,\n sizeScatterGainMax2x: patch.sizeScatterGainMax2x ?? base.sizeScatterGainMax2x,\n sizeScatterFloor2x: patch.sizeScatterFloor2x ?? base.sizeScatterFloor2x,\n sizeScatterSpanMax2x: patch.sizeScatterSpanMax2x ?? base.sizeScatterSpanMax2x,\n sizeScatterGainFar2x: patch.sizeScatterGainFar2x ?? base.sizeScatterGainFar2x,\n sizeScatterRampStartThin1x:\n patch.sizeScatterRampStartThin1x ?? base.sizeScatterRampStartThin1x,\n sizeScatterRampStartThick1x:\n patch.sizeScatterRampStartThick1x ?? base.sizeScatterRampStartThick1x,\n sizeScatterRampStartThin2x:\n patch.sizeScatterRampStartThin2x ?? base.sizeScatterRampStartThin2x,\n sizeScatterRampStartThick2x:\n patch.sizeScatterRampStartThick2x ?? base.sizeScatterRampStartThick2x,\n sizeScatterRampStartFar1x: patch.sizeScatterRampStartFar1x ?? base.sizeScatterRampStartFar1x,\n sizeScatterRampStartFar2x: patch.sizeScatterRampStartFar2x ?? base.sizeScatterRampStartFar2x,\n sizeScatterRampReach1xPx: patch.sizeScatterRampReach1xPx ?? base.sizeScatterRampReach1xPx,\n sizeScatterRampReach2xPx: patch.sizeScatterRampReach2xPx ?? base.sizeScatterRampReach2xPx,\n sizeScatterHeavyShareThick1x:\n patch.sizeScatterHeavyShareThick1x ?? base.sizeScatterHeavyShareThick1x,\n sizeScatterHeavyShareThick2x:\n patch.sizeScatterHeavyShareThick2x ?? base.sizeScatterHeavyShareThick2x,\n sizeToneLevelFar: patch.sizeToneLevelFar ?? base.sizeToneLevelFar,\n sizeHeavyTapSigma: patch.sizeHeavyTapSigma ?? base.sizeHeavyTapSigma,\n sizeHeavyTapSigma2x: patch.sizeHeavyTapSigma2x ?? base.sizeHeavyTapSigma2x,\n // W30 G2's spanning set. One line each, because this merge is explicit per\n // leaf and a leaf without its own line resolves silently to the base —\n // which for a leaf a document is meant to fit is a fit that does nothing.\n sizeHeavySecondSigma: patch.sizeHeavySecondSigma ?? base.sizeHeavySecondSigma,\n sizeHeavySecondSigma2x: patch.sizeHeavySecondSigma2x ?? base.sizeHeavySecondSigma2x,\n sizeHeavySecondShare: patch.sizeHeavySecondShare ?? base.sizeHeavySecondShare,\n sizeScatterScaleGain: patch.sizeScatterScaleGain ?? base.sizeScatterScaleGain,\n sizeScatterScaleRef: patch.sizeScatterScaleRef ?? base.sizeScatterScaleRef,\n sizeOcclusionGain: patch.sizeOcclusionGain ?? base.sizeOcclusionGain,\n sizeShadowGainMax: patch.sizeShadowGainMax ?? base.sizeShadowGainMax,\n lensRefractionGain: patch.lensRefractionGain ?? base.lensRefractionGain,\n lensHeightPerSpan: patch.lensHeightPerSpan ?? base.lensHeightPerSpan,\n lensHeightMax: patch.lensHeightMax ?? base.lensHeightMax,\n lensAmountPerSpan: patch.lensAmountPerSpan ?? base.lensAmountPerSpan,\n lensAmountMax: patch.lensAmountMax ?? base.lensAmountMax,\n lensThicknessReference: patch.lensThicknessReference ?? base.lensThicknessReference,\n lensExtentGain: patch.lensExtentGain ?? base.lensExtentGain,\n lensProfileExponent: patch.lensProfileExponent ?? base.lensProfileExponent,\n lensOvalization: patch.lensOvalization ?? base.lensOvalization,\n lensOvalizationSpanMin: patch.lensOvalizationSpanMin ?? base.lensOvalizationSpanMin,\n lensOvalizationSpanMax: patch.lensOvalizationSpanMax ?? base.lensOvalizationSpanMax,\n reducedTransparencyFrost: patch.reducedTransparencyFrost ?? base.reducedTransparencyFrost,\n increasedOcclusionLift: patch.increasedOcclusionLift ?? base.increasedOcclusionLift,\n ...((patch.increasedOcclusionLiftByPolicy ?? base.increasedOcclusionLiftByPolicy) === undefined\n ? {}\n : { increasedOcclusionLiftByPolicy: {\n ...base.increasedOcclusionLiftByPolicy,\n ...patch.increasedOcclusionLiftByPolicy,\n } as MaterialOcclusionLiftByPolicy }),\n strongBorderRim: { ...base.strongBorderRim, ...patch.strongBorderRim },\n reducedTintAdaptation: patch.reducedTintAdaptation ?? base.reducedTintAdaptation,\n tintShadeDark: patch.tintShadeDark ?? base.tintShadeDark,\n tintShadeLight: patch.tintShadeLight ?? base.tintShadeLight,\n tintShadeStrength: patch.tintShadeStrength ?? base.tintShadeStrength,\n ...((patch.tintChromaScale ?? base.tintChromaScale ?? 1) === 1 ? {} : {\n tintChromaScale: patch.tintChromaScale ?? base.tintChromaScale,\n }),\n ...((patch.tintShadeCollapseRetention ?? base.tintShadeCollapseRetention ?? 0) === 0 ? {} : {\n tintShadeCollapseRetention: patch.tintShadeCollapseRetention ?? base.tintShadeCollapseRetention,\n }),\n backdropToneMax: patch.backdropToneMax ?? base.backdropToneMax,\n backdropToneLow: patch.backdropToneLow ?? base.backdropToneLow,\n backdropToneHigh: patch.backdropToneHigh ?? base.backdropToneHigh,\n backdropToneSizeBias: patch.backdropToneSizeBias ?? base.backdropToneSizeBias,\n collapseTransmission: patch.collapseTransmission ?? base.collapseTransmission,\n collapseTransmission2x:\n patch.collapseTransmission2x ?? patch.collapseTransmission ?? base.collapseTransmission2x,\n bodyChromaRetention: patch.bodyChromaRetention ?? base.bodyChromaRetention,\n rimCollapsed: patch.rimCollapsed ?? base.rimCollapsed,\n rimCollapsedTinted: patch.rimCollapsedTinted ?? base.rimCollapsedTinted,\n rimTintChroma: patch.rimTintChroma ?? base.rimTintChroma,\n ...(backdropToneAbscissa === undefined ? {} : { backdropToneAbscissa }),\n backdropToneAnchorX,\n backdropToneResponseThin,\n backdropToneResponseThick,\n backdropToneResponseStrength:\n patch.backdropToneResponseStrength ?? base.backdropToneResponseStrength,\n outerShadow: { ...base.outerShadow, ...patch.outerShadow },\n lightDirection: patch.lightDirection ?? base.lightDirection,\n rimLitAxis: patch.rimLitAxis ?? base.rimLitAxis,\n sweepBandRadians: patch.sweepBandRadians ?? base.sweepBandRadians,\n glowRadiusCss: patch.glowRadiusCss ?? base.glowRadiusCss,\n glowGain: patch.glowGain ?? base.glowGain,\n sweepGain: patch.sweepGain ?? base.sweepGain,\n };\n}\n\n/**\n * Fold core's resolved material *regime* onto this package's numbers.\n *\n * core decides which regime applies and nothing here re-decides it. One branch\n * per axis of `MaterialPolicyView`, so a new axis in core surfaces as a missing\n * branch here rather than as silence.\n */\nexport function opticsUnderPolicy(\n optics: MaterialOptics,\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): MaterialOptics {\n let next = optics;\n\n if (policy.frost === \"increased\") {\n next = { ...next, blurSigma: next.blurSigma * profile.reducedTransparencyFrost };\n } else if (policy.frost === \"none\") {\n next = { ...next, blurSigma: 0 };\n }\n\n next = {\n ...next,\n tintAlpha: occlusionAlphaUnderPolicy(\n next.tintAlpha,\n policy.occlusion,\n occlusionLiftForPolicy(policy, profile),\n ),\n };\n\n /*\n * The accessibility border SUBSTITUTES the rim; it does not tune it (W23 G1's\n * review fix). A spread of `strongBorderRim`'s two numbers leaves every other\n * constant the rim now reads at the variant's own value, and after W23 the rim\n * reads three more: the band's second anchor and the amplitude law's gain, and\n * they carried the substitution away from what it declares. `rimWidth2x` 1.35\n * narrowed a 2 CSS px border to 1.35 at dpr 2, and `rimLevelGain` −0.628 turned\n * an alpha of 0.95 into 0.64 on a surface of level 0.5 and 0.35 on a bright one\n * — a border that fades exactly where a preference asked for one. So the fold\n * takes BOTH width anchors to the declared width and the gain to 0: under this\n * policy the border is one width and one brightness at every scale and over\n * every backdrop, which is what `border: \"strong\"` means.\n *\n * The specular is left where the variant has it, as it always was: it is gated\n * to nothing at rest (W22) and this fold has no reading on it.\n */\n if (policy.border === \"strong\") {\n next = {\n ...next,\n rimWidth: profile.strongBorderRim.rimWidth,\n rimWidth2x: profile.strongBorderRim.rimWidth,\n rimAlpha: profile.strongBorderRim.rimAlpha,\n rimLevelGain: 0,\n // And the lit edge stands down with it (W24): a border a preference asked\n // for is one brightness the whole way round, and a directional factor\n // would take it to nothing on two of its four corners.\n rimLitExponent: 0,\n // The along-side field stands down for the same reason (W25): a border a\n // preference asked for is one brightness the whole way round, and a\n // position field would grade it corner to corner.\n rimAlongSideSlope: 0,\n };\n }\n\n return next;\n}\n\n/**\n * The rim a COLLAPSED surface keeps, under the accessibility regime (W23 G1's\n * review fix) — `mix(rimCollapsed, rimCollapsedTinted, tintStrength)`, except\n * where a preference has asked for a border.\n *\n * The collapse trades the appearance's own rim for an absolute one, and the\n * absolute one is 0.038 bare and 0.520 painted: what Apple's collapsed capsule\n * keeps. Under `border: \"strong\"` that trade would take a border the user's\n * preference asked for and hand back a mark a twenty-fifth as bright, on the one\n * surface that is already the hardest to see — a material that has taken its\n * backdrop's tone. The substitution therefore reaches the collapsed rim too, and\n * the border is the same on a collapsed surface as on any other.\n *\n * **No cell of any bed exercises this branch**: the two accessibility profiles\n * declare no scene over `dark-solid` or `impulse`, so nothing on the calibration\n * bed both collapses and carries a strong border. It is a correctness statement\n * about the policy rather than a fitted constant, and it is written here rather\n * than left implicit because the alternative is a preference that silently stops\n * being honoured on one class of surface.\n */\nexport function collapsedRimUnderPolicy(\n policy: MaterialPolicyView,\n tintStrength: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n if (policy.border === \"strong\") return profile.strongBorderRim.rimAlpha;\n const strength = Math.min(1, Math.max(0, tintStrength));\n return profile.rimCollapsed + (profile.rimCollapsedTinted - profile.rimCollapsed) * strength;\n}\n\n/** How much of the analysis-driven tint is applied, under the contrast regime. */\nexport function adaptationStrength(\n policy: MaterialPolicyView,\n analysisExact: boolean,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n if (!analysisExact) return 0;\n switch (policy.ambientTint) {\n case \"nominal\":\n return 1;\n case \"reduced\":\n return profile.reducedTintAdaptation;\n case \"none\":\n return 0;\n }\n}\n\n/**\n * How much of the tint's tone excursion survives the contrast regime.\n *\n * The tone map is the tinted material's response to what is behind it, so it\n * rides the axis that already governs exactly that — `ambientTint` — rather\n * than inventing a second one. Under increased contrast the range narrows\n * toward the bare seed, which is the direction W1 measured Apple's own\n * accessibility material moving (its interior \"has all but stopped\n * transmitting the backdrop\"); under forced colours there is no material to\n * tint at all and the caller never reaches here.\n *\n * The author's colour is never changed by a policy. Only how far the material\n * is allowed to move it is.\n */\nexport function tintToneAdaptation(\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n switch (policy.ambientTint) {\n case \"nominal\":\n return 1;\n case \"reduced\":\n return profile.reducedTintAdaptation;\n case \"none\":\n return 0;\n }\n}\n\n/**\n * The shade the seed is shown at over a material of luminance `u` (W10) — the\n * CPU statement of what `WGSL_OPTICS_PASS` evaluates per pixel.\n *\n * `u` is the linear luminance of the UNTINTED material at the pixel — what the\n * surface would show with no author tint, backdrop included. `grip` is how much\n * of the excursion is allowed: the contrast regime's `tintToneAdaptation`, the\n * profile's provenance gate `tintShadeStrength`, and `(1 − collapse)` for W7's\n * axis, multiplied by the caller; at 0 the shade is 1 and the layer is the bare\n * seed. Clamped at 1 because a shade brighter than the seed is not a shade — the\n * fitted light end sits just past 1 (claims §5.36).\n *\n * Exported because two other things have to agree with the shader without being\n * it: the CSS tier folds this layer into its one `rgba()`, and the foreground\n * decision has to be taken against the material the surface actually shows. A\n * second implementation is how those two drift, so there is one, here.\n */\nexport function tintShade(\n materialLuminance: number,\n grip: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n const u = Math.min(1, Math.max(0, materialLuminance));\n const shade = Math.min(1, Math.max(0, profile.tintShadeDark + (profile.tintShadeLight - profile.tintShadeDark) * u));\n const k = Math.min(1, Math.max(0, grip));\n return 1 + (shade - 1) * k;\n}\n\n/** The opaque layer an author tint paints: the seed at its shade, linear light. */\nexport function tintShadeLayer(\n seed: Rgb,\n materialLuminance: number,\n grip: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): Rgb {\n const shade = tintShade(materialLuminance, grip, profile);\n const chroma = Math.min(1, Math.max(0, profile.tintChromaScale ?? 1));\n if (chroma === 1) return [seed[0] * shade, seed[1] * shade, seed[2] * shade];\n const neutral = Math.max(...seed);\n return [\n (neutral + (seed[0] - neutral) * chroma) * shade,\n (neutral + (seed[1] - neutral) * chroma) * shade,\n (neutral + (seed[2] - neutral) * chroma) * shade,\n ];\n}\n\n/**\n * The tinted material's colour once the author's layer composites over it.\n *\n * The layer is opaque and lands at the AUTHOR's opacity (`strength`), in the\n * encoded space — a `CALayer` with `opacity` over the material, which is how the\n * reference's half-strength cell measures (claims §5.36 finding 3). `material`\n * is the untinted composite at this pixel, linear; the result is linear too.\n * At strength 0 the material is returned untouched, so an untinted surface is\n * byte-identical to before this axis existed.\n */\nexport function tintedMaterialColour(\n material: Rgb,\n tint: { readonly color: Rgb; readonly strength: number } | undefined,\n grip: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): Rgb {\n if (tint === undefined || tint.strength <= 0) return material;\n const s = Math.min(1, Math.max(0, tint.strength));\n const layer = tintShadeLayer(tint.color, relativeLuminance(material), grip, profile);\n const clamp01 = (value: number): number => Math.min(1, Math.max(0, value));\n const channel = (index: 0 | 1 | 2): number => {\n const from = linearToSrgbChannel(clamp01(material[index]));\n const to = linearToSrgbChannel(clamp01(layer[index]));\n return srgbToLinearChannel(from + (to - from) * s);\n };\n return [channel(0), channel(1), channel(2)];\n}\n\n/**\n * **Backdrop tone adaptation, the curve** — how far this surface's tint is pulled\n * onto the backdrop it is looking at, 0…1, before any accessibility fold.\n *\n * `thickness` is the size law's own factor (`sizeThickness`), and it enters the\n * curve's argument rather than scaling its result: a thicker surface reads its\n * backdrop as brighter than it is, so it holds its own appearance longer. See\n * `MaterialProfile.backdropToneSizeBias` for the measurement that shape came from.\n *\n * Exported for the same reason `tintTone` is: the CSS tier evaluates it at one\n * backdrop level, the foreground decision has to be taken against the material the\n * surface actually shows, and `WGSL_OPTICS_PASS` mirrors it per pixel. One curve,\n * three consumers, no second implementation.\n */\nexport function backdropToneAdaptation(\n backdropLuminance: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n const x = backdropLuminance + profile.backdropToneSizeBias * Math.min(1, Math.max(0, thickness));\n const span = Math.max(profile.backdropToneHigh - profile.backdropToneLow, 1e-6);\n const t = Math.min(1, Math.max(0, (x - profile.backdropToneLow) / span));\n return Math.min(1, Math.max(0, profile.backdropToneMax)) * (1 - t * t * (3 - 2 * t));\n}\n\n/**\n * How much of the backdrop adaptation survives an accessibility regime.\n *\n * Two folds, each with its own reason, and the product is what the material gets.\n *\n * `ambientTint` is the axis the wave's composition contract names for \"how far\n * the material may move its colour\", and it is what carries increased contrast\n * (narrowed toward the scheme's own neutral) and forced colours (no material to\n * adapt — the optics pass stands down before it reaches here).\n *\n * The refraction ladder read at the **accessibility cap** carries reduced\n * transparency, which touches no tint axis at all and would otherwise get the\n * adaptation at full strength — and adaptation at full strength dissolves the\n * surface into its backdrop, which is precisely the occlusion that preference\n * asked to be *raised*. A policy has to win against a material law, so it does.\n * The same cap, for the same reason, that `sizeThicknessUnderPolicy` reads.\n *\n * Deliberately unmeasured rather than fitted: neither accessibility profile's\n * scene set contains a backdrop dark enough for this axis to act on, so the fold\n * is a statement about which way to be wrong, not a number the bed chose. It is\n * named in the claims doc with the capture that would close it.\n */\nexport function backdropToneUnderPolicy(\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return tintToneAdaptation(policy, profile) * profile.refractionScale[accessibilityRefractionCap(policy)];\n}\n\n/**\n * The size bias to hand a consumer that will multiply it by a **policy-folded**\n * thickness (`sizeThicknessUnderPolicy`) — the shader and the CSS tier both do.\n *\n * The gate is geometric: it says how much material stands between the viewer and\n * the backdrop, which no preference changes. But there is one thickness in the\n * pipeline and it is the folded one (it rides `aux.z` through the field pass's\n * union, and widening `aux` for a second copy of the same quantity would be a\n * per-pixel channel spent on arithmetic). Dividing the bias by the same cap\n * restores the geometric product exactly: `bias' * thickness_folded ===\n * bias * thickness_raw`, pinned as a test rather than promised here.\n *\n * At `cap = none` the fold above is already 0, so the adaptation is off and the\n * bias is not read; 0 is returned rather than an infinity.\n */\nexport function backdropToneSizeBiasUnderPolicy(\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n const cap = profile.refractionScale[accessibilityRefractionCap(policy)];\n return cap <= 0 ? 0 : profile.backdropToneSizeBias / cap;\n}\n\n/**\n * The neutral tint after the backdrop has had its say — step two of the wave's\n * composition contract (colour scheme → **backdrop adaptation** → author tint).\n *\n * `backdrop` is the **averaged** light the surface's body transmits, not one\n * pixel's lens-displaced sample: a fully adapted material shows its backdrop's\n * tone, and a tone is a mean. Over a flat backdrop the two are the same value and\n * the surface disappears into it exactly, which is what the reference's capsule\n * over `dark-solid` does — byte-identical to its own background.\n */\nexport function adaptedTintColour(\n neutral: Rgb,\n backdrop: Rgb,\n adaptation: number,\n tintAlpha: number,\n): Rgb {\n const k = Math.min(1, Math.max(0, adaptation));\n if (k === 0) return neutral;\n // The pair (colour, alpha) that makes the interior composite CONVERGE on the\n // backdrop's tone: mix(mix(b, T, α), M, k) === mix(b, T', α') exactly, with α'\n // from `adaptedTintAlpha`. Solving it here rather than lerping the two\n // parameters separately is the difference between an adaptation and a\n // brightening — a lerped alpha over a still-mostly-neutral tint makes a\n // partially adapted surface *lighter* than the one it started from, which the\n // 96 px cells caught immediately (interior 0.4545 → 0.5179 against a reference\n // of 0.4542).\n const alpha = adaptedTintAlpha(tintAlpha, k);\n if (alpha <= 0) return neutral;\n const wNeutral = (1 - k) * tintAlpha;\n return [\n (neutral[0] * wNeutral + backdrop[0] * k) / alpha,\n (neutral[1] * wNeutral + backdrop[1] * k) / alpha,\n (neutral[2] * wNeutral + backdrop[2] * k) / alpha,\n ];\n}\n\n/**\n * The material's occlusion once the backdrop has had its say — the second half of\n * the adaptation, and the half a cross-tier measurement forced.\n *\n * An adapting material does not merely take its backdrop's colour, it stops\n * transmitting: the settled reference's capsule over the `impulse` backdrop is a\n * flat body at its backdrop's own mean, with the impulse grid *hidden* behind it\n * (interior standard deviation 0.0008 against the backdrop's 0.056), not a\n * transparent pane showing it through.\n *\n * Adapting the colour alone made the material fully transparent at full strength,\n * and that is where the two tiers part company: this one blurs its backdrop in\n * linear light and the CSS tier's `backdrop-filter` blurs in the encoded space, so\n * over a high-dynamic-range backdrop a transparent material renders *different\n * pixels* on the two tiers by construction. Measured on that cell, GPU over CSS\n * interior ratio 23.5 against a gated band of 0.80…1.25 — a hard failure of the\n * cross-tier bound, and the reason this exists. A material that shows its\n * backdrop's mean is a colour, and a colour is tier-independent.\n *\n * The same \"fraction of what is left\" shape as `increasedOcclusionLift`, and for\n * the same reason: it lifts strictly for every nominal below 1, whatever a later\n * tuning pass moves nominal to.\n *\n * This is the one place a colour axis reaches the alpha, and it is not an\n * exception to the composition contract's rule that an author's tint may not:\n * that rule is about an *author's* choice not moving the material's occlusion.\n * This is the material's own response to its surroundings, which is what the\n * occlusion axis is for.\n */\nexport function adaptedTintAlpha(tintAlpha: number, adaptation: number): number {\n const k = Math.min(1, Math.max(0, adaptation));\n return tintAlpha + k * (1 - tintAlpha);\n}\n\nconst smoothstep = (edge0: number, edge1: number, x: number): number => {\n if (edge1 <= edge0) return x < edge0 ? 0 : 1;\n const t = Math.min(1, Math.max(0, (x - edge0) / (edge1 - edge0)));\n return t * t * (3 - 2 * t);\n};\n\n/**\n * **The size law's one input**: how thick a surface of this span reads, 0…1.\n *\n * Every thickness-derived facet is a gain on this number and on nothing else —\n * see `MaterialProfile.sizeSpanMin`. Exactly 0 at or below `sizeSpanMin`, so the\n * whole law is inert on a small control, and exactly 1 at or above `sizeSpanMax`,\n * so nothing keeps growing off the end of the canonical range.\n *\n * Mirrored by `@vitreajs/vitrea-web`'s `sizeThickness`, pinned in both directions\n * by `packages/calibration/test/tier-coherence.test.ts`.\n */\nexport function sizeThickness(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return smoothstep(profile.sizeSpanMin, profile.sizeSpanMax, spanPx);\n}\n\n/**\n * The backdrop tone response `R(encodedInput, thickness)` (W9) — the settled\n * interior level the reference shows over a backdrop whose ENCODED-space mean\n * is `encodedInput`, for a surface of the given (unfolded) thickness. See\n * `MaterialProfile.backdropToneAnchorX` for what the anchors are and where the\n * law's authority ends.\n *\n * Monotone (Fritsch–Carlson) interpolation through the three anchors, clamped\n * to their span; smoothstep between the thin and thick rows. Mirrored by\n * `@vitreajs/vitrea-web` and by the optics shader, pinned by\n * `tier-coherence.test.ts`.\n */\nexport function backdropToneResponse(\n encodedInput: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n levelFar = 0,\n): number {\n const xs = profile.backdropToneAnchorX;\n const f = smoothstep(0, 1, thickness);\n const ys = [0, 1, 2].map(\n (i) =>\n (profile.backdropToneResponseThin[i] ?? 0) +\n ((profile.backdropToneResponseThick[i] ?? 0) - (profile.backdropToneResponseThin[i] ?? 0)) *\n f,\n ) as [number, number, number];\n\n let x: number, h: number, t: number, y0: number, y1: number, s0: number, s1: number;\n if (xs.length === 3) {\n // Kept as the original arithmetic, not routed through the four-knot branch:\n // every existing three-knot document must resolve and render bit-identically.\n x = Math.min(xs[2], Math.max(xs[0], encodedInput));\n const h0 = xs[1] - xs[0];\n const h1 = xs[2] - xs[1];\n const d0 = (ys[1] - ys[0]) / h0;\n const d1 = (ys[2] - ys[1]) / h1;\n const m1 = d0 * d1 <= 0 ? 0 : (2 * d0 * d1) / (d0 + d1);\n const seg = x <= xs[1] ? 0 : 1;\n h = seg === 0 ? h0 : h1;\n t = (x - (seg === 0 ? xs[0] : xs[1])) / h;\n y0 = seg === 0 ? ys[0] : ys[1];\n y1 = seg === 0 ? ys[1] : ys[2];\n s0 = seg === 0 ? d0 : m1;\n s1 = seg === 0 ? m1 : d1;\n } else {\n const ys4 = [ys[0], ys[1], ys[2],\n profile.backdropToneResponseThin[3]!\n + (profile.backdropToneResponseThick[3]! - profile.backdropToneResponseThin[3]!) * f,\n ] as const;\n x = Math.min(xs[3], Math.max(xs[0], encodedInput));\n const h0 = xs[1] - xs[0], h1 = xs[2] - xs[1], h2 = xs[3] - xs[2];\n const d0 = (ys4[1] - ys4[0]) / h0;\n const d1 = (ys4[2] - ys4[1]) / h1;\n const d2 = (ys4[3] - ys4[2]) / h2;\n const m1 = d0 * d1 <= 0 ? 0 : (2 * d0 * d1) / (d0 + d1);\n const m2 = d1 * d2 <= 0 ? 0 : (2 * d1 * d2) / (d1 + d2);\n const seg = x <= xs[1] ? 0 : x <= xs[2] ? 1 : 2;\n const hs = [h0, h1, h2] as const;\n const slopes = [d0, m1, m2, d2] as const;\n h = hs[seg]!;\n t = (x - xs[seg]!) / h;\n y0 = ys4[seg]!;\n y1 = ys4[seg + 1]!;\n s0 = slopes[seg]!;\n s1 = slopes[seg + 1]!;\n }\n // `levelFar` is W25's level term above the thickness knee (claims §5.113; W25\n // Decision Log 3 (b)) — an OFFSET on the settled level this curve returns, in\n // the curve's own encoded units, and not a continuation of its thin-to-thick\n // blend. The rows chose the shape: see `MaterialProfile.sizeToneLevelFar`.\n // It is 0 at and below span 96 by the shape of its span curve, and 0 at every\n // span on the landed material.\n return (\n y0 * (1 + 2 * t) * (1 - t) * (1 - t) +\n s0 * h * t * (1 - t) * (1 - t) +\n y1 * t * t * (3 - 2 * t) +\n s1 * h * t * t * (t - 1)\n + levelFar\n );\n}\n\n/**\n * How much authority the response law has at this input, 0…1 (W9).\n *\n * Full on its measured domain (the dark anchor upward), fading to zero over\n * the dark anchor's own lower half — below it the only evidence is\n * `impulse__rrect-md`, which the collapse constants were fitted on and the\n * response surface would contradict. Derived from the anchor, not a constant.\n */\nexport function backdropToneSolveWeight(\n encodedInput: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n const anchor = profile.backdropToneAnchorX[0];\n return smoothstep(anchor * 0.5, anchor, encodedInput);\n}\n\n/**\n * The size law under an accessibility regime — the fold every other optic gets,\n * and the law does not get to skip it.\n *\n * **MEASURED (W2), and it was measured the hard way.** The law was first landed\n * unfolded, and the regeneration caught it: under both accessibility profiles the\n * large-span cells' ΔE p95 rose past their adopted bounds while every\n * light-standard cell improved. The reason is legible in the reference. Under\n * reduce-transparency Apple's material is nearly opaque and its interior level is\n * *flat* in span (0.9465 at a 44 px span, 0.9526 at 96), where in the standard\n * profile it is not — so a size term that deepens the material's own shadow is\n * modelling something the accessibility reference does not do, and vitrea's\n * accessibility fold already under-occludes against it (W1's Surprise), so the\n * extra depth compounds an error instead of closing one.\n *\n * The scale is the profile's own refraction ladder rather than a new constant,\n * read at the **accessibility** cap alone: 1 nominal, 0.45 reduced, 0 none. That\n * is the number that already means \"how much depth this preference allows\", and\n * the law is nothing but a depth simulation. Deliberately not the *resolved* cap,\n * which also carries the group's sampling capability — a group demoted to a CSS\n * proxy should still look as thick as it is, because being demoted is not a\n * statement about the material.\n *\n * One consequence, stated rather than hidden: the lens displacement is scaled by\n * `refractionScale` again in the shader, so under a reduced regime the size\n * gain's contribution to it is scaled twice. That is the safe direction — a\n * preference asking for less refraction gets less — and the base thickness, which\n * is most of the depth, is scaled exactly once.\n */\nexport function sizeThicknessUnderPolicy(\n spanPx: number,\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return (\n sizeThickness(spanPx, profile) * profile.refractionScale[accessibilityRefractionCap(policy)]\n );\n}\n\n/**\n * The inner shadow's size gain — see `MaterialProfile.lensSizeGainMax`. The\n * name is the constant's; the lens has read its own law since W12 G2.\n */\nexport function lensSizeGain(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return 1 + (profile.lensSizeGainMax - 1) * sizeThickness(spanPx, profile);\n}\n\n/** `lensSizeGain` for a surface whose thickness factor the policy has already folded. */\nexport function lensSizeGainFromThickness(\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return 1 + (profile.lensSizeGainMax - 1) * thickness;\n}\n\n/**\n * The inner shadow's depth in CSS px — the law the lens ran on until W12 G2,\n * kept for the occlusion exactly as it was: the thickness times the size gain,\n * clamped to the shorter half extent. `thickness` here is the policy-folded\n * factor (`sizeThicknessUnderPolicy`), as the shader's `sizeK` is.\n */\nexport function shadowDepthPx(\n thicknessPx: number,\n spanPx: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.min(\n Math.max(thicknessPx, 0) * lensSizeGainFromThickness(thickness, profile),\n spanPx * 0.5,\n );\n}\n\n/** The reference's inner refraction height for a span: `min(lensHeightPerSpan · span, lensHeightMax)`. */\nexport function lensHeightBasePx(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.min(profile.lensHeightPerSpan * Math.max(spanPx, 0), profile.lensHeightMax);\n}\n\n/** The reference's inner refraction amount for a span: `min(lensAmountPerSpan · span, lensAmountMax)`. */\nexport function lensAmountBasePx(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.min(profile.lensAmountPerSpan * Math.max(spanPx, 0), profile.lensAmountMax);\n}\n\n/**\n * The lens's ovalization for a span (W12 G2): `lensOvalization` on a thick\n * surface, 0 on a thin one, a smoothstep over the reference's knee between.\n */\nexport function lensOvalizationAt(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return profile.lensOvalization * smoothstep(profile.lensOvalizationSpanMin, profile.lensOvalizationSpanMax, spanPx);\n}\n\n/**\n * The lens's magnitude at the contour, in CSS px (W12 G2): the reference's\n * amount law scaled by the author's thickness and by `lensRefractionGain`,\n * under the same accessibility fold and half-extent clamp the depth takes —\n * see `lensDepthPx`. 44.7 at saturation on the default thickness.\n */\nexport function lensMagnitudePx(\n thicknessPx: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n fold = 1,\n): number {\n const thick = Math.max(thicknessPx, 0);\n if (thick <= 0) return 0;\n const scale = thick / profile.lensThicknessReference;\n // The height and the amount are scaled together; a clamped depth scales the\n // amount by the same ratio so the profile's shape survives the clamp.\n const unclamped = thick + (lensHeightBasePx(spanPx, profile) * scale - thick) * fold;\n const depth = lensDepthPx(thicknessPx, spanPx, profile, fold);\n const amount = thick + (lensAmountBasePx(spanPx, profile) * scale - thick) * fold;\n return profile.lensRefractionGain * amount * (unclamped > 0 ? depth / unclamped : 0);\n}\n\n/** The lens profile's extent: D reaches zero `lensExtentGain` lens depths in. */\nexport function lensExtentPx(\n thicknessPx: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n fold = 1,\n): number {\n return profile.lensExtentGain * lensDepthPx(thicknessPx, spanPx, profile, fold);\n}\n\n/**\n * The direction the lens displaces along at a pixel (W12 G2): the gradient of\n * the blended field `(1 − ω)·d_rrect + ω·d_oval`, where `d_oval` is the signed\n * distance of the ellipse inscribed in the surface's box —\n * `min(a, b)·(√((x/a)² + (y/b)²) − 1)` — and the rounded rectangle's gradient is\n * the field pass's unit normal. `offset` is the pixel relative to the surface's\n * centre and `half` the half-extents, both in CSS px. Returns a unit vector;\n * the shader's arithmetic, on the CPU for the tests.\n */\nexport function lensDirection(\n normal: readonly [number, number],\n offset: readonly [number, number],\n half: readonly [number, number],\n ovalization: number,\n): [number, number] {\n const a = Math.max(half[0], 1e-6);\n const b = Math.max(half[1], 1e-6);\n const ex = offset[0] / (a * a);\n const ey = offset[1] / (b * b);\n const r = Math.max(Math.hypot(offset[0] / a, offset[1] / b), 1e-6);\n const scale = Math.min(a, b) / r;\n const gx = (1 - ovalization) * normal[0] + ovalization * ex * scale;\n const gy = (1 - ovalization) * normal[1] + ovalization * ey * scale;\n const len = Math.hypot(gx, gy);\n return len > 1e-9 ? [gx / len, gy / len] : [normal[0], normal[1]];\n}\n\n/**\n * The body blur σ a surface of this span actually runs at — the scattering facet.\n *\n * One function for both tiers, which is what stops them scattering differently:\n * `platform-web` calls its mirror of this to write `blur()`, and this package\n * calls it to derive the chain level the optics pass lerps its body sample\n * toward. It is also what a group's `samplingPadding` floor must be taken over —\n * a wider blur needs a wider proxy, and the group's floor is set by its *largest*\n * member (S1's 3σ rule, applied to the σ the material will really use).\n *\n * `devicePixelRatio` reaches the ramp's projection — the ramp's start and reach\n * and, since W15 G1, the deep value's floor and span top are per-scale\n * constants — and the heavy width's gain, but never the width itself, which is\n * CSS px at every scale in this shared projection (see `sizeScatterSigmaAt`).\n * It defaults to 1, where the whole expression is the 1x law.\n *\n * The span reaches the gain as well as the mix since W15 G1's re-form (claims\n * §5.70 §4 and §7): the reference's heavy kernel grows with the span, so this\n * hands `spanPx` on to `sizeScatterSigmaAt`. At dpr ≤ 1 that grading is flat and\n * the σ is what it always was.\n */\nexport function sizeScatterSigma(\n sigmaPx: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n extentsCssPx?: readonly [number, number],\n): number {\n return sizeScatterSigmaAt(\n sigmaPx,\n scatterThickness(spanPx, 1, profile, devicePixelRatio, extentsCssPx),\n profile,\n devicePixelRatio,\n spanPx,\n );\n}\n\n/**\n * **The depth ramp's start at a device scale and a span** — s₀(span, dpr), the\n * sharp component's share at the contour (W13 G1, claims §5.61 §2, §5.64 §5).\n *\n * ```\n * s₀(span, dpr) = startThin(dpr) + (startThick(dpr) − startThin(dpr)) · sizeThickness(span)\n * ```\n *\n * Two gradings, and they are different quantities. **In dpr**: the reference\n * was read at dpr 1 and dpr 2 and nowhere between, so each anchor is\n * interpolated linearly between its two readings and held outside [1, 2],\n * because an extrapolation of a two-point fit past its own anchors would be an\n * invention rather than a measurement. **In span**: G0 read the start much\n * higher on the thin surfaces than on the thick ones, and the curve it grades\n * along is `sizeThickness` — the material's existing knee at 64, not a new\n * statistic. A single start per scale was the second form and its sweep refuted\n * it (claims §5.64 §2). And past that knee the start keeps FALLING, along the\n * scatter facet's own curve to `far` at `sizeScatterSpanMax` — the fourth form,\n * from the third's one holdout failure (claims §5.67 §4).\n *\n * `scatterRampReachDevicePx` carries the dpr rule on the reach; the two are\n * separate functions so a sweep can move one without the other, and the reach\n * has no span grading because it measured as one length (§5.61 §2).\n */\nexport function scatterRampStart(\n devicePixelRatio: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n spanPx = 0,\n): number {\n const thin = rampAtScale(\n profile.sizeScatterRampStartThin1x,\n profile.sizeScatterRampStartThin2x,\n devicePixelRatio,\n );\n const thick = rampAtScale(\n profile.sizeScatterRampStartThick1x,\n profile.sizeScatterRampStartThick2x,\n devicePixelRatio,\n );\n const far = rampAtScale(\n profile.sizeScatterRampStartFar1x,\n profile.sizeScatterRampStartFar2x,\n devicePixelRatio,\n );\n // The fourth form (W13 Decision Log 6): past the thickness knee the start keeps\n // falling along the scatter facet's own curve, from the thick anchor at\n // `sizeSpanMax` to `far` at `sizeScatterSpanMax`. Same curve the deep value\n // rises along, so the two are one span statistic read twice.\n const decline = smoothstep(\n profile.sizeSpanMax,\n scatterSpanMaxAtScale(profile, devicePixelRatio),\n spanPx,\n );\n return thin + (thick - thin) * sizeThickness(spanPx, profile) + (far - thick) * decline;\n}\n\n/**\n * **The depth ramp's reach at a device scale**, in DEVICE px — U(dpr), the depth\n * at which the sharp share would reach zero if it started at 1 (W13 G1).\n *\n * In device pixels because that is how it measured: the per-span reaches in\n * absolute depth spread by 1.3× where the reaches as a fraction of the half-span\n * spread by 2.2×, and between the two scales the length roughly halves in CSS px\n * — one length in device pixels fits both beds where one in CSS px does not\n * (claims §5.61 §2). Callers working in CSS px divide by the same dpr.\n */\nexport function scatterRampReachDevicePx(\n devicePixelRatio: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return rampAtScale(\n profile.sizeScatterRampReach1xPx,\n profile.sizeScatterRampReach2xPx,\n devicePixelRatio,\n );\n}\n\n/**\n * Linear in dpr between the 1x and 2x anchors, held outside [1, 2]. The two\n * anchors are returned exactly rather than through the interpolation, because\n * they are the values the reference was measured at and a profile that names\n * one should render it, not a float one ulp away from it.\n */\nfunction rampAtScale(at1x: number, at2x: number, devicePixelRatio: number): number {\n const t = devicePixelRatio - 1;\n if (t <= 0) return at1x;\n if (t >= 1) return at2x;\n return at1x + (at2x - at1x) * t;\n}\n\n/**\n * **The rim band's half-width at a device scale** (W23 G1, claims §5.100 §5;\n * W23 Decision Log 2 (d)).\n *\n * The rim's amplitude is one law for both scales and its band is not: read at\n * the contour, vitrea's per-CSS-px band integral rises 19 % between 1x and 2x\n * while the reference's falls 10 %, and no amplitude constant can absorb a\n * mismatch that is across the scale axis. So the band takes a second anchor at\n * dpr 2 through the same `rampAtScale` the body's second-scale constants use,\n * and at dpr ≤ 1 it returns `rimWidth` exactly — a variant whose two anchors\n * are equal renders identically at every ratio, which is what the `clear`\n * variant and the strong-border rim both do.\n */\nexport function rimWidthAtScale(optics: MaterialOptics, devicePixelRatio = 1): number {\n return rampAtScale(optics.rimWidth, optics.rimWidth2x, devicePixelRatio);\n}\n\n/**\n * **The heavy width's gain at a device scale** (W15 G1, claims §5.69 §1).\n *\n * The gain multiplies the sharp width to give the heavy component's σ, and the\n * reference's heavy component is a different width at 2x than the 1x gain of 8\n * makes it once the sharp width is read in device pixels. Interpolated by\n * `rampAtScale`, so a profile that names only the 1x gain returns it at every\n * ratio and this function is the identity on the landed material.\n */\n/**\n * **The collapse's transmission at a device scale** (W24 G1).\n *\n * Interpolated by `rampAtScale`, so a profile that names only the 1x constant\n * returns it at every ratio and this function is the identity on the landed\n * material — where both anchors are 0 and the collapse is W7's to the bit.\n */\nexport function collapseTransmissionAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(\n profile.collapseTransmission,\n profile.collapseTransmission2x,\n devicePixelRatio,\n );\n}\n\nexport function scatterGainAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(profile.sizeScatterGainMax, profile.sizeScatterGainMax2x, devicePixelRatio);\n}\n\n/**\n * **The heavy width's gain at the top of the scatter span curve, at a device\n * scale** (W15 G1's re-form, claims §5.70 §4 and §7).\n *\n * The far end of `scatterGainAt`'s span grading. Interpolated from\n * `sizeScatterGainMax` — the 1x gain — rather than from the 2x one, which is\n * what makes the whole grading inert at dpr 1: there the far gain and the base\n * gain are the same number, so the curve between them is flat whatever\n * `sizeScatterGainFar2x` says.\n */\nexport function scatterGainFarAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(profile.sizeScatterGainMax, profile.sizeScatterGainFar2x, devicePixelRatio);\n}\n\n/**\n * **The heavy width's gain at a span and a device scale** (W15 G1's re-form,\n * claims §5.70 §4 and §7) — the width law the body's heavy component actually\n * runs at.\n *\n * ```\n * gain(span, dpr) = gainAtScale(dpr)\n * + (gainFar(dpr) − gainAtScale(dpr))\n * · smoothstep(sizeSpanMax, sizeScatterSpanMax(dpr), span)\n * ```\n *\n * The reference's heavy kernel GROWS with the span — 8.0 / 7.5 / 8.0 / 9.0 /\n * 11.0 device px across the bed (claims §5.69 §1) — and W15 G1's first landing\n * carried one number for it, which left the largest span's deep interior 40%\n * too structured (§5.70 §4). The curve the gain grades along is the one the\n * fourth form's far anchor already declines along, from `sizeSpanMax` to\n * `sizeScatterSpanMax` at scale, so the width and the ramp's start are one span\n * statistic read twice and no new knee enters the material.\n *\n * At dpr ≤ 1 both ends are `sizeScatterGainMax` and this is that constant at\n * every span, which is the binding rule of the wave expressed as arithmetic.\n */\nexport function scatterGainAt(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n const near = scatterGainAtScale(profile, devicePixelRatio);\n const far = scatterGainFarAtScale(profile, devicePixelRatio);\n if (far === near) return near;\n return (\n near\n + (far - near)\n * smoothstep(\n profile.sizeSpanMax,\n scatterSpanMaxAtScale(profile, devicePixelRatio),\n spanPx,\n )\n );\n}\n\n/**\n * **The scatter facet's frost at a device scale** (W15 G1, claims §5.69 §2) —\n * the deep value's floor, and the value the whole facet folds to.\n *\n * One function rather than two reads of the profile, because the floor is read\n * in three places that must agree: the deep curve below, the fold in\n * `scatterThickness`, and the uniform the shader takes for both.\n */\nexport function scatterFloorAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return clampUnit(\n rampAtScale(profile.sizeScatterFloor, profile.sizeScatterFloor2x, devicePixelRatio),\n );\n}\n\n/**\n * **The deep value's span top at a device scale** (W15 G1, claims §5.69 §2) —\n * the span at which the deep value reaches 1, fully heavy.\n *\n * It is one span statistic read twice, here as at 1x: the deep curve rises to\n * it and the ramp's start declines to `far` along the same smoothstep, so a\n * sweep that moves the top at 2x moves both together, which is the relation the\n * fourth form was built on (`scatterRampStart`).\n */\nexport function scatterSpanMaxAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(profile.sizeScatterSpanMax, profile.sizeScatterSpanMax2x, devicePixelRatio);\n}\n\n/**\n * **The span law that supplies the ramp's deep value** — kDeep(span), the heavy\n * share the body mixes by everywhere deeper than the ramp's reach (W11c G1,\n * claims §5.41; kept underneath the ramp by W13 G1).\n *\n * `sizeScatterFloor` + (1 − floor) · smoothstep(`sizeSpanMin`,\n * `sizeScatterSpanMax`, span), unfolded — exactly the curve W11c fitted and W12\n * landed. The accessibility fold is applied once, by `scatterThickness` and by\n * the shader, on the whole mix rather than on this term alone.\n *\n * `devicePixelRatio` reaches the floor and the span top, which are per-scale\n * constants since W15 G1 (claims §5.69 §2: the reference's 2x deep interior is\n * fully heavy on the two largest spans where this curve leaves a sharp share of\n * 0.24–0.36). It defaults to 1, where the whole expression is the 1x law, and\n * the two anchors are equal on the landed material, so every ratio returns that\n * law until the sweep fits the second scale.\n */\nexport function scatterDeepThickness(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n const floor = scatterFloorAtScale(profile, devicePixelRatio);\n // W25's share law (claims §5.113; W25 Decision Log 3 (a)): the thick end's lift\n // on the material's OWN thin/thick curve, added to the W11c span curve rather\n // than replacing it. `sizeThickness` is exactly 0 at and below `sizeSpanMin`,\n // so the thin controls are bit-identical whatever the lift says, and at 0 the\n // whole term is one multiplication by zero — see\n // `MaterialProfile.sizeScatterHeavyShareThick1x` for why the thin end stays.\n const lift =\n scatterHeavyShareThickAtScale(profile, devicePixelRatio) * sizeThickness(spanPx, profile);\n return clampUnit(\n floor\n + (1 - floor)\n * smoothstep(profile.sizeSpanMin, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx)\n + lift,\n );\n}\n\n/**\n * **The heavy share's thick-end lift at a device scale** (W25; claims §5.113).\n *\n * Interpolated by `rampAtScale`, so a profile that names only the 1x lift\n * returns it at every ratio, and on the landed material both anchors are 0 and\n * this is the constant zero — which is what makes the whole mechanism inert\n * before G3 declares the fit.\n */\nexport function scatterHeavyShareThickAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(\n profile.sizeScatterHeavyShareThick1x,\n profile.sizeScatterHeavyShareThick2x,\n devicePixelRatio,\n );\n}\n\n/**\n * **The heavy blur's Gaussian σ at a device scale, in device px** (W26) — the\n * one constant of `MaterialProfile.sizeHeavyTapSigma`, resolved per scale.\n *\n * Per scale because the reference's heavy component is a device-px quantity whose\n * two readings do not halve into each other (19.52 at 1x, 11.29 at 2x; claims\n * §5.113 §2), so one number cannot serve both. Interpolated by `rampAtScale` on\n * the pattern `sizeScatterGainMax2x` established, which means a profile naming\n * only the 1x σ drags the 2x end toward the 2x constant's own default — so a\n * document that means both names both.\n *\n * **On the landed material both anchors are 9** (W26; claims §5.122 §4), so this\n * is the constant 9 device px at every ratio and the ramp between the anchors is\n * flat. That the two scales agree is a reading and not a simplification: the\n * family reader asks 9.48 / 8.63 / 9.19 at dpr 1 and 8.13 / 9.79 / 8.37 at dpr 2,\n * and one number is within 11 % of every one of the six. It stays a per-scale pair\n * because the two scales are separately measured and separately movable — the two\n * off-diagonal rungs of W26 G1c's ladder read each scale's anchor and nothing of\n * the other's — not because they happen to be equal today.\n */\nexport function heavyTapSigmaAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n return rampAtScale(profile.sizeHeavyTapSigma, profile.sizeHeavyTapSigma2x, devicePixelRatio);\n}\n\n/**\n * **The SECOND heavy blur's Gaussian σ at a device scale, in CSS px** (W30 G2) —\n * the width of `MaterialProfile.sizeHeavySecondSigma`, resolved per scale by\n * `heavyTapSigmaAtScale`'s own `rampAtScale`, and **zero wherever the share that\n * gates it is zero**.\n *\n * The gate is in here rather than at every caller so that the mechanism has\n * exactly one off condition: the pyramid asks this function for a width, gets 0\n * where the material declines the operator, and allocates nothing. A profile\n * that names a width and leaves `sizeHeavySecondShare` at 0 therefore gets\n * nothing, which is deliberate — a width is not a switch, and W26 Decision Log\n * 6 (c) records what happens when a near-zero width is read as one.\n *\n * In CSS px rather than device px because the second tap is a difference from the\n * first at a scale the fit chooses, and nothing yet says its two readings fail to\n * halve into each other the way `sizeHeavyTapSigma`'s do; §5.159 records what the\n * ladder says when it is fitted. The pyramid converts to source texels with the\n * placed density, exactly as it does for the body and the first heavy tap.\n */\nexport function heavySecondTapSigmaAtScale(\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n): number {\n if (profile.sizeHeavySecondShare === 0) return 0;\n return rampAtScale(\n profile.sizeHeavySecondSigma,\n profile.sizeHeavySecondSigma2x,\n devicePixelRatio,\n );\n}\n\n/**\n * **The level term above the thickness knee** (W25; claims §5.113, W25 Decision\n * Log 3 (b)) — the offset on the settled interior level a surface of this span\n * takes, in the tone response's own encoded units, resolved at a device scale.\n *\n * `sizeToneLevelFar · smoothstep(sizeSpanMax, sizeScatterSpanMax(dpr), span)`,\n * which is **exactly 0 at and below `sizeSpanMax`** at every value of the\n * constant — a smoothstep is zero at and below its own low edge — so nothing at\n * or under span 96 can move on this term. The curve is the one the ramp's far\n * anchor declines along and the 2x heavy gain rises along, so the wave adds no\n * new span statistic. `fold` is the accessibility fold the response it offsets\n * already takes.\n */\nexport function sizeToneLevelFar(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n fold = 1,\n): number {\n return (\n profile.sizeToneLevelFar\n * smoothstep(profile.sizeSpanMax, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx)\n * fold\n );\n}\n\n/**\n * **The along-side position field** (W25; claims §5.113, W25 Decision Log 3 (c))\n * — the surface's own normalised diagonal coordinate at a pixel, +1 at the\n * top-left and bottom-right corners and −1 at the other two, 0 on both axes\n * through the centre.\n *\n * `offset` is the pixel relative to the surface's centre and `half` its\n * half-extents, both in CSS px, viewport coordinates with y down — the shader's\n * `aux2`. The product of the two normalised coordinates rather than a projection\n * onto a metric diagonal, because the reference's four sides read equal and\n * OPPOSITE slopes and a field linear in position gives the top and the bottom\n * side the same one; see `MaterialOptics.rimAlongSideSlope`.\n *\n * Its mean over any straight side is exactly zero, which is what leaves W23's and\n * W24's straight-span amplitudes and the CSS tier's single inset alone.\n */\nexport function rimAlongSideField(\n offset: readonly [number, number],\n half: readonly [number, number],\n): number {\n const x = offset[0] / Math.max(Math.abs(half[0]), 1e-6);\n const y = offset[1] / Math.max(Math.abs(half[1]), 1e-6);\n return Math.max(-1, Math.min(1, x * y));\n}\n\n/**\n * **The rim amplitude's along-side factor** (W25; claims §5.113) —\n * `1 + rimAlongSideSlope · sizeThickness(span) · field`, the position half of the\n * light whose direction half W24 landed.\n *\n * At slope 0 this is exactly 1 at every position and every span, and at span ≤\n * `sizeSpanMin` it is exactly 1 whatever the slope. The shader's arithmetic, on\n * the CPU for the tests.\n */\nexport function rimAlongSideFactor(\n field: number,\n spanPx: number,\n optics: MaterialOptics,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.max(0, 1 + optics.rimAlongSideSlope * sizeThickness(spanPx, profile) * field);\n}\n\n/**\n * **The sharp component's share at a depth** — s(u, span), the law the GPU\n * tier's optics pass evaluates per pixel (W13 G1, claims §5.61 §2).\n *\n * ```\n * s(u, span) = sDeep(span) + max(0, s₀(span) − sDeep(span)) · max(0, 1 − u / U)\n * ```\n *\n * with `sDeep = 1 − scatterDeepThickness(span)` and `s₀` the span-graded start\n * `scatterRampStart` resolves. Deeper than the reach the\n * surface reads its span law exactly; within it the sharp component is lifted\n * toward the contour value `s₀`. `max(0, s₀ − sDeep)` rather than a signed\n * difference: the excursion is the band the reference has *above* the body, and\n * on a span whose deep sharp share already exceeds `s₀` there is nothing to add\n * — the alternative would quietly make the small spans heavier at the contour\n * than in their own middle, which is the opposite of what §5.61 §2 measured.\n *\n * `uDevicePx` is the pixel's depth under the contour in DEVICE pixels, which is\n * the field's own signed distance (negative inside) read in CSS px and\n * multiplied by the ratio the tier draws at. Zero and negative depths — the\n * contour and everything outside it — read the start value, because the body\n * outside the silhouette is not drawn at all.\n *\n * The heavy share the body mixes by is 1 − s(u, span), before the accessibility\n * fold `scatterThickness` and the shader apply.\n */\nexport function scatterSharpShare(\n uDevicePx: number,\n devicePixelRatio: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n spanPx = 0,\n): number {\n const deepSharp = 1 - scatterDeepThickness(spanPx, profile, devicePixelRatio);\n const start = scatterRampStart(devicePixelRatio, profile, spanPx);\n const reach = Math.max(scatterRampReachDevicePx(devicePixelRatio, profile), 1e-6);\n const excursion = Math.max(start - deepSharp, 0) * Math.max(1 - Math.max(uDevicePx, 0) / reach, 0);\n return clampUnit(deepSharp + excursion);\n}\n\n/**\n * **The scattering facet's input** — how far toward its heavy blur a surface of\n * this span mixes ON AVERAGE, 0…1: the depth ramp's projection onto one number\n * per surface (W13 G1; the binding rule \"the span law is the ramp's projection,\n * on both tiers\").\n *\n * The GPU tier mixes per pixel and needs no projection; every other consumer\n * does — the CSS tier's single `blur()` σ, the sampling proxy's 3σ padding\n * floor, the demo's law readout — and if each of them invented its own the two\n * tiers would scatter differently. So this is the area average of the ramp over\n * the surface. Because the ramp now rides on the span law rather than replacing\n * it, the average is that law minus the excursion's average, and on a surface\n * far larger than the reach it is the span law almost exactly — which is what\n * keeps the CSS tier's large spans where W11c and W12 put them.\n *\n * `fold` is the accessibility fold every facet takes (the refraction ladder read\n * at the preference's cap, `sizeThicknessUnderPolicy`'s factor). It scales the\n * excursion away from `sizeScatterFloor` and NOT the floor itself: the floor is\n * the frost the material has at any size, the rest is depth a preference is\n * entitled to remove. At fold 1 this is the ramp's own average and at fold 0 it\n * is the floor exactly.\n *\n * Mirrored by `@vitreajs/vitrea-web`'s `scatterThickness`, pinned by\n * `packages/calibration/test/tier-coherence.test.ts` over spans, folds and dpr.\n */\nexport function scatterThickness(\n spanPx: number,\n fold: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n extentsCssPx?: readonly [number, number],\n): number {\n const floor = scatterFloorAtScale(profile, devicePixelRatio);\n const mean = scatterRampAreaMean(spanPx, profile, devicePixelRatio, extentsCssPx);\n return clampUnit(floor + (mean - floor) * fold);\n}\n\n/**\n * The unfolded area average of the heavy share over a surface — the integral\n * `scatterThickness` documents, separated so a reader can check the closed form\n * against a quadrature and so the fold stays one multiplication.\n *\n * The average is exact rather than sampled. The heavy share at depth u is\n * `kDeep(span) − A · T(u)` with `A = max(0, s₀ − sDeep)` the excursion's\n * amplitude and `T(u) = max(0, 1 − u / R)` its triangle in depth, so the area\n * average is `kDeep − A · T̄` and only `T̄` has to be integrated — the amplitude\n * is one number per surface even though the start grades with span, because a\n * surface has one span. On a rectangle\n * the area at depth ≥ u is `(W − 2u)(H − 2u)`, so the area *at* depth u has\n * measure `P − 8u` with `P = 2(W + H)`, and\n *\n * ```\n * T̄ = (1 / WH) ∫₀^{min(R, min(W,H)/2)} (1 − u / R) · (P − 8u) du\n * = (1 / WH) · [ P·m − 4m² − P·m² / (2R) + (8/3)·m³ / R ]\n * ```\n *\n * with `m` that upper limit: a surface shallower than the reach integrates only\n * the depth it has. The corners are ignored — a rounded rect's erosion keeps the\n * corner radius shrinking with the depth and the exact measure differs from\n * `P − 8u` only inside the corner quarter-disks — which is the same\n * approximation the spec's design states and costs less than the ramp's own\n * measurement error.\n *\n * `extentsCssPx` is the surface's own width and height where the caller has\n * them. Where it does not — and most callers do not, because a group's law is\n * taken over its *widest member's span* and a span is one number — the surface\n * is taken to be a square of the span, which is the honest reading of \"a\n * surface of this span\" and is exactly right on the calibration bed's square\n * components.\n */\nexport function scatterRampAreaMean(\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n extentsCssPx?: readonly [number, number],\n): number {\n const deep = scatterDeepThickness(spanPx, profile, devicePixelRatio);\n const amplitude = Math.max(scatterRampStart(devicePixelRatio, profile, spanPx) - (1 - deep), 0);\n if (amplitude <= 0) return clampUnit(deep);\n const width = Math.max(extentsCssPx?.[0] ?? spanPx, 0);\n const height = Math.max(extentsCssPx?.[1] ?? spanPx, 0);\n const area = width * height;\n if (area <= 0) return clampUnit(deep - amplitude);\n // The reach in CSS px, which is the unit the depth arrives in: u_device / U =\n // u_css · dpr / U, so the CSS-space reach is U / dpr and the ratio is the same\n // number the shader computes.\n const reach = Math.max(\n scatterRampReachDevicePx(devicePixelRatio, profile) / Math.max(devicePixelRatio, 1e-3),\n 1e-6,\n );\n const perimeter = 2 * (width + height);\n const limit = Math.min(reach, Math.min(width, height) / 2);\n const triangleMean =\n (perimeter * limit\n - 4 * limit * limit\n - (perimeter * limit * limit) / (2 * reach)\n + (8 * limit * limit * limit) / (3 * reach))\n / area;\n return clampUnit(deep - amplitude * triangleMean);\n}\n\n/**\n * The same, for a caller that has already resolved the scatter thickness — which\n * is every caller with a policy to fold under.\n *\n * The two-function shape is deliberate and it is mirrored on the CSS tier: the\n * thickness form is the law, the span form is the convenience that computes an\n * unfolded thickness for it. One formula, so a policy fold cannot end up applied\n * to one facet and not another.\n *\n * **The ratio never divides this σ.** W12 G3 read the widths as device-pixel\n * quantities (claims §5.56 §1) and this form divided by the ratio; W13 Decision\n * Log 8 (user-decided, 2026-09-04) retired that on the bed, and W15 G1 restores\n * the device-pixel reading on the GPU tier alone, where the renderer's\n * `bodySigmaCssFor` divides the sharp width by the viewport's own ratio. This\n * function is the SHARED projection — the CSS tier's single `blur()` σ, a\n * group's 3σ padding floor, the demo's readout — and W15 Decision Log 2 leaves\n * W13 Decision Log 5 in force until G1 predicts the CSS tier's 2x σ, so a\n * division here would move the CSS tier the way claims §5.69 §4 says is wrong\n * (its own measured 2x ceiling is 3–5 CSS px, LARGER than the 1x reading, not\n * half of it).\n *\n * What the ratio does reach is the GAIN: `sizeScatterGainMax2x` is the heavy\n * width's multiplier at dpr 2 (claims §5.69 §1), so at mix 0 this returns\n * `sigmaPx` at every ratio and at mix 1 it returns the ratio's own heavy width.\n * On the landed material the two gains are equal and every ratio returns the 1x\n * σ, which is what `tier-coherence` pins.\n *\n * `spanPx` is OPTIONAL and it selects which gain: given, the span-graded one\n * `scatterGainAt` resolves (W15 G1's re-form, claims §5.70 §4 and §7); omitted,\n * the flat `scatterGainAtScale`. The two are the same number at every span at\n * dpr ≤ 1 and on any profile whose far gain equals its base gain, so a caller\n * that has no span — `css-tier.ts`'s single `blur()`, the demo's readout —\n * keeps exactly the meaning it had, and a caller that has one gets the width\n * the reference's own kernel has at that span. The parameter rather than a\n * second function because this is the mix's own end point and there is one of\n * it.\n */\nexport function sizeScatterSigmaAt(\n sigmaPx: number,\n scatter: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n devicePixelRatio = 1,\n spanPx?: number,\n): number {\n const mix = clampUnit(scatter);\n const gain =\n spanPx === undefined\n ? scatterGainAtScale(profile, devicePixelRatio)\n : scatterGainAt(spanPx, profile, devicePixelRatio);\n return sigmaPx * (1 + (gain - 1) * mix);\n}\n\n/** 0…1, the clamp every share in this facet takes. */\nfunction clampUnit(value: number): number {\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * The occlusion alpha a surface of this span carries — the opacity facet.\n *\n * Composes with `occlusionAlphaUnderPolicy` rather than replacing it: both close\n * a fraction of whatever transparency is left, so the order they are applied in\n * changes the result by less than either term and neither can cancel the other.\n * The accessibility policy is applied first, because a preference outranks a\n * material law.\n */\nexport function sizeOcclusionAlpha(\n alpha: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return sizeOcclusionAlphaAt(alpha, sizeThickness(spanPx, profile), profile);\n}\n\n/** The same, for a caller that has already resolved the thickness factor. */\nexport function sizeOcclusionAlphaAt(\n alpha: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.min(1, alpha + profile.sizeOcclusionGain * thickness * (1 - alpha));\n}\n\n/** The inner shadow's depth at this span — see `MaterialProfile.sizeShadowGainMax`. */\nexport function sizeShadowDepth(\n shadowDepth: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return sizeShadowDepthAt(shadowDepth, sizeThickness(spanPx, profile), profile);\n}\n\n/** The same, for a caller that has already resolved the thickness factor. */\nexport function sizeShadowDepthAt(\n shadowDepth: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return shadowDepth * (1 + (profile.sizeShadowGainMax - 1) * thickness);\n}\n\n/**\n * The outer shadow's peak occlusion at this span — see\n * `MaterialOuterShadow.sizeGain`. At the shipped gain of 0 this is the identity,\n * exactly, which is the point.\n */\nexport function sizeOuterShadowOcclusion(\n occlusion: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return sizeOuterShadowOcclusionAt(occlusion, sizeThickness(spanPx, profile), profile);\n}\n\n/** The same, for a caller that has already resolved the thickness factor. */\nexport function sizeOuterShadowOcclusionAt(\n occlusion: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n return Math.min(1, occlusion + profile.outerShadow.sizeGain * thickness * (1 - occlusion));\n}\n\n/**\n * Where the thin regime's three amplitude anchors sit on the backdrop luminance\n * axis, and where the two interpolations between them run (W14 G1).\n *\n * The axis is the SAME statistic W9's face response keys on — the backdrop's\n * ENCODED-space mean, decoded to a linear luminance — which is the charter's\n * third binding rule (\"no second luminance statistic is introduced for the\n * shadow\"). `MaterialProfile.backdropToneAnchorX` names the same three solids in\n * the encoded space: 0.1104 / 0.2706 / 0.9505 encoded are 0.0117 / 0.0595 /\n * 0.891 linear, which is `inert` / `midFrom` / `bright` below.\n *\n * `midFrom` … `midTo` is a plateau the bed MEASURED at four backdrops\n * (`mid-dark-solid` 0.06, checkerboard and `photo` in between, `hc-text` 0.74),\n * flat to 0.02 in occlusion. The two interpolations either side of it are\n * **declared choices, not measurements**, and the bed does not constrain either:\n *\n * - `midTo` → `bright` (0.74 → 0.891) is taken LINEAR in luminance. The bed\n * jumps straight from `hc-text` to `light-solid` with nothing between, and\n * the whole factor-of-2.6 drop happens in that gap (claims §5.62, W14\n * Deferred: \"one backdrop between them would pin it\"). A linear ramp is the\n * least-committed curve through two endpoints; a smoothstep would assert a\n * knee at each end that nothing measured.\n * - `inert` → `midFrom` (0.02 → 0.06) is taken by SMOOTHSTEP. Below `inert` the\n * reference removes at most one or two of 255 codes and the compare's shadow\n * axis reports nothing at all (its backdrop floor is 0.05), so this ramp is\n * unmeasured over its whole length; it is a smoothstep so that the facet\n * arrives with a zero derivative at the black end and a scene fading from\n * `dark-solid` to `mid-dark-solid` does not show the shadow switching on.\n */\nexport const OUTER_SHADOW_THIN_L = {\n /** At and below this backdrop luminance the black term is `thinOcclusionDark`. */\n inert: 0.02,\n /** From here the mid plateau holds. */\n midFrom: 0.06,\n /** To here — `hc-text`'s own linear luminance. */\n midTo: 0.74,\n /** `light-solid`'s linear luminance, where 0.127 was measured; held above. */\n bright: 0.891,\n} as const;\n\n/**\n * The backdrop luminance the law reads where the host measured none.\n *\n * Neither tier can adapt a shadow to a backdrop nobody declared or sampled, and\n * guessing black would delete the facet on every unsampled surface while\n * guessing white would halve it. The mid plateau is what four of the bed's seven\n * backdrops sit on and what W8's single amplitude was a compromise across, so an\n * unmeasured group keeps the closest thing to the shadow it had.\n */\nexport const OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE = 0.3;\n\n/**\n * The black term's peak occlusion below the knee, at a backdrop luminance — see\n * `OUTER_SHADOW_THIN_L` for the anchors and for which parts of this curve are\n * measured and which are declared.\n */\nexport function outerShadowThinOcclusion(\n backdropLuminance: number | undefined,\n shadow: MaterialOuterShadow,\n): number {\n const l = backdropLuminance ?? OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE;\n const { inert, midFrom, midTo, bright } = OUTER_SHADOW_THIN_L;\n if (l <= inert) return shadow.thinOcclusionDark;\n if (l < midFrom) {\n const t = (l - inert) / (midFrom - inert);\n const s = t * t * (3 - 2 * t);\n return shadow.thinOcclusionDark + (shadow.thinOcclusionMid - shadow.thinOcclusionDark) * s;\n }\n if (l <= midTo) return shadow.thinOcclusionMid;\n if (l >= bright) return shadow.thinOcclusionBright;\n const t = (l - midTo) / (bright - midTo);\n return shadow.thinOcclusionMid + (shadow.thinOcclusionBright - shadow.thinOcclusionMid) * t;\n}\n\n/** The three spans the thick regime's anchors were read at, CSS px (claims §5.62 §4). */\nexport const OUTER_SHADOW_THICK_SPANS = [96, 128, 160] as const;\n\n/**\n * The composite's peak occlusion above the knee, at a casting span — piecewise\n * linear through the three measured anchors and held flat outside them.\n *\n * Held rather than extrapolated at both ends: below 96 the thin regime is what\n * the blend is walking away from and an extrapolated line would cross it, and\n * above 160 the bed has no cell at all, where the measured rise is already\n * flattening (0.379 → 0.497 → 0.544 costs 0.118 over the first 32 px of span and\n * 0.047 over the next 32).\n *\n * Not keyed on the backdrop, unlike the thin regime: the anchors are the\n * composite's transmission measured on the checkerboard, and the bed has no\n * thick cell over a dark backdrop to key against (claims §5.62 §4 — a span-128\n * or 160 surface over `impulse` would separate the composite's two terms, and\n * that scene does not exist). The dark PROFILE carries its own three anchors.\n *\n * **What it costs where it is wrong, measured.** An earlier form of this comment\n * claimed it costs nothing visible, on the argument that a multiply over a\n * near-black backdrop removes near-nothing whatever its amplitude. X7's affine\n * pair contradicts that argument on the one calibration cell that tests it:\n * `dark-solid__rrect-md`, a span-96 surface over a backdrop of linear 0.0117,\n * where vitrea now removes 0.1645 at the `3-6` band against the reference's\n * 0.1094 and against the 0.1260 the W12 close removed — the thick path over a\n * near-black backdrop went from 15% light to **50% heavy** (claims §5.65 §5).\n * In absolute terms it is 0.7 of a code and no perceptual row in the matrix\n * notices, so it is a small error, not an invisible one; it is recorded as a gap\n * and it closes with a thick cell over a dark backdrop to key against.\n */\nexport function outerShadowThickOcclusion(\n spanPx: number,\n shadow: MaterialOuterShadow,\n): number {\n const [s0, s1, s2] = OUTER_SHADOW_THICK_SPANS;\n const y0 = shadow.thickOcclusionAt96;\n const y1 = shadow.thickOcclusionAt128;\n const y2 = shadow.thickOcclusionAt160;\n if (spanPx <= s0) return y0;\n if (spanPx >= s2) return y2;\n if (spanPx <= s1) return y0 + ((y1 - y0) * (spanPx - s0)) / (s1 - s0);\n return y1 + ((y2 - y1) * (spanPx - s1)) / (s2 - s1);\n}\n\n/**\n * The outer shadow's peak LINEAR occlusion for one casting surface (W14 G1) —\n * the thin regime's backdrop-keyed amplitude, the thick regime's span law, and\n * the size law's gain, in that order.\n *\n * `thickness` is the size law's own curve for the casting surface, folded under\n * the accessibility policy exactly as every other span-dependent facet folds it\n * (`sizeThicknessUnderPolicy`); the blend between the two regimes is the\n * smoothstep of it — the SAME curve `backdropToneResponse` blends its thin and\n * thick rows across, so the shadow's knee and the face's knee are one knee.\n *\n * `backdropLuminance` is the statistic W9's response keys on, and `undefined`\n * means the host measured no backdrop — see\n * `OUTER_SHADOW_UNMEASURED_BACKDROP_LUMINANCE`.\n */\nexport function outerShadowOcclusionAt(\n shadow: MaterialOuterShadow,\n backdropLuminance: number | undefined,\n spanPx: number,\n thickness: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): number {\n const thin = outerShadowThinOcclusion(backdropLuminance, shadow);\n const thick = outerShadowThickOcclusion(spanPx, shadow);\n const k = Math.min(1, Math.max(0, thickness));\n const blend = k * k * (3 - 2 * k);\n return sizeOuterShadowOcclusionAt(thin + (thick - thin) * blend, thickness, profile);\n}\n\n/**\n * The lift's span rise, 0…1 — the fraction of `liftAmplitude` a surface of this\n * casting span adds. Zero at and below `liftSpanMin`, one at and above\n * `liftSpanFull`, a smoothstep between; see `MaterialOuterShadow.liftSpanFull`\n * for why a smoothstep rather than the layer tree's own linear clamp.\n */\nexport function outerShadowLiftRise(spanPx: number, shadow: MaterialOuterShadow): number {\n return smoothstep(shadow.liftSpanMin, shadow.liftSpanFull, spanPx);\n}\n\n/**\n * The outer shadow under an accessibility regime.\n *\n * One branch per axis that can reach it, on `opticsUnderPolicy`'s rule. `frost`\n * is the axis reduced transparency alone sets, and the amplitude it lands on is\n * measured — see `MaterialOuterShadow.reducedTransparencyOcclusion`. Under\n * forced colours the material is gone, so its shadow goes with it rather than\n * outliving the surface that cast it.\n *\n * The fold writes ONE amplitude into all six anchors rather than scaling them,\n * because that is what the reference does: under the preference its exterior is\n * flat at 0.192–0.202 thin and thick together and over every backdrop, so the\n * law's two regimes collapse onto one level and neither the backdrop keying nor\n * the span rise survives (claims §5.62 §5). Flattening the anchors here keeps\n * one folded `MaterialOuterShadow` as the single value every caller resolves\n * from, and the resolved occlusion is then that level for any span, any backdrop\n * and any thickness, since a blend between equal ends is the end. The LIFT\n * stands down with them — a composite whose two regimes read the same number has\n * no second term in it.\n */\nexport function outerShadowUnderPolicy(\n policy: MaterialPolicyView,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): MaterialOuterShadow {\n const shadow = profile.outerShadow;\n if (policy.glass === \"none\" || policy.frost === \"none\") return flatOuterShadow(shadow, 0);\n if (policy.frost === \"increased\") {\n return flatOuterShadow(shadow, shadow.reducedTransparencyOcclusion);\n }\n return shadow;\n}\n\n/** Every amplitude anchor set to `amplitude`, with the lift stood down. */\nfunction flatOuterShadow(shadow: MaterialOuterShadow, amplitude: number): MaterialOuterShadow {\n return {\n ...shadow,\n thinOcclusionDark: amplitude,\n thinOcclusionMid: amplitude,\n thinOcclusionBright: amplitude,\n thickOcclusionAt96: amplitude,\n thickOcclusionAt128: amplitude,\n thickOcclusionAt160: amplitude,\n liftAmplitude: 0,\n };\n}\n\n/**\n * The Gaussian CDF the shadow's edge falls off by, at a signed distance OUTSIDE\n * the shadow's own silhouette: 1 deep inside, 0.5 exactly on it, 0 far outside.\n *\n * A Gaussian-blurred silhouette is what `box-shadow` specifies and what the\n * reference measures, so this is the one curve, evaluated identically by both\n * tiers and by the shader. Written as the tanh form rather than as `erf` because\n * WGSL has no `erf` and a curve the shader cannot evaluate is not one shape: the\n * approximation's worst error is 1.8e-4 across the whole line, which at the\n * shipped occlusion is 0.015 of one 8-bit code.\n */\n/** sRGB's power-law exponent — the one `outerShadowAlpha` inverts. */\nexport const SRGB_ENCODING_EXPONENT = 2.4;\n\nexport function outerShadowFalloff(signedDistancePx: number, sigmaPx: number): number {\n const x = -signedDistancePx / Math.max(sigmaPx, 1e-4);\n /*\n * The argument is clamped so that this and the shader stay one function\n * (W30 G3b; claims §5.159b). `Math.tanh` is exact at every magnitude, so here\n * the clamp does nothing an f64 reader can observe — `tanh` returns exactly\n * 1.0 from |t| = 19.0615 up, measured, and not from 18.2, which this comment\n * said until the review closure corrected it (§5.159b §10) — and it is\n * written all the same, because the WGSL\n * mirror needs it: a backend that lowers `tanh` through `exp(2t)` overflows\n * f32 past |t| = 44.36 and returns NaN, and a guard that lived on one side of\n * the mirror would be a difference between the tiers rather than a fix. ±20\n * is the smallest round bound above f64's own saturation point, so the two\n * implementations return the same bits at every argument.\n */\n const t = Math.min(20, Math.max(-20, 0.7978845608028654 * (x + 0.044715 * x * x * x)));\n return 0.5 * (1 + Math.tanh(t));\n}\n\n/**\n * **The outer shadow's σ at a casting span**, CSS px (W30 G2; claims §5.156 §2):\n *\n * σ(span) = sigmaPx + max(sigmaThinOffsetPx,\n * sigmaSlopePerSpan · (span − sigmaSpanRefPx))\n *\n * One function of the CSS span with no device ratio in it, because the cut\n * rejected the device-px reading of the thin regime in both directions — which\n * is one mirror fewer for the CSS tier to keep and one reach for both scales.\n *\n * It is evaluated PER CASTER on both tiers and nowhere per group: the GPU tier\n * reads the casting surface's own span per pixel from the field pass's aux\n * target, and the CSS tier writes one `box-shadow` blur radius per surface. The\n * two GROUP-level readers — the optics pass's scissor pad and the CSS tier's\n * group-shadow clip — take the law at the widest span any member casts at, which\n * is a bound on every member's own σ rather than any member's value.\n *\n * At the shipped defaults the three leaves are 0, so this returns `shadow.sigmaPx`\n * identically: the span term is a multiplied zero and the offset an added zero\n * under a `max` whose other arm is that same zero. The identity is algebraic and\n * holds at every argument, including a negative or absent span.\n */\nexport function outerShadowSigmaPx(shadow: MaterialOuterShadow, spanPx: number): number {\n return (\n shadow.sigmaPx +\n Math.max(shadow.sigmaThinOffsetPx, shadow.sigmaSlopePerSpan * (spanPx - shadow.sigmaSpanRefPx))\n );\n}\n\n/**\n * The compositing-space alpha that reproduces a linear-light occlusion.\n *\n * Both tiers paint the shadow the same way — a pure BLACK layer at some alpha,\n * composited source-over — and that is already a multiplicative occlusion by\n * compositing algebra alone: `out = (1 − α)·backdrop + α·0 = backdrop·(1 − α)`.\n * The shadow's colour being zero is what collapses source-over onto multiply, and\n * it is also why the facet is exactly inert over black on both tiers, with no\n * special case anywhere.\n *\n * What does NOT come free is the space. The reference removes a fraction of the\n * backdrop's LINEAR light; a browser composites a `box-shadow` — and a\n * premultiplied canvas — in ENCODED sRGB. So the same visual result needs a\n * different alpha, and the conversion is exact under sRGB's power law:\n * `enc(L(1−occ)) = enc(L)·(1−α)` gives `α = 1 − (1−occ)^(1/2.4)`, independent of\n * the backdrop, which is the same conversion `cssTintAlpha` performs for the tint\n * and the same reason it exists.\n *\n * The residual is the transfer function's linear toe, and it is small and stated:\n * across every backdrop level from 0.004 to 1.0 the worst departure from the\n * reference's own composite is 2.1 of 255 at the shipped occlusion, against a bed\n * whose own reproducibility is ±4 of 255 (Decision Log 10). A per-pixel exact\n * conversion is not available to either tier — `box-shadow` takes one alpha, and\n * the canvas composites outside the shader — so this is the honest floor rather\n * than a shortcut.\n */\nexport function outerShadowAlpha(occlusion: number): number {\n const occ = Math.min(1, Math.max(0, occlusion));\n return 1 - Math.pow(1 - occ, 1 / SRGB_ENCODING_EXPONENT);\n}\n\n/**\n * How far past a surface's own contour the shadow can still change a pixel, CSS\n * px — the margin the GPU tier has to rasterise into, since a scissor rect that\n * stops at the contour would slice the facet off.\n *\n * The cut-off is where the shadow stops moving an 8-bit code over a white\n * backdrop, and it is taken against the **compositing-space alpha** rather than\n * against the linear occlusion, because the alpha is what the canvas actually\n * writes: `page × (1 − α·falloff)` moves one code when `α·falloff` reaches\n * 1/255. Thresholding the linear occlusion instead over-allocated by about 5 CSS\n * px on every edge at the shipped constants — pure cost on a facet already\n * measured at 3.2× the frame's GPU time.\n *\n * `occlusion` must be the EFFECTIVE amplitude — after the accessibility fold,\n * after the backdrop key and the span law, and after the size law — which is the\n * caller's to resolve, because only it knows the group's membership and the\n * backdrop it sits over. A pad taken from the base amplitude while the shader\n * emits an amplified one slices the deepest surface's shadow off at the scissor,\n * while the CSS tier, which has no scissor, goes on drawing it. It is a separate\n * argument since W14 G1, because a `MaterialOuterShadow` no longer carries one\n * amplitude to read.\n *\n * The solve runs over the signed distance to the shadow's OWN silhouette, which\n * may be negative — a pixel just outside the contour is already inside the\n * offset, spread silhouette — so `occlusion = 0`, and any amplitude too faint to\n * move a code anywhere, both fall out as a reach of zero rather than needing a\n * case of their own.\n *\n * `spanPx` is the CASTING span the σ law is read at (W30 G2; see\n * `outerShadowSigmaPx`), and it is the second quantity a caller now owes for the\n * amplitude's reason: since macOS 27 the blur is a function of the caster, so a\n * reach taken at one span while the shader draws another is the same slice at\n * the scissor that a reach taken from the base amplitude was.\n *\n * It is **required**, with no default. A default of 0 would read as \"no span to\n * give\" and resolve as the thinnest caster there is, which is an UNDER-bound the\n * moment the slope is non-zero — and it would be a silent one, because at the\n * inert leaves it is exactly right (W30 G2 review closure, claims §5.158 §8,\n * finding 4). A caller with no span states the span it means.\n *\n * **A group's caller passes the largest occlusion and the largest span among its\n * members, and `reach(max occlusion, max span)` bounds every member's own reach\n * exactly while `sigmaSlopePerSpan ≥ 0`** — σ non-decreasing in span. The reach\n * is monotone in σ (a wider Gaussian moves a code further out) and monotone in\n * the amplitude, and the two maxima are taken independently, so the pair\n * dominates every member's pair. A NEGATIVE slope would make the widest member's\n * σ the smallest, and the bound would have to be taken at the thinnest span\n * instead; the law's shape is a blur that grows with the caster, and\n * `w30-inert-laws.test.ts` asserts the monotonicity at the shape §5.159 fits so\n * that a fit inheriting a negative slope fails there rather than at a scissor.\n */\nexport function outerShadowReachPx(\n shadow: MaterialOuterShadow,\n occlusion: number,\n spanPx: number,\n): number {\n const alpha = outerShadowAlpha(occlusion);\n if (!(alpha > 0)) return 0;\n const cutoff = 1 / 255 / alpha;\n // Even a pixel the silhouette covers outright cannot move a code.\n if (cutoff >= 1) return 0;\n\n const sigma = Math.max(outerShadowSigmaPx(shadow, spanPx), 1e-4);\n // Bisected on the falloff itself, so the reach cannot disagree with what the\n // shader draws.\n let lo = -(8 * sigma + Math.abs(shadow.offsetPx) + Math.abs(shadow.spreadPx));\n let hi = 8 * sigma;\n for (let i = 0; i < 48; i += 1) {\n const mid = (lo + hi) / 2;\n if (outerShadowFalloff(mid, sigma) > cutoff) lo = mid;\n else hi = mid;\n }\n\n /*\n * Back to a distance from the COMPONENT's contour, in whichever direction\n * reaches furthest — the pad is applied to all four edges, so one bound has to\n * cover them all. The offset enters by magnitude (downward when positive,\n * upward when negative) and the spread carries its own sign, because a\n * negative spread pulls every direction in together.\n */\n return Math.max(0, hi + Math.abs(shadow.offsetPx) + shadow.spreadPx);\n}\n\n/**\n * The lens depth in CSS px (W12 G2): the reference's own height law,\n * `min(lensHeightPerSpan · span, lensHeightMax)`, scaled by the author's\n * thickness over `lensThicknessReference`, clamped to the shorter half extent.\n * 8 / 11 / 20 on spans 32 / 44 / ≥ 80 at the default thickness — the numbers\n * read from the reference's layer tree (claims §5.50).\n *\n * `fold` is the accessibility regime's factor on the size-dependent part (the\n * refraction ladder at the preference's cap, `sizeThicknessUnderPolicy`'s\n * factor): at 1 the depth is the law's, at 0 it is the authored thickness and\n * nothing more — the same shape the W2 law folded by, so a reduced regime\n * keeps the lens it had.\n */\nexport function lensDepthPx(\n thicknessPx: number,\n spanPx: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n fold = 1,\n): number {\n const thick = Math.max(thicknessPx, 0);\n const scale = thick / profile.lensThicknessReference;\n const depth = thick + (lensHeightBasePx(spanPx, profile) * scale - thick) * fold;\n return Math.min(Math.max(depth, 0), spanPx * 0.5);\n}\n\n/**\n * How far inside the surface the shader reads the body for a pixel `depthPx`\n * in from the contour (W12 G2), in CSS px — `S · max(0, 1 − depthPx / L′)^p`\n * with `S = lensMagnitudePx`, `L′ = lensExtentPx` and `p` the profile's\n * exponent, times the refraction scale the policy resolved. At the default\n * thickness on a 96 px span: 33.7 / 24.3 / 11.9 at 2 / 4 / 8 px in, zero from\n * 26.7 px in — the reference's crossings read 34 / 24 / 12 (claims §5.49).\n */\nexport function lensDisplacementPx(\n depthPx: number,\n spanPx: number,\n thicknessPx: number,\n refractionScale: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n fold = 1,\n): number {\n const extent = lensExtentPx(thicknessPx, spanPx, profile, fold);\n if (extent <= 0) return 0;\n const t = Math.max(0, 1 - Math.max(depthPx, 0) / extent);\n return (\n lensMagnitudePx(thicknessPx, spanPx, profile, fold) *\n Math.pow(t, profile.lensProfileExponent) *\n refractionScale\n );\n}\n","/**\n * Backdrop analysis on the CPU side: the stats a reduction produced, and the\n * temporal hysteresis that makes them usable.\n *\n * §Motion binds `backdrop-adaptation values` to the *exponential low-pass +\n * hysteresis* driver, and §Motion also puts every driver on the CPU. So the shape\n * is: the GPU reduces (exactly — X2's `analysis: \"exact\"`), the result is read\n * back at a low rate, and `LowPassHysteresisDriver` from `@vitrea/motion` — the\n * same class the rest of the runtime uses, not a reimplementation — smooths it.\n * The shader reads the driver's output as a uniform and never sees the raw stat.\n *\n * ## Why the readback is not a per-frame cost\n *\n * §Foreground adaptation caps the readback at an advisory 15 Hz (Decision Log\n * #19), and the governor lowers it further. That is not a performance\n * concession — it is what keeps the adaptation honest. A per-frame readback would\n * either stall the pipeline waiting for the map, or produce a value two frames old\n * and pretend it was current. At 15 Hz with a 500 ms low-pass the staleness is far\n * inside the filter's own time constant, so it is invisible in the output.\n *\n * ## The band is on the input, not the output\n *\n * `LowPassHysteresisDriver` commits a new observation only once it departs the\n * *committed* value by more than the band, then low-passes the committed\n * staircase. Measuring against the moving output instead would let a slow drift\n * leak through one small step at a time, which is exactly the foreground pumping\n * §Foreground adaptation rules out. That property is the driver's, and it is the\n * reason to use the driver rather than an `exp()` here.\n */\n\nimport { LowPassHysteresisDriver } from \"@vitrea/motion\";\n\nimport { DEFAULT_MATERIAL_PROFILE, type MaterialProfile } from \"./material\";\nimport { srgbToLinearChannel, type Rgb } from \"./color\";\n\n/** The four floats the reduction writes. */\nexport interface BackdropStats {\n /** Mean linear luminance, 0..1-ish (an HDR-ish source can exceed 1). */\n readonly luminance: number;\n /** Variance of linear luminance. */\n readonly variance: number;\n /** Mean luminance-gradient magnitude per texel — the edge-density measure. */\n readonly edgeDensity: number;\n /** Samples the reduction actually took. 0 means \"never reduced\". */\n readonly sampleCount: number;\n}\n\nexport const ZERO_STATS: BackdropStats = {\n luminance: 0,\n variance: 0,\n edgeDensity: 0,\n sampleCount: 0,\n};\n\nexport function statsFromBuffer(values: ArrayLike<number>): BackdropStats {\n return {\n // The reduction publishes the ENCODED-space mean (the W9 model, claims\n // §5.31) and this is its one decode: every consumer downstream — the\n // drivers, `adaptiveTint`'s fitted thresholds — still speaks linear light,\n // and a solid backdrop reads identically under either convention.\n luminance: srgbToLinearChannel(values[0] ?? 0),\n variance: values[1] ?? 0,\n edgeDensity: values[2] ?? 0,\n sampleCount: values[3] ?? 0,\n };\n}\n\n/**\n * Driver configuration for the three adaptation channels.\n *\n * The time constant and band are §Motion's `backdropAdaptation` defaults — a long\n * constant and a wide band so scrolling past a contrast edge cannot pump the\n * material. Restated as a literal rather than read off `DEFAULT_MOTION_PROFILE`\n * because `edgeDensity` and `variance` live on different scales from luminance and\n * want their own bands; the *shape* is motion's, the widths are this package's.\n */\nconst LUMINANCE_CONFIG = {\n kind: \"low-pass-hysteresis\",\n timeConstantMs: 500,\n hysteresis: 0.04,\n restDistance: 1e-3,\n} as const;\n\nconst VARIANCE_CONFIG = { ...LUMINANCE_CONFIG, hysteresis: 0.01 } as const;\nconst EDGE_CONFIG = { ...LUMINANCE_CONFIG, hysteresis: 0.01 } as const;\n\nexport interface AdaptationValues {\n readonly luminance: number;\n readonly variance: number;\n readonly edgeDensity: number;\n /** The tint the optics pass should mix toward, in linear light. */\n readonly tint: Rgb;\n /** True once at least one reduction has been observed. */\n readonly observed: boolean;\n}\n\nexport interface AdaptationState {\n /** Commit a fresh reduction. Cheap — the band may reject it outright. */\n observe(stats: BackdropStats): void;\n /** Advance the filters by a frame delta in ms. */\n advance(deltaMs: number): void;\n /** Jump the filters to a reduction with no transient. Used on the first frame. */\n reset(stats: BackdropStats): void;\n readonly values: AdaptationValues;\n readonly settled: boolean;\n}\n\nconst smoothstep = (edge0: number, edge1: number, x: number): number => {\n if (edge1 <= edge0) return x < edge0 ? 0 : 1;\n const t = Math.min(1, Math.max(0, (x - edge0) / (edge1 - edge0)));\n return t * t * (3 - 2 * t);\n};\n\n/**\n * The adaptive tint: a crossfade between the dark-backdrop and light-backdrop\n * tints across a luminance band.\n *\n * The crossfade is deliberately not a hard threshold. §Motion gives the\n * *foreground* light/dark decision a threshold-plus-crossfade driver because it\n * feeds a DOM `color`, which is discrete; the material's own tint is continuous\n * and can simply follow the smoothed luminance, so it does. One fewer driver, and\n * no risk of the tint and the foreground disagreeing at the threshold.\n */\nexport function adaptiveTint(\n luminance: number,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): Rgb {\n const dark = profile.adaptiveTintDark;\n const light = profile.adaptiveTintLight;\n const t = smoothstep(profile.adaptiveLuminanceLow, profile.adaptiveLuminanceHigh, luminance);\n return [\n dark[0] + (light[0] - dark[0]) * t,\n dark[1] + (light[1] - dark[1]) * t,\n dark[2] + (light[2] - dark[2]) * t,\n ];\n}\n\nexport function createAdaptationState(\n initial: BackdropStats = ZERO_STATS,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n): AdaptationState {\n const luminance = new LowPassHysteresisDriver(LUMINANCE_CONFIG, initial.luminance);\n const variance = new LowPassHysteresisDriver(VARIANCE_CONFIG, initial.variance);\n const edge = new LowPassHysteresisDriver(EDGE_CONFIG, initial.edgeDensity);\n let observed = initial.sampleCount > 0;\n\n return {\n observe(stats) {\n if (stats.sampleCount <= 0) return;\n observed = true;\n luminance.retarget(stats.luminance);\n variance.retarget(stats.variance);\n edge.retarget(stats.edgeDensity);\n },\n\n advance(deltaMs) {\n luminance.advance(deltaMs);\n variance.advance(deltaMs);\n edge.advance(deltaMs);\n },\n\n reset(stats) {\n observed = stats.sampleCount > 0;\n luminance.jumpTo(stats.luminance);\n variance.jumpTo(stats.variance);\n edge.jumpTo(stats.edgeDensity);\n },\n\n get values() {\n return {\n luminance: luminance.value,\n variance: variance.value,\n edgeDensity: edge.value,\n tint: adaptiveTint(luminance.value, profile),\n observed,\n };\n },\n\n get settled() {\n return luminance.settled && variance.settled && edge.settled;\n },\n };\n}\n\n/**\n * Whether a readback is due, given the governor's cadence.\n *\n * A single-slot gate rather than a queue: if the previous map has not resolved the\n * next one is simply skipped. Queueing readbacks under pressure is how a renderer\n * ends up with a backlog of stale buffers and a growing memory footprint, and the\n * consumer here cannot use two answers from the same frame anyway.\n */\nexport function readbackDue(\n lastAtMs: number | undefined,\n nowMs: number,\n cadenceHz: number,\n): boolean {\n if (cadenceHz <= 0) return false;\n if (lastAtMs === undefined) return true;\n return nowMs - lastAtMs >= 1000 / cadenceHz;\n}\n","/**\n * The renderer's typed failures.\n *\n * X3 asks for one specific behaviour and this class exists to deliver it:\n * \"App-supplied views must satisfy declared usage/format/dimension requirements\n * — **validated at registration with a typed error, never discovered at draw\n * time**.\" So every provider validates its descriptor before it touches the\n * device, and every rejection carries a code a caller can branch on plus a\n * message that says which requirement failed and what to pass instead.\n *\n * The split from core's diagnostics channel is deliberate and mirrors the one\n * `scene.ts` draws: a structural mistake — a view of the wrong format, a\n * duplicate source id, a draw against a torn-down device — throws, because\n * continuing leaves the resource graph describing textures that are not there.\n * Recoverable, per-frame findings are not errors: those travel as\n * `demotionReason`s through core's state model, which is the honest place for\n * \"this still renders, just less\".\n */\n\nexport const RENDERER_ERROR_CODES = [\n /** A `GPUTextureView`'s backing texture lacks a required usage flag. */\n \"texture-usage\",\n /** Format outside the set the sampling path can read. */\n \"texture-format\",\n /** Wrong view dimension, or a depth/array layer count the pass cannot bind. */\n \"texture-dimension\",\n /** Zero or absurd extent, or a size that exceeds the device's limits. */\n \"texture-size\",\n /** A source id registered twice, or an unknown id referenced. */\n \"source-identity\",\n /** The provider was asked for a frame it cannot produce (closed video, detached canvas). */\n \"source-unavailable\",\n /** No device is attached, or the attached one is lost. */\n \"device-unavailable\",\n /** A frame was acquired twice without a release, or released without an acquire. */\n \"frame-protocol\",\n /** A pass was asked to draw something the current resources cannot express. */\n \"pass-input\",\n] as const;\n\nexport type RendererErrorCode = (typeof RENDERER_ERROR_CODES)[number];\n\nexport class RendererError extends Error {\n readonly code: RendererErrorCode;\n /** The source, group or node the failure is about, when there is one. */\n readonly subject: string | undefined;\n\n constructor(code: RendererErrorCode, message: string, subject?: string) {\n super(message);\n this.name = \"RendererError\";\n this.code = code;\n this.subject = subject;\n }\n}\n\nexport function rendererError(\n code: RendererErrorCode,\n message: string,\n subject?: string,\n): RendererError {\n return new RendererError(code, message, subject);\n}\n","/**\n * X3 — the BackdropFrame acquisition protocol, and a provider for every source\n * kind §Backdrop contracts names.\n *\n * The spec calls this contract \"operational, not aspirational\", and the reason is\n * a hard WebGPU fact: **there is no cross-device texture sharing.** So every\n * source, however it arrives, is normalised through one protocol —\n * `acquire(frame)` at frame start, `release()` after submit — and the frame\n * carries the four things a consumer cannot infer: the binding, the size epoch,\n * the colour space, and the alpha mode.\n *\n * ## The five kinds, and what is actually different about each\n *\n * | kind | mechanism | alpha | re-acquired |\n * | --- | --- | --- | --- |\n * | `image` | `copyExternalImageToTexture` | premultiplied | only when dirty |\n * | `video` | `importExternalTexture` | **unpremultiplied** | **every sampling frame** |\n * | `canvas` | `copyExternalImageToTexture` | premultiplied | every frame by default |\n * | `gradient` | `queue.writeTexture` of CPU-generated texels | opaque | never |\n * | `app-texture-view` | the app's own `GPUTexture` | declared by the app | every frame |\n *\n * Two of those cells are WebGPU semantics rather than choices, and §Surprises\n * records them as such: `importExternalTexture` handles **expire at task end**, so\n * a video must be re-imported on every frame that samples it; and imported video\n * arrives **unpremultiplied** while copied images arrive premultiplied. The import\n * pass normalises both to premultiplied linear, so nothing downstream branches on\n * either fact.\n *\n * ## VideoFrame ownership\n *\n * X3: \"`VideoFrame` close ownership held by the provider.\" When the app hands in a\n * `VideoFrame`, this provider closes it in `release()` — after submit, because an\n * imported external texture must outlive the submission that samples it. When the\n * app hands in an `HTMLVideoElement` the browser owns the frames and the provider\n * closes nothing. Getting that backwards leaks decoder buffers until playback\n * stalls, which is why the two cases are separate provider inputs rather than one\n * permissive union.\n *\n * ## Device generations\n *\n * The same WebGPU fact has a second consequence, and it is the one easiest to get\n * wrong: a provider closes over the device it was built with, so when that device\n * dies the provider holds storage nothing can bind and a texture handle nothing\n * will complain about. `invalidate(generation, device)` is how a provider crosses\n * that boundary — new device adopted, old storage dropped, re-import armed — and\n * `generation` is the tag that says which side of it the provider is on. The\n * app-texture provider is the exception on purpose: the renderer cannot re-make\n * someone else's texture, so it refuses rather than binding a foreign-device view\n * that would render nothing and report nothing.\n *\n * ## Validation at registration\n *\n * Also X3: app-supplied views \"must satisfy declared usage/format/dimension\n * requirements — validated at registration with a typed error, never discovered at\n * draw time.\" `registerAppTexture` therefore takes the `GPUTexture`, not just a\n * view: a `GPUTextureView` exposes none of its own properties, so a contract that\n * accepted only a view could not be checked at all.\n */\n\nimport {\n type BackdropAlphaMode,\n type BackdropColorSpace,\n linearToSrgbChannel,\n srgbToLinearChannel,\n} from \"./color\";\nimport { rendererError } from \"./errors\";\n\nexport const BACKDROP_KINDS = [\n \"image\",\n \"video\",\n \"canvas\",\n \"gradient\",\n \"app-texture-view\",\n] as const;\n\nexport type BackdropKind = (typeof BACKDROP_KINDS)[number];\n\n/** How the import pass binds the source. `external` needs its own pipeline. */\nexport type BackdropBinding =\n | { readonly kind: \"sampled\"; readonly view: GPUTextureView }\n | { readonly kind: \"external\"; readonly texture: GPUExternalTexture };\n\nexport interface BackdropFrame {\n readonly sourceId: string;\n readonly binding: BackdropBinding;\n /** Source extent in texture px. */\n readonly width: number;\n readonly height: number;\n /** Bumped when the extent changes; invalidates every dependent allocation. */\n readonly sizeEpoch: number;\n readonly colorSpace: BackdropColorSpace;\n readonly alphaMode: BackdropAlphaMode;\n /** True when the sampled values are sRGB-encoded rather than linear. */\n readonly encoded: boolean;\n}\n\n/** The frame facts a provider is handed. Matches core's `FrameInfo`. */\nexport interface FrameInfoView {\n readonly id: number;\n readonly timeMs: number;\n}\n\nexport interface BackdropProvider {\n readonly id: string;\n readonly kind: BackdropKind;\n /**\n * The device generation this provider's storage belongs to (`device.ts`'s\n * counter). A provider built under one generation holds nothing a later\n * generation can bind, and the failure is silent — so the number is here to be\n * compared, cheaply, before anything of the provider's is used.\n */\n readonly generation: number;\n /** True when content may have changed since the last successful import. */\n isDirty(): boolean;\n /** X3: at frame start. Throws `source-unavailable` if the source cannot serve. */\n acquire(frame: FrameInfoView): BackdropFrame;\n /** X3: after submit. Releases whatever the acquire took ownership of. */\n release(): void;\n /** Called once the import pass has consumed the frame's pixels. */\n markImported(): void;\n /**\n * Adopt `device` at `generation`: the device that built this provider's storage\n * is gone.\n *\n * Every provider closes over the device it was built with, so a reset that only\n * cleared the dirty flags would re-import onto the dead device and hand the new\n * one a foreign texture. Hence the device travels with the call.\n *\n * A provider whose storage the renderer allocated drops it and arms a\n * re-import, so recovery flows through the ordinary dirty path. A provider\n * wrapping the *app's* own texture cannot be re-pointed at all — WebGPU has no\n * cross-device sharing, and the app owns the texture — so it refuses every\n * later `acquire` with a typed error instead of binding a foreign-device view.\n */\n invalidate(generation: number, device: BackdropDevice): void;\n /**\n * Re-declare the source's extent. Implemented where the renderer allocates the\n * storage (image, canvas); absent where the source declares its own size.\n */\n resize?(width: number, height: number): void;\n destroy(): void;\n}\n\n/** Formats the sampling path can read. Everything else is refused at registration. */\nexport const SUPPORTED_APP_TEXTURE_FORMATS: readonly GPUTextureFormat[] = [\n \"rgba8unorm\",\n \"rgba8unorm-srgb\",\n \"bgra8unorm\",\n \"bgra8unorm-srgb\",\n \"rgba16float\",\n \"rgba32float\",\n];\n\n/** The slice of `GPUDevice` the providers need. `GPUDevice` satisfies it as-is. */\nexport interface BackdropDevice {\n readonly queue: GPUQueue;\n readonly limits: GPUSupportedLimits;\n createTexture(descriptor: GPUTextureDescriptor): GPUTexture;\n importExternalTexture(descriptor: GPUExternalTextureDescriptor): GPUExternalTexture;\n}\n\n/** Computed on first use, not at module scope — see the note in `passes.ts`. */\nconst copyUsage = (): GPUTextureUsageFlags =>\n GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT;\n\ninterface SizeTracker {\n epoch: number;\n width: number;\n height: number;\n}\n\nfunction trackSize(tracker: SizeTracker, width: number, height: number): void {\n if (tracker.width === width && tracker.height === height) return;\n tracker.width = width;\n tracker.height = height;\n tracker.epoch += 1;\n}\n\n// ---------------------------------------------------------------------------\n// image and canvas — copyExternalImageToTexture\n// ---------------------------------------------------------------------------\n\n/** Anything `copyExternalImageToTexture` accepts as a source. */\nexport type CopyableSource =\n | ImageBitmap\n | HTMLImageElement\n | HTMLCanvasElement\n | OffscreenCanvas\n | ImageData\n | VideoFrame;\n\nexport interface CopyProviderOptions {\n readonly id: string;\n readonly kind: \"image\" | \"canvas\";\n readonly device: BackdropDevice;\n readonly source: CopyableSource;\n readonly width: number;\n readonly height: number;\n readonly colorSpace?: BackdropColorSpace;\n /**\n * Whether content changes every frame. `true` for a live canvas, `false` for a\n * decoded image — which is what makes a static backdrop rebuild nothing at all\n * (§Core model invariant).\n */\n readonly live?: boolean;\n /** The device generation this provider is being built under. See `BackdropProvider.generation`. */\n readonly generation?: number;\n}\n\nexport function createCopyProvider(options: CopyProviderOptions): BackdropProvider {\n let device = options.device;\n const size = { epoch: 0, width: options.width, height: options.height };\n const live = options.live ?? options.kind === \"canvas\";\n let dirty = true;\n let texture: GPUTexture | undefined;\n let generation = options.generation ?? 0;\n\n const ensureTexture = (): GPUTexture => {\n if (texture !== undefined && texture.width === size.width && texture.height === size.height) {\n return texture;\n }\n texture?.destroy();\n texture = device.createTexture({\n label: `vitrea:backdrop:${options.id}:upload`,\n size: { width: size.width, height: size.height, depthOrArrayLayers: 1 },\n // 8-bit is the honest storage for an image or a canvas: both are 8-bit\n // sources, and the import pass promotes to float on the way into level 0.\n format: \"rgba8unorm\",\n usage: copyUsage(),\n });\n return texture;\n };\n\n return {\n id: options.id,\n kind: options.kind,\n\n get generation() {\n return generation;\n },\n\n isDirty() {\n return dirty || live;\n },\n\n acquire() {\n if (size.width <= 0 || size.height <= 0) {\n throw rendererError(\n \"source-unavailable\",\n `Backdrop \"${options.id}\" has a zero extent (${size.width}×${size.height}); nothing can be copied from it.`,\n options.id,\n );\n }\n const target = ensureTexture();\n if (dirty || live) {\n device.queue.copyExternalImageToTexture(\n { source: options.source, flipY: false },\n {\n texture: target,\n colorSpace: options.colorSpace ?? \"srgb\",\n // X3: copied images arrive premultiplied. Declaring it here is what\n // makes that true rather than assumed — the copy performs the multiply\n // when the source is not already premultiplied.\n premultipliedAlpha: true,\n },\n { width: size.width, height: size.height },\n );\n }\n return {\n sourceId: options.id,\n binding: { kind: \"sampled\", view: target.createView() },\n width: size.width,\n height: size.height,\n sizeEpoch: size.epoch,\n colorSpace: options.colorSpace ?? \"srgb\",\n alphaMode: \"premultiplied\",\n encoded: true,\n };\n },\n\n release() {\n // Nothing to release: the destination texture is this provider's own and\n // outlives the frame.\n },\n\n markImported() {\n dirty = false;\n },\n\n invalidate(next, nextDevice) {\n generation = next;\n device = nextDevice;\n // The upload texture belonged to the dead device. Dropping it and arming\n // the dirty flag is the whole recovery: the next acquire allocates on the\n // new device and re-copies, through the same path a content change takes.\n texture?.destroy();\n texture = undefined;\n dirty = true;\n },\n\n resize(width, height) {\n const changed = size.width !== width || size.height !== height;\n trackSize(size, width, height);\n if (changed) dirty = true;\n },\n\n destroy() {\n texture?.destroy();\n texture = undefined;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// video — importExternalTexture\n// ---------------------------------------------------------------------------\n\nexport interface VideoProviderOptions {\n readonly id: string;\n readonly device: BackdropDevice;\n /**\n * Either a live element the browser keeps frames for, or a callback producing a\n * `VideoFrame` this provider then owns and closes. The two are separate because\n * their ownership rules are opposite — see the module note.\n */\n readonly source:\n | { readonly kind: \"element\"; readonly element: HTMLVideoElement }\n | { readonly kind: \"frames\"; readonly next: () => VideoFrame | undefined };\n readonly colorSpace?: BackdropColorSpace;\n /** The device generation this provider is being built under. See `BackdropProvider.generation`. */\n readonly generation?: number;\n}\n\nexport function createVideoProvider(options: VideoProviderOptions): BackdropProvider {\n let device = options.device;\n const size = { epoch: 0, width: 0, height: 0 };\n let ownedFrame: VideoFrame | undefined;\n let acquired = false;\n let generation = options.generation ?? 0;\n\n return {\n id: options.id,\n kind: \"video\",\n\n get generation() {\n return generation;\n },\n\n isDirty() {\n // `importExternalTexture` handles expire at task end, so a video is dirty\n // on every frame that samples it. That is a WebGPU semantic, not a policy.\n return true;\n },\n\n acquire() {\n if (acquired) {\n throw rendererError(\n \"frame-protocol\",\n `Backdrop \"${options.id}\" was acquired twice without a release. X3 pairs one acquire per frame with one release after submit.`,\n options.id,\n );\n }\n\n let source: HTMLVideoElement | VideoFrame;\n if (options.source.kind === \"element\") {\n const element = options.source.element;\n if (element.readyState < 2 || element.videoWidth === 0) {\n throw rendererError(\n \"source-unavailable\",\n `Backdrop \"${options.id}\" is a video with no decoded frame yet (readyState ${element.readyState}). Wait for \"loadeddata\" before registering it, or let the group render without a backdrop until it arrives.`,\n options.id,\n );\n }\n trackSize(size, element.videoWidth, element.videoHeight);\n source = element;\n } else {\n const frame = options.source.next();\n if (frame === undefined) {\n throw rendererError(\n \"source-unavailable\",\n `Backdrop \"${options.id}\" produced no VideoFrame for this frame.`,\n options.id,\n );\n }\n ownedFrame = frame;\n trackSize(size, frame.displayWidth, frame.displayHeight);\n source = frame;\n }\n\n let texture: GPUExternalTexture;\n try {\n texture = device.importExternalTexture({\n label: `vitrea:backdrop:${options.id}:external`,\n source,\n colorSpace: \"srgb\",\n });\n } catch (error) {\n // The frame is already this provider's to close, and a throw here leaves\n // `acquired` false — so no release is queued and the next acquire would\n // overwrite `ownedFrame`, leaking one decoder buffer per failure until\n // playback stalls. Closing before the rethrow keeps the ownership rule\n // (\"close ownership held by the provider\") true on the failure path too.\n ownedFrame?.close();\n ownedFrame = undefined;\n throw error;\n }\n acquired = true;\n\n return {\n sourceId: options.id,\n binding: { kind: \"external\", texture },\n width: size.width,\n height: size.height,\n sizeEpoch: size.epoch,\n colorSpace: options.colorSpace ?? \"srgb\",\n // X3: imported video arrives UNPREMULTIPLIED.\n alphaMode: \"unpremultiplied\",\n encoded: true,\n };\n },\n\n release() {\n acquired = false;\n // After submit, and only for a frame this provider owns.\n ownedFrame?.close();\n ownedFrame = undefined;\n },\n\n markImported() {\n // A video is dirty again immediately; nothing to record.\n },\n\n invalidate(next, nextDevice) {\n generation = next;\n device = nextDevice;\n // An external texture from the dead device is already gone — imports expire\n // at task end — so all that is owed here is the frame this provider holds\n // and the acquire/release pairing, which the loss interrupted mid-flight.\n ownedFrame?.close();\n ownedFrame = undefined;\n acquired = false;\n },\n\n destroy() {\n ownedFrame?.close();\n ownedFrame = undefined;\n acquired = false;\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// gradient — procedural, generated once on the CPU\n// ---------------------------------------------------------------------------\n\nexport interface GradientStop {\n /** 0..1 along the gradient axis. */\n readonly offset: number;\n /** sRGB-encoded 0..1, plus alpha. */\n readonly color: readonly [number, number, number, number];\n}\n\nexport interface GradientProviderOptions {\n readonly id: string;\n readonly device: BackdropDevice;\n readonly stops: readonly GradientStop[];\n /** Gradient direction in the source's own uv space. Defaults to top-to-bottom. */\n readonly direction?: readonly [number, number];\n readonly width?: number;\n readonly height?: number;\n /** The device generation this provider is being built under. See `BackdropProvider.generation`. */\n readonly generation?: number;\n}\n\n/**\n * Generated on the CPU and uploaded once, rather than rendered with a pipeline of\n * its own.\n *\n * A procedural gradient is static by definition, so it rebuilds nothing after the\n * first frame and a whole render pipeline for it would be dead weight in the\n * pipeline cache. Interpolation is in **linear light** and the result is\n * re-encoded, because a gradient interpolated in sRGB has a visible dark band\n * through its middle — the one place where doing the maths in the wrong space is\n * obvious to the eye rather than to a metric.\n */\nexport function createGradientProvider(options: GradientProviderOptions): BackdropProvider {\n const width = Math.max(1, options.width ?? 64);\n const height = Math.max(1, options.height ?? 64);\n const direction = options.direction ?? [0, 1];\n const stops = [...options.stops].sort((a, b) => a.offset - b.offset);\n\n if (stops.length === 0) {\n throw rendererError(\n \"source-unavailable\",\n `Gradient backdrop \"${options.id}\" has no stops.`,\n options.id,\n );\n }\n\n const texels = new Uint8Array(width * height * 4);\n const axisLength = Math.hypot(direction[0], direction[1]) || 1;\n const ax = direction[0] / axisLength;\n const ay = direction[1] / axisLength;\n\n const sample = (t: number): readonly [number, number, number, number] => {\n const clamped = Math.min(1, Math.max(0, t));\n let lower = stops[0] as GradientStop;\n let upper = stops[stops.length - 1] as GradientStop;\n for (let i = 0; i < stops.length - 1; i += 1) {\n const a = stops[i] as GradientStop;\n const b = stops[i + 1] as GradientStop;\n if (clamped >= a.offset && clamped <= b.offset) {\n lower = a;\n upper = b;\n break;\n }\n }\n const span = upper.offset - lower.offset;\n const local = span <= 0 ? 0 : (clamped - lower.offset) / span;\n const mix = (from: number, to: number): number => from + (to - from) * local;\n // Colour channels are decoded, mixed, and re-encoded; alpha is already\n // linear and is mixed as-is. Mixing the encoded values instead puts a\n // visible dark band through the middle of every gradient — the one place\n // where working in the wrong space is obvious to the eye rather than to a\n // metric.\n const channel = (index: 0 | 1 | 2): number =>\n linearToSrgbChannel(\n mix(srgbToLinearChannel(lower.color[index]), srgbToLinearChannel(upper.color[index])),\n );\n return [channel(0), channel(1), channel(2), mix(lower.color[3], upper.color[3])];\n };\n\n for (let y = 0; y < height; y += 1) {\n for (let x = 0; x < width; x += 1) {\n const u = width === 1 ? 0 : x / (width - 1);\n const v = height === 1 ? 0 : y / (height - 1);\n // Project onto the axis and rescale so the endpoints of the projected\n // range land on stops 0 and 1 whatever the direction.\n const t = (u * ax + v * ay + Math.max(0, -ax) + Math.max(0, -ay)) / (Math.abs(ax) + Math.abs(ay) || 1);\n const [r, g, b, a] = sample(t);\n const index = (y * width + x) * 4;\n texels[index + 0] = Math.round(Math.min(1, Math.max(0, r)) * 255);\n texels[index + 1] = Math.round(Math.min(1, Math.max(0, g)) * 255);\n texels[index + 2] = Math.round(Math.min(1, Math.max(0, b)) * 255);\n texels[index + 3] = Math.round(Math.min(1, Math.max(0, a)) * 255);\n }\n }\n\n let texture: GPUTexture | undefined;\n let uploaded = false;\n let device = options.device;\n let generation = options.generation ?? 0;\n\n return {\n id: options.id,\n kind: \"gradient\",\n\n get generation() {\n return generation;\n },\n\n isDirty() {\n return !uploaded;\n },\n\n acquire() {\n texture ??= device.createTexture({\n label: `vitrea:backdrop:${options.id}:gradient`,\n size: { width, height, depthOrArrayLayers: 1 },\n format: \"rgba8unorm\",\n usage: copyUsage(),\n });\n if (!uploaded) {\n device.queue.writeTexture(\n { texture },\n texels,\n { bytesPerRow: width * 4, rowsPerImage: height },\n { width, height },\n );\n }\n return {\n sourceId: options.id,\n binding: { kind: \"sampled\", view: texture.createView() },\n width,\n height,\n sizeEpoch: 0,\n colorSpace: \"srgb\",\n alphaMode: \"premultiplied\",\n encoded: true,\n };\n },\n\n release() {\n // Nothing acquired that needs releasing.\n },\n\n markImported() {\n uploaded = true;\n },\n\n invalidate(next, nextDevice) {\n generation = next;\n device = nextDevice;\n // A gradient is static, so `uploaded` is the only thing standing between it\n // and a silent black backdrop after a loss: without the reset the next\n // acquire hands out a view of a texture the dead device made and never\n // writes the texels again. The pixels themselves are CPU-side and survive.\n texture?.destroy();\n texture = undefined;\n uploaded = false;\n },\n\n destroy() {\n texture?.destroy();\n texture = undefined;\n uploaded = false;\n },\n };\n}\n\n/** Two-stop convenience, in linear light, for tests and for the golden scenes. */\nexport function linearGradientStops(\n from: readonly [number, number, number],\n to: readonly [number, number, number],\n): readonly GradientStop[] {\n const encode = (c: readonly [number, number, number]): readonly [number, number, number, number] =>\n [linearToSrgbChannel(c[0]), linearToSrgbChannel(c[1]), linearToSrgbChannel(c[2]), 1];\n return [\n { offset: 0, color: encode(from) },\n { offset: 1, color: encode(to) },\n ];\n}\n\n// ---------------------------------------------------------------------------\n// app-texture-view — validated at registration\n// ---------------------------------------------------------------------------\n\nexport interface AppTextureProviderOptions {\n readonly id: string;\n readonly device: BackdropDevice;\n /**\n * The app's texture. Required rather than a bare view because a\n * `GPUTextureView` exposes none of its own properties, so a view-only contract\n * could not be validated at all — and X3 requires validation at registration.\n */\n readonly texture: GPUTexture;\n /** Optional pre-made view. One is created per acquire when absent. */\n readonly view?: GPUTextureView;\n readonly colorSpace?: BackdropColorSpace;\n readonly alphaMode?: BackdropAlphaMode;\n /** Whether the app's values are sRGB-encoded. A float target is usually linear. */\n readonly encoded?: boolean;\n /**\n * The device generation the app's texture belongs to. See\n * `BackdropProvider.generation` — this is the number `acquire` refuses against\n * once the renderer has moved on to a later device.\n */\n readonly generation?: number;\n}\n\n/**\n * Validate an app-supplied texture against the sampling path's requirements.\n *\n * Exported separately so a host can check before it registers, and so the checks\n * are testable without a device — every one of them reads only the texture's own\n * declared properties.\n */\nexport function validateAppTexture(\n texture: Pick<GPUTexture, \"width\" | \"height\" | \"format\" | \"usage\" | \"dimension\" | \"depthOrArrayLayers\">,\n limits: Pick<GPUSupportedLimits, \"maxTextureDimension2D\">,\n subject: string,\n): void {\n if (texture.dimension !== \"2d\") {\n throw rendererError(\n \"texture-dimension\",\n `Backdrop \"${subject}\" supplied a ${texture.dimension} texture. The sampling path binds a 2d texture; register a 2d texture or a 2d view of one slice.`,\n subject,\n );\n }\n if (texture.depthOrArrayLayers !== 1) {\n throw rendererError(\n \"texture-dimension\",\n `Backdrop \"${subject}\" supplied a texture with ${texture.depthOrArrayLayers} array layers. Bind a single-layer view.`,\n subject,\n );\n }\n if ((texture.usage & GPUTextureUsage.TEXTURE_BINDING) === 0) {\n throw rendererError(\n \"texture-usage\",\n `Backdrop \"${subject}\" supplied a texture without GPUTextureUsage.TEXTURE_BINDING, so it cannot be sampled. Add TEXTURE_BINDING to the texture's usage when you create it.`,\n subject,\n );\n }\n if (!SUPPORTED_APP_TEXTURE_FORMATS.includes(texture.format)) {\n throw rendererError(\n \"texture-format\",\n `Backdrop \"${subject}\" supplied a \"${texture.format}\" texture. Supported formats are ${SUPPORTED_APP_TEXTURE_FORMATS.join(\", \")}.`,\n subject,\n );\n }\n if (texture.width <= 0 || texture.height <= 0) {\n throw rendererError(\n \"texture-size\",\n `Backdrop \"${subject}\" supplied a ${texture.width}×${texture.height} texture.`,\n subject,\n );\n }\n const max = limits.maxTextureDimension2D;\n if (texture.width > max || texture.height > max) {\n throw rendererError(\n \"texture-size\",\n `Backdrop \"${subject}\" supplied a ${texture.width}×${texture.height} texture, past this adapter's maxTextureDimension2D of ${max}.`,\n subject,\n );\n }\n}\n\nexport function createAppTextureProvider(options: AppTextureProviderOptions): BackdropProvider {\n // Registration-time validation. Throwing here — not at draw time — is the whole\n // point of X3's sentence about app-supplied views.\n validateAppTexture(options.texture, options.device.limits, options.id);\n\n const encoded = options.encoded ?? !options.texture.format.includes(\"float\");\n const size = {\n epoch: 0,\n width: options.texture.width,\n height: options.texture.height,\n };\n\n const builtGeneration = options.generation ?? 0;\n let generation = builtGeneration;\n\n return {\n id: options.id,\n kind: \"app-texture-view\",\n\n get generation() {\n return generation;\n },\n\n isDirty() {\n // The app may redraw into its own texture at any time and the renderer has\n // no way to know. Assuming dirty is the honest default; an app that knows\n // better re-registers with a static source.\n return true;\n },\n\n acquire() {\n // One integer compare, which is the only check available: a\n // `GPUTextureView` carries no evidence of the device that made it, and\n // binding one from a superseded device produces no error the renderer can\n // see — only a pass that quietly renders nothing. X3's \"never discovered at\n // draw time\" cuts the other way here, so the refusal is loud and names the\n // handshake that clears it.\n if (generation !== builtGeneration) {\n throw rendererError(\n \"source-unavailable\",\n `Backdrop \"${options.id}\" wraps a GPUTexture from device generation ${builtGeneration}, and the renderer is now on generation ${generation}. WebGPU has no cross-device texture sharing: unregister this source and register the replacement texture the app made on the new device.`,\n options.id,\n );\n }\n return {\n sourceId: options.id,\n binding: {\n kind: \"sampled\",\n view: options.view ?? options.texture.createView(),\n },\n width: size.width,\n height: size.height,\n sizeEpoch: size.epoch,\n colorSpace: options.colorSpace ?? \"srgb\",\n alphaMode: options.alphaMode ?? \"premultiplied\",\n encoded,\n };\n },\n\n release() {\n // The app owns the texture; the renderer releases nothing.\n },\n\n markImported() {\n // Nothing to record.\n },\n\n invalidate(next) {\n // Nothing to drop and nothing to re-point: the texture is the app's, made\n // on a device this provider does not own. Recording the generation is what\n // turns the next acquire into a refusal.\n generation = next;\n },\n\n destroy() {\n // The app owns the texture; destroying it here would be taking ownership we\n // were never given.\n },\n };\n}\n","/**\n * Where a backdrop texture sits on the plane, and what that makes of a CSS px.\n *\n * The optics pass samples the backdrop through one uv transform on\n * viewport-normalised coordinates — `uv = viewport01 · scale + offset` — and\n * the pyramid converts the material's CSS-px σ into source texels once, at build.\n * Both numbers are functions of the same thing: the rectangle of the viewport the\n * texture's pixels actually occupy. This module is the one place that rectangle\n * turns into either.\n *\n * ## Placed\n *\n * A texture handed over from a DOM element — an `<img>`, a `<canvas>`, a\n * `<video>` — has a box the host measures every read phase, in CSS px relative\n * to the viewport, and that box IS the placement: a 320 px raster in the corner\n * of a 1440 px page maps the 320 px, not the page. The source's own extent is\n * still what the pyramid is built from; the placement only says where on the\n * plane its texels land, so one texel is `placement.width / sourceWidth` CSS px.\n *\n * Outside the placement the sampler clamps to the edge. A surface hanging past\n * the texture's box reads the nearest edge texel rather than nothing; the\n * unsampled layer (W11a) is not applied to partial overlap in this cut.\n *\n * ## Cover\n *\n * A source with no placement — an `ImageBitmap`, an `OffscreenCanvas`, an\n * element not in the document, or a renderer driven without a host at all —\n * keeps the original rule: the backdrop fills the viewport and the overflow is\n * cropped symmetrically. Every golden and every calibration capture was taken\n * with the texture the size of the stage, where the two rules coincide exactly;\n * the demo's reference panel is where they came apart (claims §5.47).\n */\n\nimport type { Rect } from \"./render-model\";\n\n/** `[scaleX, scaleY, offsetX, offsetY]` on viewport-normalised coordinates. */\nexport type BackdropFit = readonly [number, number, number, number];\n\n/** A backdrop source's box on the plane, in CSS px relative to the viewport. */\nexport type BackdropPlacement = Rect;\n\nexport const IDENTITY_FIT: BackdropFit = [1, 1, 0, 0];\n\n/** A placement with a zero or negative side places nothing and falls back to cover. */\nexport function isUsablePlacement(placement: BackdropPlacement | undefined): placement is Rect {\n return (\n placement !== undefined &&\n Number.isFinite(placement.x) &&\n Number.isFinite(placement.y) &&\n placement.width > 0 &&\n placement.height > 0\n );\n}\n\n/**\n * Cover fit: the backdrop fills the viewport and the overflow is cropped\n * symmetrically, aspect preserved.\n */\nexport function coverFit(\n sourceWidth: number,\n sourceHeight: number,\n viewportWidthCss: number,\n viewportHeightCss: number,\n): BackdropFit {\n const viewportAspect = viewportHeightCss > 0 ? viewportWidthCss / viewportHeightCss : 1;\n const sourceAspect = sourceHeight > 0 ? sourceWidth / sourceHeight : 1;\n if (sourceAspect > viewportAspect) {\n const scaleX = viewportAspect / sourceAspect;\n return [scaleX, 1, (1 - scaleX) / 2, 0];\n }\n const scaleY = sourceAspect / viewportAspect;\n return [1, scaleY, 0, (1 - scaleY) / 2];\n}\n\n/**\n * Placed fit: `uv = (viewport01 · viewportCss − placement.xy) / placement.wh`,\n * so a viewport pixel inside the placement lands on the texel under it and one\n * outside lands beyond [0, 1], where the sampler clamps.\n */\nexport function placementFit(\n placement: BackdropPlacement,\n viewportWidthCss: number,\n viewportHeightCss: number,\n): BackdropFit {\n return [\n viewportWidthCss / placement.width,\n viewportHeightCss / placement.height,\n -placement.x / placement.width,\n -placement.y / placement.height,\n ];\n}\n\nexport function backdropFit(\n sourceWidth: number,\n sourceHeight: number,\n placement: BackdropPlacement | undefined,\n viewportWidthCss: number,\n viewportHeightCss: number,\n): BackdropFit {\n return isUsablePlacement(placement)\n ? placementFit(placement, viewportWidthCss, viewportHeightCss)\n : coverFit(sourceWidth, sourceHeight, viewportWidthCss, viewportHeightCss);\n}\n\n/**\n * Source texels per CSS px — the factor a CSS-px σ or displacement is multiplied\n * by to land in the source's own pixels.\n *\n * Placed: the width alone decides. A source drawn into a box of a different\n * aspect than its own (an `<img>` under `object-fit`, a canvas stretched by CSS)\n * has two densities, and the body blur is one isotropic σ; the wider axis is the\n * one a reader sees the frost across, so it is the one honoured. Cover: the axis\n * the crop keeps — the larger ratio — as it always was.\n */\nexport function texelsPerCssPx(\n sourceWidth: number,\n sourceHeight: number,\n placement: BackdropPlacement | undefined,\n viewportWidthCss: number,\n viewportHeightCss: number,\n): number {\n if (isUsablePlacement(placement)) {\n return sourceWidth > 0 ? sourceWidth / placement.width : 1;\n }\n return viewportWidthCss > 0 && viewportHeightCss > 0\n ? Math.max(sourceWidth / viewportWidthCss, sourceHeight / viewportHeightCss)\n : 1;\n}\n\n/** Two placements that would produce the same fit and density. */\nexport function samePlacement(\n a: BackdropPlacement | undefined,\n b: BackdropPlacement | undefined,\n): boolean {\n if (a === undefined || b === undefined) return a === b;\n return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;\n}\n","/**\n * Device ownership, loss teardown, and rebuild (§GPU device ownership).\n *\n * `platform-web` owns the *browser* half of the story — is there an adapter, get\n * a device, notice when it goes away. This module owns the *resource* half: what\n * has to be thrown away when a device dies, when it is safe to build again, and\n * what core's capability inputs should read while that is in flight.\n *\n * ## The two ownership modes, and why they are not symmetric\n *\n * - **vitrea-owned** — this module can re-request a device by itself, so loss is\n * a transient it recovers from: tear down, re-request, re-attach, rebuild.\n * Every backdrop source is re-imported on the next frame because loss marks\n * them all dirty, which routes recovery through the same\n * one-rebuild-per-dirty-source-per-frame path a content change takes rather\n * than through a special case.\n * - **app-owned** — the app owns the resources that would have to be\n * re-registered, so this module reports the loss, raises\n * `replacementPending`, and **waits**. Groups stay demoted until\n * `replaceDevice` arrives and the re-registration handshake completes. Inventing\n * a device the app did not give us would break the one guarantee app-ownership\n * exists for: that every texture the renderer samples came from the app's own\n * device, because WebGPU has no cross-device sharing.\n *\n * `info.reason === \"destroyed\"` is our own teardown and is not recovered from —\n * re-requesting there would resurrect a renderer the host just destroyed.\n *\n * ## Generations\n *\n * Every attach bumps a generation counter, and every GPU object this package\n * holds is tagged with the generation it was made under. A resource from a lost\n * device is unusable forever, and the failure mode is silent — bindings simply\n * produce nothing — so \"is this from the current device\" has to be a cheap\n * integer comparison somewhere. It is here.\n */\n\nimport { rendererError } from \"./errors\";\n\n/**\n * Structurally identical to `vitrea`'s `WebGPUAvailability` (X2's K1\n * amendment, Decision Log #21c). Declared here rather than imported because this\n * package sits *below* core in the dependency graph — core reaches the renderer\n * through a dynamic import, so an import back would close a cycle. A test pins\n * the two unions to the same members.\n */\nexport type WebGPUAvailability = \"not-requested\" | \"unavailable\" | \"available\";\n\nexport type DeviceOwnership = \"vitrea\" | \"app\";\n\nexport interface RendererDeviceStatus {\n /** Feeds core's `PlatformProbe.webgpu` unchanged. */\n readonly webgpu: WebGPUAvailability;\n readonly deviceHealth: \"ok\" | \"lost\";\n readonly ownership: DeviceOwnership;\n readonly device: GPUDevice | undefined;\n /** Bumped on every attach. Tags every resource built under it. */\n readonly generation: number;\n /** True while an app-owned device is lost and no replacement has arrived. */\n readonly replacementPending: boolean;\n /** Why there is no device, when there is a reason worth reporting. */\n readonly unavailableReason?: \"no-adapter\" | \"device-request-failed\" | \"lost\";\n}\n\n/** The capability facts a host folds into core's `PlatformProbe`. */\nexport interface DeviceCapabilityInput {\n readonly webgpu: WebGPUAvailability;\n readonly deviceHealth: \"ok\" | \"lost\";\n}\n\n/** Run on loss and on teardown. Must be idempotent and must not touch the device. */\nexport type TeardownHook = () => void;\n\nexport interface DeviceHostOptions {\n readonly onStatusChange?: (status: RendererDeviceStatus) => void;\n /** Raised when an app-owned device is lost and only the app can replace it. */\n readonly onReplacementNeeded?: () => void;\n /**\n * Re-request a vitrea-owned device. Absent means \"no automatic recovery\",\n * which is the honest configuration when the host owns the adapter handshake.\n */\n readonly reacquire?: () => Promise<GPUDevice | undefined>;\n}\n\nexport interface DeviceHost {\n readonly status: RendererDeviceStatus;\n readonly capabilityInput: DeviceCapabilityInput;\n /** The current device, or a thrown `device-unavailable` if there is none. */\n requireDevice(): GPUDevice;\n attach(device: GPUDevice, ownership: DeviceOwnership): void;\n /** Hand in a replacement for a lost device. Also clears `replacementPending`. */\n replaceDevice(device: GPUDevice): void;\n /**\n * Record that WebGPU *was* asked for and could not be had. Moves `webgpu` off\n * `\"not-requested\"`, which is the difference K1 exists to preserve.\n */\n markUnavailable(reason: \"no-adapter\" | \"device-request-failed\"): void;\n addTeardownHook(hook: TeardownHook): () => void;\n /** Awaits the in-flight recovery, if any. Test and shutdown seam. */\n settled(): Promise<void>;\n destroy(): void;\n}\n\nexport function createDeviceHost(options: DeviceHostOptions = {}): DeviceHost {\n let status: RendererDeviceStatus = {\n webgpu: \"not-requested\",\n deviceHealth: \"ok\",\n ownership: \"vitrea\",\n device: undefined,\n generation: 0,\n replacementPending: false,\n };\n const hooks = new Set<TeardownHook>();\n let destroyed = false;\n let recovery: Promise<void> | undefined;\n\n const publish = (next: RendererDeviceStatus): void => {\n status = next;\n if (!destroyed) options.onStatusChange?.(status);\n };\n\n const runTeardown = (): void => {\n // A hook that throws must not stop the others: half-torn-down state after a\n // device loss is the one condition from which nothing can recover.\n for (const hook of [...hooks]) {\n try {\n hook();\n } catch {\n // Deliberately swallowed — see above.\n }\n }\n };\n\n const watchLoss = (device: GPUDevice, generation: number): void => {\n void device.lost.then((info) => {\n // A loss from a superseded device is not this device's loss.\n if (destroyed || status.generation !== generation) return;\n\n runTeardown();\n const ownership = status.ownership;\n publish({\n webgpu: \"available\",\n deviceHealth: \"lost\",\n ownership,\n device: undefined,\n generation,\n replacementPending: ownership === \"app\",\n unavailableReason: \"lost\",\n });\n\n if (info.reason === \"destroyed\") return;\n\n if (ownership === \"app\") {\n options.onReplacementNeeded?.();\n return;\n }\n\n const reacquire = options.reacquire;\n if (reacquire === undefined) return;\n recovery = (async () => {\n const replacement = await reacquire();\n // A `destroy()` that lands while the re-request is in flight still has to\n // account for what the re-request produced. Returning without destroying\n // it leaks a whole GPUDevice on the one path where this module IS the\n // owner — the host has no handle to it, because it never learned the\n // reacquire had finished.\n if (destroyed) {\n replacement?.destroy();\n return;\n }\n if (replacement === undefined) return;\n attach(replacement, \"vitrea\");\n })();\n });\n };\n\n function attach(device: GPUDevice, ownership: DeviceOwnership): void {\n const generation = status.generation + 1;\n publish({\n webgpu: \"available\",\n deviceHealth: \"ok\",\n ownership,\n device,\n generation,\n replacementPending: false,\n });\n watchLoss(device, generation);\n }\n\n return {\n get status() {\n return status;\n },\n\n get capabilityInput() {\n return { webgpu: status.webgpu, deviceHealth: status.deviceHealth };\n },\n\n requireDevice() {\n const { device } = status;\n if (device === undefined) {\n throw rendererError(\n \"device-unavailable\",\n status.replacementPending\n ? \"The app-owned GPUDevice was lost and no replacement has been handed in yet. Call replaceDevice() and re-register the app's texture views before drawing again.\"\n : \"No GPUDevice is attached. Attach one (platform-web's WebGPU lifecycle produces it) before building resources or drawing.\",\n );\n }\n return device;\n },\n\n attach,\n\n replaceDevice(device) {\n attach(device, status.ownership);\n },\n\n markUnavailable(reason) {\n publish({\n ...status,\n webgpu: \"unavailable\",\n device: undefined,\n unavailableReason: reason,\n });\n },\n\n addTeardownHook(hook) {\n hooks.add(hook);\n return () => hooks.delete(hook);\n },\n\n async settled() {\n await recovery;\n },\n\n destroy() {\n destroyed = true;\n runTeardown();\n // Only a device this renderer owns is ours to destroy.\n if (status.ownership === \"vitrea\") status.device?.destroy();\n hooks.clear();\n status = { ...status, device: undefined };\n },\n };\n}\n","/**\n * The governor's knobs.\n *\n * §Performance envelope: \"The governor degrades **within** a tier first\n * (refraction resolution, adaptation cadence, edge analysis) and switches tiers\n * only with long hysteresis and cooldown.\" Decision Log #19 adds that intra-tier\n * degradation is **not a state change** — a group under `degrade-in-tier`\n * pressure keeps `activeRenderer: \"webgpu\"` and its whole resolved state.\n *\n * So the split is: **the policy lives in core, the knobs live here.** This module\n * exposes what can be turned and publishes a suggested ladder as *data*; it never\n * decides to turn anything, never reads a clock, and never applies hysteresis.\n * A governor that lived in the renderer would be a governor that could not see\n * the scene it is governing.\n *\n * ## The three knobs, weakest cost first\n *\n * 1. **`fieldFamily`** — `rsupn` → `rsup`. S2 priced this at 29% of the field's\n * cost for a bound that degrades from 0.170 px / 2.91° to 0.574 px / 4.26°.\n * It is the *first* step because it is one uniform and one pipeline: no\n * resolution change, so nothing resamples and nothing shimmers as it engages.\n * **Conditional on the f32 cross-check** (Decision Log #20) — and the check\n * has now been run, so the condition is met. See `FAMILY_C_CROSS_CHECK`.\n * 2. **`refractionResolutionScale`** — the group's **field** targets are\n * rasterised at a fraction of device resolution, and the optics and highlight\n * passes filter them instead of indexing them (`passes.ts`, and the\n * `fieldUpsampled` flag both shaders branch on). Quadratic saving on the pass\n * that evaluates the pseudo-SDF union per pixel per member, and the most\n * visible step, so it comes second.\n *\n * What it does **not** yet do is shrink the optics and highlight passes\n * themselves: those still render at full device resolution into the plane\n * canvases, because rendering them smaller means an offscreen target and a\n * resolve pass rather than a change of extent. So rungs 2 and 3 deliver the\n * field's quadratic saving and the cadence saving, not the full quadratic\n * saving on both heavy passes. Recorded here rather than implied, because a\n * ladder whose rungs are priced for savings they do not deliver is a ladder\n * core's policy will walk too far down.\n * 3. **`adaptationCadenceHz`** — how often analysis is reduced and read back.\n * Cheapest of the three in visual terms because the values it feeds are\n * already low-passed over hundreds of milliseconds; dropping the cadence\n * mostly changes how quickly a scroll's new backdrop is noticed.\n */\n\nexport type FieldFamily = \"rsupn\" | \"rsup\";\n\nexport interface GovernorKnobs {\n /** Which pseudo-SDF family the field pass compiles. */\n readonly fieldFamily: FieldFamily;\n /**\n * Device-resolution fraction the group's field targets are rasterised at,\n * 0 < s <= 1. The optics and highlight passes upsample what they read. See the\n * module note for what this does and does not save.\n */\n readonly refractionResolutionScale: number;\n /** Analysis reduction + readback rate. 0 disables adaptation entirely. */\n readonly adaptationCadenceHz: number;\n}\n\n/**\n * Full fidelity. `adaptationCadenceHz` is core's advisory 15 Hz readback ceiling\n * (Decision Log #19) — the analysis pass has no reason to run faster than the\n * values it produces can be consumed.\n */\nexport const NOMINAL_GOVERNOR: GovernorKnobs = {\n fieldFamily: \"rsupn\",\n refractionResolutionScale: 1,\n adaptationCadenceHz: 15,\n};\n\n/**\n * The suggested intra-tier ladder, as data for core's policy to walk. Each step\n * is cumulative on the one before it, weakest visual cost first.\n */\nexport const GOVERNOR_LADDER: readonly GovernorKnobs[] = [\n NOMINAL_GOVERNOR,\n { fieldFamily: \"rsup\", refractionResolutionScale: 1, adaptationCadenceHz: 15 },\n { fieldFamily: \"rsup\", refractionResolutionScale: 0.75, adaptationCadenceHz: 7.5 },\n { fieldFamily: \"rsup\", refractionResolutionScale: 0.5, adaptationCadenceHz: 4 },\n];\n\n/**\n * Decision Log #20's condition, and its answer.\n *\n * The spec makes family C's shipping \"conditional on C6 running the f32\n * cross-check on its WGSL\". C6 ran it, twice and independently:\n *\n * - **On hardware** (`e2e/gpu/cross-check.spec.ts`, apple/metal-3): the shipped\n * `sd_rsup` kernel against `@vitrea/geometry`'s f64 `rsupField` over 5535\n * points on and around three shapes' contours — **3.042e-5 px max, 0.0053% of\n * the declared 0.574 px bound.** The same run measured family D at 4.073e-5 px\n * / 0.0240%, reproducing S2's own 4.08e-5 / 0.024% on that adapter class,\n * which is what makes the two runs comparable at all.\n * - **In the unit suite** (`test/f32-cross-check.test.ts`): the same arithmetic\n * emulated in f32 through `Math.fround`, so the answer exists on a machine\n * with no adapter. 3.523e-5 px, the same order.\n *\n * So the gate is open by default, and the option below is the opt-out rather than\n * the opt-in. What keeps that honest is that both checks run in CI and that\n * `@vitrea/geometry` fingerprints the kernel strings: editing `sd_rsup` trips the\n * fingerprint test, which says in as many words to re-run the cross-check.\n */\nexport const FAMILY_C_CROSS_CHECK = {\n ran: true,\n adapter: \"apple/metal-3\",\n points: 5535,\n maxAbsDiffPx: 3.042e-5,\n boundPx: 0.574,\n} as const;\n\nexport interface GovernorOptions {\n /**\n * Whether family C's WGSL has been through the f32 cross-check (Decision Log\n * #20). Defaults to `FAMILY_C_CROSS_CHECK.ran` — see above. Pass `false` to\n * hold the governor to family D regardless.\n */\n readonly familyCVerified?: boolean;\n readonly onChange?: (knobs: GovernorKnobs) => void;\n}\n\nexport interface Governor {\n readonly knobs: GovernorKnobs;\n /** True when `fieldFamily: \"rsup\"` is permitted to engage. */\n readonly familyCVerified: boolean;\n set(patch: Partial<GovernorKnobs>): GovernorKnobs;\n /** Move to a rung of the suggested ladder. Out-of-range clamps to the ends. */\n setLevel(level: number): GovernorKnobs;\n reset(): GovernorKnobs;\n /** Record that the cross-check passed, unlocking family C. */\n recordFamilyCVerified(): void;\n}\n\nconst clampScale = (s: number): number => Math.min(1, Math.max(0.125, s));\n\nexport function createGovernor(options: GovernorOptions = {}): Governor {\n let knobs = NOMINAL_GOVERNOR;\n let verified = options.familyCVerified ?? FAMILY_C_CROSS_CHECK.ran;\n\n const apply = (next: GovernorKnobs): GovernorKnobs => {\n const family: FieldFamily = next.fieldFamily === \"rsup\" && !verified ? \"rsupn\" : next.fieldFamily;\n knobs = {\n fieldFamily: family,\n refractionResolutionScale: clampScale(next.refractionResolutionScale),\n adaptationCadenceHz: Math.max(0, next.adaptationCadenceHz),\n };\n options.onChange?.(knobs);\n return knobs;\n };\n\n return {\n get knobs() {\n return knobs;\n },\n\n get familyCVerified() {\n return verified;\n },\n\n set(patch) {\n return apply({ ...knobs, ...patch });\n },\n\n setLevel(level) {\n const index = Math.min(GOVERNOR_LADDER.length - 1, Math.max(0, Math.round(level)));\n return apply(GOVERNOR_LADDER[index] as GovernorKnobs);\n },\n\n reset() {\n return apply(NOMINAL_GOVERNOR);\n },\n\n recordFamilyCVerified() {\n verified = true;\n },\n };\n}\n","/**\n * Shader-module and pipeline caches.\n *\n * Pipeline creation is the single most expensive thing a WebGPU renderer can do\n * per frame, and this renderer's pipeline set is small and fixed: two field\n * families, two import kinds, the chain, the analysis reduction, optics,\n * highlight. So the cache is a plain memo keyed by a descriptor string, and the\n * only interesting part is what goes into that key.\n *\n * Two rules about keys, both learned the same way — a cache that returns a\n * pipeline compiled against a different target format fails at draw time with an\n * error that names neither the format nor the cache:\n *\n * - **Every property that changes the compiled artefact is in the key.** Target\n * format, blend state, and the entry points, not just the shader name.\n * - **Nothing else is.** Uniform *values* never are; they travel in buffers. A\n * key that grew a tint colour would make the cache a leak.\n *\n * Like the texture pool, this is written over the narrow slice of `GPUDevice` it\n * uses, so eviction and key discipline are testable without an adapter.\n */\n\n/** The slice of `GPUDevice` the caches need. `GPUDevice` satisfies it as-is. */\nexport interface PipelineFactory {\n createShaderModule(descriptor: GPUShaderModuleDescriptor): GPUShaderModule;\n createRenderPipeline(descriptor: GPURenderPipelineDescriptor): GPURenderPipeline;\n createComputePipeline(descriptor: GPUComputePipelineDescriptor): GPUComputePipeline;\n}\n\nexport interface PipelineCacheStats {\n readonly modules: number;\n readonly renderPipelines: number;\n readonly computePipelines: number;\n readonly hits: number;\n readonly misses: number;\n}\n\nexport interface PipelineCache {\n readonly stats: PipelineCacheStats;\n module(key: string, source: () => string): GPUShaderModule;\n renderPipeline(key: string, describe: () => GPURenderPipelineDescriptor): GPURenderPipeline;\n computePipeline(key: string, describe: () => GPUComputePipelineDescriptor): GPUComputePipeline;\n clear(): void;\n}\n\nexport function createPipelineCache(factory: PipelineFactory): PipelineCache {\n const modules = new Map<string, GPUShaderModule>();\n const renderPipelines = new Map<string, GPURenderPipeline>();\n const computePipelines = new Map<string, GPUComputePipeline>();\n let hits = 0;\n let misses = 0;\n\n function memo<T>(store: Map<string, T>, key: string, make: () => T): T {\n const existing = store.get(key);\n if (existing !== undefined) {\n hits += 1;\n return existing;\n }\n misses += 1;\n const made = make();\n store.set(key, made);\n return made;\n }\n\n return {\n get stats() {\n return {\n modules: modules.size,\n renderPipelines: renderPipelines.size,\n computePipelines: computePipelines.size,\n hits,\n misses,\n };\n },\n\n module(key, source) {\n return memo(modules, key, () => factory.createShaderModule({ label: key, code: source() }));\n },\n\n renderPipeline(key, describe) {\n return memo(renderPipelines, key, () => factory.createRenderPipeline(describe()));\n },\n\n computePipeline(key, describe) {\n return memo(computePipelines, key, () => factory.createComputePipeline(describe()));\n },\n\n clear() {\n // GPU pipelines and modules have no explicit destroy: dropping the last\n // reference is the release. Clearing the maps IS the teardown, and it has to\n // happen on device loss because objects from a lost device stay unusable\n // forever.\n modules.clear();\n renderPipelines.clear();\n computePipelines.clear();\n },\n };\n}\n\n/** Pipeline keys, so the \"everything that changes the artefact\" rule is visible. */\nexport const pipelineKey = {\n field: (family: string, format: GPUTextureFormat): string => `field:${family}:${format}`,\n import: (kind: string, format: GPUTextureFormat): string => `import:${kind}:${format}`,\n chain: (entry: string, format: GPUTextureFormat): string => `chain:${entry}:${format}`,\n analysis: (): string => \"analysis\",\n optics: (format: GPUTextureFormat, blend: string): string => `optics:${format}:${blend}`,\n highlight: (format: GPUTextureFormat, blend: string): string => `highlight:${format}:${blend}`,\n} as const;\n","/**\n * The texture pool, with size-epoch invalidation.\n *\n * §GPU device ownership: \"Resizes bump a size epoch that invalidates dependent\n * pyramid allocations.\" Two properties follow from taking that literally, and\n * both are what the pool exists for:\n *\n * - **A texture is keyed by purpose, not by shape.** Callers ask for\n * `\"pyramid:bg-video:level-2\"`, not for \"a 512×256 rgba16float\". So a resize\n * replaces an allocation in place rather than leaking a second one beside it,\n * and the leak is impossible rather than unlikely.\n * - **The epoch is compared, not the size.** A texture allocated under an older\n * epoch is destroyed even when its dimensions happen to match, because a size\n * epoch also covers DPR changes and resolution-policy changes that leave the\n * pixel count alone. Comparing sizes would silently keep a texture whose\n * *meaning* changed.\n *\n * The pool is written over a two-method `TextureAllocator` rather than against\n * `GPUDevice` directly. That is not indirection for its own sake: it makes the\n * keying, the epoch sweep, and the destroy-exactly-once accounting testable\n * without a GPU, which is the half of this file most likely to harbour a leak.\n */\n\nexport interface TextureRequest {\n readonly width: number;\n readonly height: number;\n readonly format: GPUTextureFormat;\n readonly usage: GPUTextureUsageFlags;\n /** Mip levels. The blur chain is the only caller that asks for more than one. */\n readonly mipLevelCount?: number;\n readonly label?: string;\n}\n\n/** The slice of `GPUDevice` the pool needs. `GPUDevice` satisfies it as-is. */\nexport interface TextureAllocator {\n createTexture(descriptor: GPUTextureDescriptor): GPUTexture;\n}\n\ninterface PoolEntry {\n readonly texture: GPUTexture;\n readonly request: TextureRequest;\n readonly epoch: number;\n}\n\nexport interface TexturePoolStats {\n readonly live: number;\n readonly created: number;\n readonly destroyed: number;\n readonly reused: number;\n readonly epoch: number;\n}\n\nexport interface TexturePool {\n readonly sizeEpoch: number;\n readonly stats: TexturePoolStats;\n /**\n * The texture for `key` at the current epoch, allocating or reallocating as\n * needed. Two calls with the same key and the same request in one epoch return\n * the same texture.\n */\n acquire(key: string, request: TextureRequest): GPUTexture;\n /** The texture for `key`, or undefined if nothing is allocated under it. */\n peek(key: string): GPUTexture | undefined;\n release(key: string): void;\n /** Bump the size epoch. Nothing is destroyed until the next `acquire` or `sweep`. */\n bumpSizeEpoch(): number;\n /** Destroy everything allocated under an older epoch. */\n sweep(): number;\n /** Destroy everything. Used by device-loss teardown and by `destroy`. */\n clear(): void;\n}\n\nconst sameShape = (a: TextureRequest, b: TextureRequest): boolean =>\n a.width === b.width &&\n a.height === b.height &&\n a.format === b.format &&\n a.usage === b.usage &&\n (a.mipLevelCount ?? 1) === (b.mipLevelCount ?? 1);\n\nexport function createTexturePool(allocator: TextureAllocator): TexturePool {\n const entries = new Map<string, PoolEntry>();\n let epoch = 0;\n let created = 0;\n let destroyed = 0;\n let reused = 0;\n\n const destroy = (entry: PoolEntry): void => {\n entry.texture.destroy();\n destroyed += 1;\n };\n\n return {\n get sizeEpoch() {\n return epoch;\n },\n\n get stats() {\n return { live: entries.size, created, destroyed, reused, epoch };\n },\n\n acquire(key, request) {\n const existing = entries.get(key);\n if (existing !== undefined) {\n if (existing.epoch === epoch && sameShape(existing.request, request)) {\n reused += 1;\n return existing.texture;\n }\n destroy(existing);\n }\n\n const texture = allocator.createTexture({\n size: {\n width: Math.max(1, Math.floor(request.width)),\n height: Math.max(1, Math.floor(request.height)),\n depthOrArrayLayers: 1,\n },\n format: request.format,\n usage: request.usage,\n mipLevelCount: request.mipLevelCount ?? 1,\n ...(request.label === undefined ? {} : { label: request.label }),\n });\n created += 1;\n entries.set(key, { texture, request, epoch });\n return texture;\n },\n\n peek(key) {\n return entries.get(key)?.texture;\n },\n\n release(key) {\n const entry = entries.get(key);\n if (entry === undefined) return;\n destroy(entry);\n entries.delete(key);\n },\n\n bumpSizeEpoch() {\n epoch += 1;\n return epoch;\n },\n\n sweep() {\n let swept = 0;\n for (const [key, entry] of [...entries]) {\n if (entry.epoch === epoch) continue;\n destroy(entry);\n entries.delete(key);\n swept += 1;\n }\n return swept;\n },\n\n clear() {\n for (const entry of entries.values()) destroy(entry);\n entries.clear();\n },\n };\n}\n\n/** Pool keys, in one place so a typo is a compile error rather than a leak. */\nexport const poolKey = {\n backdropLevel0: (sourceId: string): string => `backdrop:${sourceId}:level0`,\n backdropChain: (sourceId: string): string => `backdrop:${sourceId}:chain`,\n backdropChainScratch: (sourceId: string, level: number): string =>\n `backdrop:${sourceId}:chain-scratch:${level}`,\n backdropBody: (sourceId: string): string => `backdrop:${sourceId}:body`,\n backdropBodyScratch: (sourceId: string): string => `backdrop:${sourceId}:body-scratch`,\n /** The heavy blur and its scratch (W26) — the body's pair, one width deeper. */\n backdropHeavy: (sourceId: string): string => `backdrop:${sourceId}:heavy`,\n backdropHeavyScratch: (sourceId: string): string => `backdrop:${sourceId}:heavy-scratch`,\n /** The SECOND heavy blur and its scratch (W30 G2) — the same pair, one more\n * width along, acquired only where `sizeHeavySecondShare` is non-zero. */\n backdropHeavy2: (sourceId: string): string => `backdrop:${sourceId}:heavy2`,\n backdropHeavy2Scratch: (sourceId: string): string => `backdrop:${sourceId}:heavy2-scratch`,\n backdropUpload: (sourceId: string): string => `backdrop:${sourceId}:upload`,\n /*\n * The four field targets. Their key is a group's RESOURCE identity — the id\n * qualified by the plane it draws on (`groupResourceId`) — and not the group\n * id, because one group can draw on two planes in one frame and each plane's\n * field is its own size.\n */\n groupField: (resourceId: string): string => `group:${resourceId}:field`,\n groupAux: (resourceId: string): string => `group:${resourceId}:aux`,\n groupAux2: (resourceId: string): string => `group:${resourceId}:aux2`,\n /** The surface's presence per pixel (W27d) — the field pass's fourth target. */\n groupPresence: (resourceId: string): string => `group:${resourceId}:presence`,\n} as const;\n","/**\n * Everything that belongs to one device generation, in one object.\n *\n * A device loss makes every GPU object made from that device permanently\n * unusable, and the failure is *silent* — bindings simply stop producing pixels.\n * So the pool, the pipeline cache, the samplers and the uniform buffers are held\n * together with the generation they were made under, and recovery replaces the\n * whole context rather than reaching into it. That makes \"did I just bind a\n * resource from a dead device\" impossible to get wrong instead of merely unlikely.\n */\n\nimport { createPipelineCache, type PipelineCache } from \"./pipeline-cache\";\nimport { createTexturePool, type TexturePool } from \"./texture-pool\";\n\nexport interface GpuContext {\n readonly device: GPUDevice;\n /** The device generation this context belongs to. */\n readonly generation: number;\n readonly pool: TexturePool;\n readonly cache: PipelineCache;\n /** Linear min/mag with linear mip filtering — the pyramid's sampler. */\n readonly chainSampler: GPUSampler;\n /** Linear min/mag, no mips — the body blur and import samplers. */\n readonly flatSampler: GPUSampler;\n destroy(): void;\n}\n\nexport function createGpuContext(device: GPUDevice, generation: number): GpuContext {\n const pool = createTexturePool(device);\n const cache = createPipelineCache(device);\n\n // Clamp-to-edge on every axis. A repeating pyramid would wrap the backdrop\n // across the refraction offset at a group's edge, which reads as a hard seam\n // exactly where the lens is strongest.\n const chainSampler = device.createSampler({\n label: \"vitrea:sampler:chain\",\n magFilter: \"linear\",\n minFilter: \"linear\",\n mipmapFilter: \"linear\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n });\n\n const flatSampler = device.createSampler({\n label: \"vitrea:sampler:flat\",\n magFilter: \"linear\",\n minFilter: \"linear\",\n addressModeU: \"clamp-to-edge\",\n addressModeV: \"clamp-to-edge\",\n });\n\n return {\n device,\n generation,\n pool,\n cache,\n chainSampler,\n flatSampler,\n destroy() {\n pool.clear();\n cache.clear();\n },\n };\n}\n\n/** A uniform buffer sized to a fixed float count, reused across frames. */\nexport interface UniformSlot {\n readonly buffer: GPUBuffer;\n readonly data: Float32Array;\n write(): void;\n}\n\nexport function createUniformSlot(\n device: GPUDevice,\n floats: number,\n label: string,\n): UniformSlot {\n // Uniform buffers must be a multiple of 16 bytes, and every struct in this\n // package is laid out as vec4 rows precisely so this rounding never silently\n // truncates a member.\n const size = Math.ceil((floats * 4) / 16) * 16;\n const buffer = device.createBuffer({\n label,\n size,\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n });\n const data = new Float32Array(size / 4);\n return {\n buffer,\n data,\n write() {\n device.queue.writeBuffer(buffer, 0, data.buffer, data.byteOffset, data.byteLength);\n },\n };\n}\n\n/** A storage buffer that grows in place when the instance count outgrows it. */\nexport interface StorageSlot {\n readonly buffer: GPUBuffer;\n ensure(byteLength: number): GPUBuffer;\n write(data: Float32Array, floatCount: number): void;\n destroy(): void;\n}\n\nexport function createStorageSlot(\n device: GPUDevice,\n initialBytes: number,\n label: string,\n): StorageSlot {\n let capacity = Math.max(initialBytes, 256);\n let buffer = device.createBuffer({\n label,\n size: capacity,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n\n return {\n get buffer() {\n return buffer;\n },\n ensure(byteLength) {\n if (byteLength <= capacity) return buffer;\n buffer.destroy();\n // Grow in powers of two: a group that gains one surface per frame during a\n // morph would otherwise reallocate every frame.\n capacity = 1 << Math.ceil(Math.log2(byteLength));\n buffer = device.createBuffer({\n label,\n size: capacity,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\n });\n return buffer;\n },\n write(data, floatCount) {\n device.queue.writeBuffer(buffer, 0, data.buffer, data.byteOffset, floatCount * 4);\n },\n destroy() {\n buffer.destroy();\n },\n };\n}\n","/**\n * What the renderer consumes each frame, and why it is declared here rather than\n * imported from `vitrea`.\n *\n * The renderer sits **below** core in the dependency graph: core reaches it\n * through a dynamic import (X7's lazy seam), so importing core back would close a\n * cycle that neither `pnpm -r build` nor `tsc` can order. The types below are\n * therefore declared as the *minimal structural contract* the renderer reads, and\n * core's own types satisfy them without an adapter — `SceneResolution`,\n * `FrameContext` and `FrameParticipant` are assignable to the views here, which\n * `test/core-contract.test.ts` asserts against core's real modules.\n *\n * Two things genuinely do not come from core, and both are flagged as\n * parent-impact rather than papered over:\n *\n * - **The corner reference.** `GlassNodeDescriptor` carries `shapeFamily` and\n * the X8 channel vector but not which of the two corner references the shape\n * is fit against (Decision Log #22a made those two separate references, not\n * one axis). It defaults to `\"apple-continuous\"`, which is what the public\n * `profile: \"continuous\"` — the default — resolves to.\n * - **The concentric parent link.** X8 rider 2 binds the renderer to draw a\n * concentric child as a level set *of its parent's field*, which needs to know\n * which surface the parent is. core's node descriptor has no parent edge, so it\n * arrives as a render input.\n *\n * Interaction values arrive as **numbers**, never as time. §Motion puts the\n * drivers on the CPU and the spec is explicit that this package consumes their\n * outputs; there is no clock anywhere in this package for the same reason there is\n * none in core.\n */\n\nimport type {\n CornerReference,\n GroupUnionParams,\n ShapeChannels,\n ShapeFamily,\n} from \"@vitrea/geometry\";\n\nimport type { Rgb } from \"./color\";\nimport type { MaterialPolicyView, MaterialVariant, RefractionQuality } from \"./material\";\n\n/** Viewport-space rectangle in CSS px. Matches core's `Rect`. */\nexport interface Rect {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\n/** Motion-driver outputs for one surface. Every one is a value, never a time. */\nexport interface SurfaceChannels {\n /** `pressCompression`, 0..1. Scaled by motion's `pressCompressionScale`. */\n readonly press: number;\n /** `glow`, 0..1, from the fast-attack / slow-decay driver. */\n readonly glow: number;\n /** Specular sweep position, 0..1 around the contour. */\n readonly sweep: number;\n /**\n * The shimmer's amplitude, 0..1 — the sweep's gain rather than its position.\n *\n * The band's angular coordinate covers the whole contour, so no phase is off\n * the surface and the phase alone cannot mean \"not shimmering\"; this channel\n * carries that. It is 0 on a resting surface, which makes the highlight pass's\n * sweep term exactly zero there, and it is what a shimmer driver will output\n * when v1 gains one.\n */\n readonly shimmer: number;\n /**\n * `lensStrength`, 0..1+. Multiplies the resolved refraction scale.\n *\n * **The range is open above 1** (W27a), which is the range `@vitreajs/vitrea-web`'s\n * `channels.ts` has always documented and the range the motion table has always\n * driven: 1 at rest, 1.03 focused, 1.06 hover, 1.10 morphing, 1.14 pressed, and\n * 0.5 disabled. The instance builder used to clamp the channel at 1 on its way\n * into the shader, which left `disabled` as the only interaction state the lens\n * could see and silently discarded every one that deepens it. The lens depth is\n * still clamped to the surface's half span in the fragment stage, so a strength\n * above 1 deepens the lens without pushing it through the surface.\n */\n readonly lensStrength: number;\n /**\n * `materialization`, 0..1 — the surface's PRESENCE (W27d; contract X6).\n *\n * Apple's `Glass.identity` animates glass to nothing in place and\n * `GlassEffectTransition.materialize` brings it back, and Apple states the\n * mechanism twice: \"prefer setting the effect property over the alpha\", and a\n * surface materializes \"by gradually modulating the light bending and\n * lensing\". The runtime states it a third time from the other side — an\n * `opacity` below 1 on a host or one of its ancestors forms a Backdrop Root\n * and kills the group's proxy sampling — so presence is a scalar on the\n * material's own optical terms and never on the element.\n *\n * It scales the lens's depth and magnitude, the body's mix away from the\n * unblurred backdrop, the material's alpha, the author tint's coverage, the\n * inner and outer shadows, the rim and the highlight. At 1 every one of those\n * is a multiplication by exactly one, so the resting material is byte-identical\n * to the material that had no channel.\n *\n * **Exactly 0 is not the bottom of that ramp but the absence of the surface**\n * (`Glass.identity`). The member is dropped before the field pass\n * (`resolveSurfaces`), so it owns no coverage and joins no union: a group whose\n * members are all at 0 draws nothing at all, and one absent member of a\n * connected group leaves its neighbours the pixels they would have had alone.\n * A material scaled to nothing would still have been a silhouette, and a\n * silhouette that eroded as it faded would be a geometric transition, which is\n * what Apple says materializing is not.\n *\n * The renderer takes a value and never a time: the transit is the motion\n * kernel's `monotonic-ease` driver, on the CPU, like every other channel here.\n */\n readonly materialization: number;\n /** Press point in viewport CSS px. Defaults to the surface's centre. */\n readonly pressPoint?: readonly [number, number];\n}\n\nexport const IDLE_CHANNELS: SurfaceChannels = {\n press: 0,\n glow: 0,\n sweep: 0,\n shimmer: 0,\n lensStrength: 1,\n // 1 rather than 0, for `lensStrength`'s reason: a surface nobody is driving is\n // a surface that is fully there, and 0 is a distinct claim a driver can make.\n materialization: 1,\n};\n\n/** An author tint as this package takes it: a seed in linear light, and a strength. */\nexport interface MaterialTintInput {\n readonly color: readonly [number, number, number];\n readonly strength: number;\n}\n\nexport interface SurfaceInput {\n readonly nodeId: string;\n readonly family: ShapeFamily;\n /** X8, in viewport CSS px. `centre` is the surface's centre, `size` its full extent. */\n readonly shape: ShapeChannels;\n /** Defaults to `\"apple-continuous\"` — see the module note. */\n readonly reference?: CornerReference;\n readonly variant?: MaterialVariant;\n /**\n * The author's tint (core's `ResolvedMaterial.tint`), in **linear** light —\n * the host converts, because this package's whole optical model is linear and\n * the seed is about to be mixed into it.\n *\n * The strength travels per surface and reaches the fragment stage per pixel;\n * the seed colour is resolved once per group, because a group is one optics\n * pass. Core warns when a group's members ask for different seeds\n * (`tint-mixing`), and the first tinted member's colour is the one drawn.\n */\n readonly tint?: MaterialTintInput;\n readonly channels?: Partial<SurfaceChannels>;\n /**\n * X8 rider 2. When present this surface renders as `parentField + inset`, and\n * the parent must be declared in the same group — as a member, or as a\n * `fieldReferenceOnly` shape.\n */\n readonly concentricOf?: { readonly nodeId: string; readonly inset: number };\n /**\n * Declared so a concentric child can be a level set of it, but not itself\n * drawn.\n *\n * This exists because of what a union is: a concentric child's field is its\n * parent's plus a positive inset, so inside the parent the child is always the\n * larger value and `min` discards it. A child nested in the same union as its\n * parent is therefore invisible *by construction* — correct, and not what an\n * inset indicator inside a segmented control's track wants. There, the track\n * and the indicator are separate surfaces with separate material, and the\n * indicator's group needs the track's geometry only as the field its own\n * contour is offset from.\n */\n readonly fieldReferenceOnly?: boolean;\n}\n\nexport interface GroupRenderInput {\n readonly groupId: string;\n readonly surfaces: readonly SurfaceInput[];\n /** The backdrop source to sample. Absent means the group draws with no backdrop. */\n readonly backdropSourceId?: string;\n /** X2's resolved refraction quality for this group. Half of the dual cap. */\n readonly refraction: RefractionQuality;\n /** True where X2 resolved `analysis: \"exact\"`; gates adaptive tint. */\n readonly analysisExact: boolean;\n /**\n * The backdrop source's own average colour, linear light — what backdrop tone\n * adaptation (W7) adapts toward, and the luminance it decides from.\n *\n * A **per-source scalar rather than a per-pixel sample**, and that is why it\n * arrives from outside rather than being read off the pyramid. The host measures\n * it once from the pixels it already supplied and both tiers then read the\n * identical number: the CSS tier cannot sample per pixel at all, and a per-pixel\n * GPU adaptation beside a per-surface CSS one puts the two tiers on different\n * pictures wherever the backdrop has structure — measured on the impulse cell at\n * an interior level ratio of 79 against a gated band of 0.80…1.25. It is also\n * what the reference does: its capsule over a sparse bright grid is a *flat*\n * body, not a window onto the grid.\n *\n * Absent means the adaptation stands down for this group, rather than falling\n * back to a level nobody measured.\n */\n readonly backdropTone?: Rgb;\n /** Author hints retain precedence over the silhouette reduction. */\n readonly backdropToneHint?: boolean;\n /**\n * The backdrop's ENCODED-space tone level (W9, claims §5.31–§5.34): the mean\n * taken in sRGB-encoded space, decoded once — the input the reference's tone\n * response tracks, feeding the collapse band's argument and the response\n * curve. Distinct from `backdropTone` on any structured backdrop: the\n * COLOUR is the physical linear mean (what the collapse converges onto —\n * on the impulse grid the two differ 2.6×, and converging onto the encoded\n * reading was a measured ΔE p95 0.03 → 0.12 regression), while the LEVEL is\n * the encoded reading. Absent falls back to `backdropTone`'s own luminance.\n */\n readonly backdropToneLevel?: number;\n /**\n * The backdrop's LINEAR-space mean luminance, beside `backdropToneLevel`'s\n * encoded-space reading (W9, claims §5.31). The per-pixel tint-tone input\n * samples a chain that averages linearly, so the optics pass multiplies it by\n * `backdropToneLevel / backdropToneLinearLuminance` — locality is\n * preserved and the input's spatial mean matches the model exactly. Absent\n * (or equal to the tone's level) collapses the ratio to 1.\n */\n readonly backdropToneLinearLuminance?: number;\n /**\n * Enables the profile-at-tone material for a DOM layer (W27f G1).\n * The reference is an encoded-compositing convention only, never a measured\n * tone or permission to collapse. The profile itself stays in linear light.\n * Absent preserves the renderer-only harness's legacy no-backdrop drawing;\n * texture groups ignore this descriptor entirely.\n */\n readonly unsampledMaterial?: {\n readonly referenceBackdropLuminance: number;\n readonly minimumTintContrast: number;\n };\n readonly variant?: MaterialVariant;\n /** Overrides the calibration-delegated union defaults. */\n readonly union?: GroupUnionParams;\n}\n\n/** The whole frame's render input. */\nexport interface FrameRenderInput {\n readonly groups: readonly GroupRenderInput[];\n /** The other half of the dual cap. Defaults to the nominal policy. */\n readonly accessibility?: MaterialPolicyView;\n}\n\n/**\n * The structural view of core's `SceneResolution` the renderer reads, so a host\n * can hand core's own object straight through.\n */\nexport interface SceneResolutionView {\n readonly groups: readonly {\n readonly groupId: string;\n readonly state: {\n readonly refraction: RefractionQuality;\n readonly analysis: \"exact\" | \"hint\" | \"none\";\n readonly samplingBackend: \"gpu-texture\" | \"css-backdrop\" | \"none\";\n };\n }[];\n readonly accessibility: { readonly material: MaterialPolicyView };\n}\n\n/** The structural view of core's `BackdropRebuildRequest`. */\nexport interface RebuildRequestView {\n readonly sourceId: string;\n readonly epoch: number;\n readonly resolution: { readonly scale: number; readonly maxDimension: number };\n readonly groupIds: readonly string[];\n}\n\n/** The structural view of core's `FrameContext`. */\nexport interface FrameContextView {\n readonly frame: { readonly id: number; readonly timeMs: number };\n readonly phase: \"collect\" | \"read\" | \"update\" | \"write\" | \"render\";\n readonly resolution?: SceneResolutionView;\n consumeDirtyBackdropSources(): readonly RebuildRequestView[];\n}\n\n/** The structural view of core's `FrameParticipant`. */\nexport interface FrameParticipantView {\n readonly id: string;\n readonly write?: (context: FrameContextView) => void;\n readonly render?: (context: FrameContextView) => void;\n}\n","/**\n * Instance packing: X8's channel vector plus the six derived floats, into the\n * storage buffer the field pass walks.\n *\n * ## X8 rider 2, made unavoidable\n *\n * The rider (tightened at C3's landing, Decision Log #22b) says a renderer MUST\n * draw a concentric child as a **level set of the parent's field**, because\n * instantiating the child as its own resolved shape adds an offset-approximation\n * error that grows with inset — 0.326 px at 8 px, past the field's own declared\n * bound, and dominant past about 4 px.\n *\n * The way that is honoured here is not a check: a concentric surface is packed\n * with its **parent's** `half/re/k` and its own `inset`, and the shader's only\n * expression is `field(p; those params) + inset`. There is no instantiated-shape\n * path to take, so no future caller can take it by accident. `resolveConcentric`\n * — geometry's other path — is still the right answer for bounds and hit-testing,\n * and this module uses it for exactly that and nothing else.\n *\n * ## Press compression\n *\n * §Motion: \"The `pressCompression` channel runs 0…1; this is what 1 means, so the\n * renderer needs no constant of its own.\" So the scale comes from\n * `DEFAULT_MOTION_PROFILE.pressCompressionScale` rather than from a literal here,\n * and it is applied to `size` before the corner is derived — which matters,\n * because the corner budget is a function of size, so a compressed surface must\n * re-derive its corner rather than scale a corner derived at rest.\n */\n\nimport {\n DEFAULT_GROUP_UNION,\n type FieldParams,\n fieldParams,\n governorFieldParams,\n type GroupUnionParams,\n resolveConcentric,\n resolveFromChannels,\n type ResolvedShape,\n type ShapeChannels,\n} from \"@vitrea/geometry\";\nimport { DEFAULT_MOTION_PROFILE } from \"@vitrea/motion\";\n\nimport { rendererError } from \"./errors\";\nimport type { FieldFamily } from \"./governor\";\nimport {\n accessibilityRefractionCap,\n DEFAULT_MATERIAL_PROFILE,\n lensDepthPx as lensDepthOf,\n NOMINAL_MATERIAL_POLICY,\n sizeThicknessUnderPolicy,\n type MaterialPolicyView,\n type MaterialProfile,\n} from \"./material\";\nimport { IDLE_CHANNELS, type GroupRenderInput, type Rect, type SurfaceChannels, type SurfaceInput } from \"./render-model\";\n\n/**\n * 18 floats, 72 bytes, matching `WGSL_INSTANCE_STRUCT`.\n *\n * It was 16 until W2 and W3 landed in the same cut, each needing a per-surface\n * scalar the fragment stage reads per pixel — the size law's thickness factor and\n * the author tint's strength. 17 is not a legal stride: `centre` and `half` are\n * `vec2f`, which aligns the struct to 8 bytes, so its size has to be a multiple\n * of 8 and 72 is the next one up. The eighteenth float was that padding, written\n * as zero rather than left to whatever the buffer held; since W27d it carries the\n * `materialization` channel, so the surface gained a presence at no stride at all.\n */\nexport const INSTANCE_FLOATS = 18;\nexport const INSTANCE_BYTES = INSTANCE_FLOATS * 4;\n\n/**\n * The ceiling on the `lensStrength` channel, as it enters the instance buffer.\n *\n * Not an optical limit — the optics saturate long before it. The fragment stage\n * clamps the lens depth to `span * 0.5` and scales the magnitude by the same\n * ratio, so at the shipped `lensThicknessReference` of 8 a strength of 4 has\n * already pinned every surface in the canonical range against that clamp, and\n * `@vitrea/motion`'s own table tops out at 1.14. Nothing a driver produces comes\n * near this, and nothing between 1.14 and here draws differently from 4.\n *\n * It is a guard on the **buffer**. The channel is read off a host's own custom\n * property (`channels.ts`), where an app can write whatever `parseFloat`\n * accepts, and a profile could in principle carry an absurd thickness beside it.\n * A non-finite product packed into a `Float32Array` reaches the shader as a\n * non-finite uniform, which does not draw a strange lens — it blanks the pass\n * that reads it, silently and for the whole group. A finite ceiling costs one\n * `Math.min` and makes that unreachable.\n */\nexport const LENS_STRENGTH_MAX = 4;\n\n/**\n * The channel as it may enter the buffer: clamped into `[0, LENS_STRENGTH_MAX]`,\n * with `NaN` answered by the idle value rather than by either end of it.\n *\n * `NaN` needs saying out loud because a clamp does not catch it: it compares\n * false against everything, so `Math.min(max, Math.max(0, NaN))` is `NaN` and\n * the guard the clamp was written to be would have had a hole exactly the shape\n * of the thing it was guarding against. Infinities need no such care — they\n * order normally, so `+Infinity` saturates at the ceiling and `-Infinity` at the\n * floor, which is what each of them means.\n *\n * The idle value and not zero, because those are different claims and this\n * package already draws the distinction (`IDLE_CHANNELS`): zero is a surface\n * with its lens switched off, which is something a driver can legitimately ask\n * for, and 1 is a surface nobody is driving. A value that is not a number is the\n * second of those, not the first.\n */\nfunction boundedLensStrength(strength: number): number {\n if (Number.isNaN(strength)) return IDLE_CHANNELS.lensStrength;\n return Math.min(LENS_STRENGTH_MAX, Math.max(0, strength));\n}\n\n/**\n * The presence as it may enter the buffer (W27d): clamped into `[0, 1]`, with\n * `NaN` answered by the idle rather than by either end of it.\n *\n * The same two arguments `boundedLensStrength` makes, for the same reasons. The\n * clamp is closed above here because presence has a top — a surface cannot be\n * more than present, and the terms it scales are the material's own, already\n * fitted at their full amount — and `NaN` is the undriven case rather than a\n * surface asked to disappear, which is the difference between a channel nobody\n * wrote and a channel written to 0.\n */\nfunction boundedMaterialization(value: number): number {\n if (Number.isNaN(value)) return IDLE_CHANNELS.materialization;\n return Math.min(1, Math.max(0, value));\n}\n\n/**\n * Whether this surface draws material at all — the one predicate for it.\n *\n * Two kinds of member do not, for one reason: neither has anything for the field\n * pass to draw. A reference shape (`fieldReferenceOnly`) exists so a concentric\n * child has a parent field to be a level set of. A surface at `materialization:\n * 0` is `Glass.identity` — the glass animated to nothing in place — and a surface\n * with no glass on it contributes no instance, no coverage and no union.\n *\n * Exported because the group's own uniforms have to agree with it: the tint seed\n * is resolved from the first *drawn* tinted member, and a group whose emphasised\n * control has dematerialized must paint with the colour of one that is still\n * there. Anything else that reads \"which members does this group draw\" belongs\n * here too rather than in a second copy of the rule.\n */\nexport function drawsMaterial(surface: SurfaceInput): boolean {\n if (surface.fieldReferenceOnly === true) return false;\n const presence = surface.channels?.materialization ?? IDLE_CHANNELS.materialization;\n return boundedMaterialization(presence) > 0;\n}\n\nexport interface ResolvedSurface {\n readonly nodeId: string;\n /** The surface's own resolved shape — bounds, hit-testing, and the rim's scale. */\n readonly shape: ResolvedShape;\n /** The field parameters actually packed: the parent's, for a concentric child. */\n readonly field: FieldParams;\n /** Level-set offset. 0 for an ordinary surface. */\n readonly inset: number;\n readonly centre: readonly [number, number];\n readonly channels: SurfaceChannels;\n /** Shorter extent in CSS px — what the whole size law is a function of. */\n readonly spanPx: number;\n /**\n * The lens depth in CSS px (W12 G2): the reference's height law scaled by the\n * author's thickness, folded under the accessibility regime, clamped to the\n * shorter half extent — `lensDepthPx` in `material.ts`. The CPU's reading of\n * what the shader evaluates per pixel from the thickness and the span it\n * carries; tests and the harness read it, the shader does not.\n */\n readonly lensDepthPx: number;\n /** The author tint's strength, 0 where the surface is untinted. */\n readonly tintStrength: number;\n /**\n * The size law's thickness factor for this surface, 0…1 (`sizeThickness`),\n * folded under the accessibility policy.\n *\n * Resolved here because it is a property of the surface, and the lens depth\n * above is derived from it on the CPU. It no longer rides the field pass:\n * since W11c the scatter facet has a curve of its own with a band top past\n * `sizeSpanMax`, so the per-pixel slot carries the SPAN (`spanPx`) and the\n * fragment stage evaluates both curves from it — see `wgsl/field.ts`'s\n * `aux` note.\n */\n readonly sizeThickness: number;\n /**\n * The surface's presence, 0…1 (W27d): the `materialization` channel bounded on\n * its way into the buffer. 1 on a surface nobody drives, which is the material\n * the calibration bed measures.\n */\n readonly materialization: number;\n}\n\nconst channelsOf = (input: SurfaceInput): SurfaceChannels => ({\n ...IDLE_CHANNELS,\n ...input.channels,\n});\n\n/** `size` after press compression, which the corner is then derived from. */\nfunction compressedChannels(shape: ShapeChannels, press: number): ShapeChannels {\n if (press <= 0) return shape;\n const scale = 1 - Math.min(1, Math.max(0, press)) * DEFAULT_MOTION_PROFILE.pressCompressionScale;\n return { ...shape, size: [shape.size[0] * scale, shape.size[1] * scale] };\n}\n\n/**\n * Resolve one group's surfaces, ordered so that a concentric child always follows\n * its parent. The order matters only for the resolution pass, not for the union —\n * `smoothUnion2` is commutative, which `union.ts` asserts rather than assumes.\n */\nexport function resolveSurfaces(\n group: GroupRenderInput,\n family: FieldFamily,\n profile: MaterialProfile = DEFAULT_MATERIAL_PROFILE,\n policy: MaterialPolicyView = NOMINAL_MATERIAL_POLICY,\n): readonly ResolvedSurface[] {\n const byId = new Map<string, SurfaceInput>();\n for (const surface of group.surfaces) {\n if (byId.has(surface.nodeId)) {\n throw rendererError(\n \"source-identity\",\n `Group \"${group.groupId}\" lists surface \"${surface.nodeId}\" twice.`,\n surface.nodeId,\n );\n }\n byId.set(surface.nodeId, surface);\n }\n\n const resolvedShapes = new Map<string, ResolvedShape>();\n const resolving = new Set<string>();\n const resolveShapeOf = (surface: SurfaceInput): ResolvedShape => {\n const cached = resolvedShapes.get(surface.nodeId);\n if (cached !== undefined) return cached;\n if (resolving.has(surface.nodeId)) {\n throw rendererError(\n \"pass-input\",\n `Concentric surfaces in group \"${group.groupId}\" form a cycle through \"${surface.nodeId}\". A level set needs a parent field that resolves without it.`,\n surface.nodeId,\n );\n }\n resolving.add(surface.nodeId);\n\n const channels = channelsOf(surface);\n const reference = surface.reference ?? \"apple-continuous\";\n\n if (surface.concentricOf === undefined) {\n const shape = resolveFromChannels(\n compressedChannels(surface.shape, channels.press),\n reference,\n surface.family,\n { devMode: false },\n );\n resolvedShapes.set(surface.nodeId, shape);\n resolving.delete(surface.nodeId);\n return shape;\n }\n\n const parentInput = byId.get(surface.concentricOf.nodeId);\n if (parentInput === undefined) {\n throw rendererError(\n \"pass-input\",\n `Surface \"${surface.nodeId}\" is concentric to \"${surface.concentricOf.nodeId}\", which is not a member of group \"${group.groupId}\". X8 rider 2 renders a concentric child as a level set of its parent's field, so the parent has to be in the same field pass.`,\n surface.nodeId,\n );\n }\n // The child's OWN resolved shape, for bounds and hit-testing only. What gets\n // packed is the parent's field plus the inset — see the module note.\n const shape = resolveConcentric(resolveShapeOf(parentInput), {\n inset: surface.concentricOf.inset,\n }).shape;\n resolvedShapes.set(surface.nodeId, shape);\n resolving.delete(surface.nodeId);\n return shape;\n };\n\n const paramsFor = (shape: ResolvedShape): FieldParams =>\n family === \"rsup\" ? governorFieldParams(shape) : fieldParams(shape);\n\n /*\n * Every member is RESOLVED — a concentric child needs its parent's field\n * whether or not the parent is drawn — and then the ones with no material on\n * them are dropped (`drawsMaterial`).\n *\n * Dropping the absent ones HERE rather than fading their terms in the shader is\n * what makes W27d's endpoint exact: the group's field rect, its instance buffer\n * and therefore its pixels become the ones the group would have had without the\n * member at all, so a surface at `materialization: 0` can neither own a\n * silhouette nor grow a neck toward a present neighbour. Every value above zero\n * is a material that is still there, drawn with each optical term scaled by the\n * channel, and the shader is where that continuum lives.\n */\n return group.surfaces\n .filter(drawsMaterial)\n .map((surface): ResolvedSurface => {\n const channels = channelsOf(surface);\n const shape = resolveShapeOf(surface);\n\n const fieldSource =\n surface.concentricOf === undefined\n ? shape\n : resolveShapeOf(byId.get(surface.concentricOf.nodeId) as SurfaceInput);\n const inset = surface.concentricOf?.inset ?? 0;\n\n const spanPx = Math.min(shape.channels.size[0], shape.channels.size[1]);\n // The size law's one input, already folded under the accessibility regime —\n // see `sizeThicknessUnderPolicy`. Resolved once here so the lens depth and the\n // per-pixel factor cannot disagree about how thick this surface reads.\n const thickness = sizeThicknessUnderPolicy(spanPx, policy, profile);\n return {\n nodeId: surface.nodeId,\n shape,\n field: paramsFor(fieldSource),\n inset,\n centre: [fieldSource.channels.center[0], fieldSource.channels.center[1]],\n channels,\n spanPx,\n lensDepthPx: lensDepthOf(\n shape.channels.thickness,\n spanPx,\n profile,\n profile.refractionScale[accessibilityRefractionCap(policy)],\n ),\n sizeThickness: thickness,\n materialization: boundedMaterialization(channels.materialization),\n tintStrength: Math.min(1, Math.max(0, surface.tint?.strength ?? 0)),\n };\n });\n}\n\n/**\n * The group's field-pass rect, in viewport CSS px.\n *\n * Padded by whatever can reach beyond a surface's own contour: the rim band, the\n * union's bulge cap, one coverage pixel, and — since W8 — the outer shadow's\n * reach. Not padded by the lens depth — the lens displaces where the backdrop is\n * *sampled from*, not where the material is *drawn*, so paying for it here would\n * widen every group's field pass for nothing.\n *\n * The shadow is the one term that is genuinely large: `outerShadowReachPx` runs\n * to roughly 45 CSS px at the shipped profile, against a rim-and-bulge pad of\n * about 3. It is not optional — the optics pass scissors to this rect, so a rect\n * that stops at the contour draws no shadow at all — and it is not unconditional\n * either: a profile whose shadow occlusion is zero has a reach of zero and pays\n * exactly what it used to.\n */\nexport function groupFieldRect(\n surfaces: readonly ResolvedSurface[],\n union: GroupUnionParams = DEFAULT_GROUP_UNION,\n rimWidthPx = 2,\n outerShadowReachPx = 0,\n): Rect {\n if (surfaces.length === 0) return { x: 0, y: 0, width: 0, height: 0 };\n\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n\n for (const surface of surfaces) {\n const [cx, cy] = surface.shape.channels.center;\n const [w, h] = surface.shape.channels.size;\n minX = Math.min(minX, cx - w / 2);\n minY = Math.min(minY, cy - h / 2);\n maxX = Math.max(maxX, cx + w / 2);\n maxY = Math.max(maxY, cy + h / 2);\n }\n\n const pad = Math.max(rimWidthPx + union.maxBulge + 1, Math.max(outerShadowReachPx, 0));\n return {\n x: minX - pad,\n y: minY - pad,\n width: maxX - minX + 2 * pad,\n height: maxY - minY + 2 * pad,\n };\n}\n\n/** A rectangle in whole device pixels: what a viewport and a scissor take. */\nexport interface DevicePixelRect {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * A group's field rect in device pixels, clipped to the plane canvas.\n *\n * `groupFieldRect` grows the surface union by the rim and bulge margin, so a\n * surface within a few CSS px of the viewport's top or left edge produces a rect\n * with a negative origin. The optics and highlight passes set that rect as the\n * canvas viewport *and* scissor, and `setScissorRect` takes unsigned values, so an\n * unclipped rect is a hard `RangeError` out of the WebGPU binding rather than a\n * clipped draw. A toolbar pinned to the left edge is enough to reach it.\n *\n * Returns `undefined` where nothing of the rect is on the canvas, which is the\n * caller's signal to skip the group entirely.\n *\n * The caller must derive the instance frame from the returned rect rather than\n * from the CSS rect it passed in. The field texture is allocated at this size and\n * `fs_optics` reads it by `uv` over the viewport, so a viewport that moved without\n * the texture and the instance origin moving with it would stretch the glass\n * instead of clipping it. What clipping costs is the part of the field outside the\n * canvas, which is the part nothing can see.\n */\nexport function clipFieldRectToCanvas(\n snapped: Rect,\n devicePixelRatio: number,\n canvasDevice: readonly [number, number],\n): DevicePixelRect | undefined {\n const left = Math.max(0, Math.round(snapped.x * devicePixelRatio));\n const top = Math.max(0, Math.round(snapped.y * devicePixelRatio));\n const right = Math.min(\n canvasDevice[0],\n Math.round((snapped.x + snapped.width) * devicePixelRatio),\n );\n const bottom = Math.min(\n canvasDevice[1],\n Math.round((snapped.y + snapped.height) * devicePixelRatio),\n );\n if (right <= left || bottom <= top) return undefined;\n return { x: left, y: top, width: right - left, height: bottom - top };\n}\n\n/** The same rect snapped outward to whole device pixels. */\nexport function snapRectToDevicePixels(rect: Rect, devicePixelRatio: number): Rect {\n const x = Math.floor(rect.x * devicePixelRatio) / devicePixelRatio;\n const y = Math.floor(rect.y * devicePixelRatio) / devicePixelRatio;\n const right = Math.ceil((rect.x + rect.width) * devicePixelRatio) / devicePixelRatio;\n const bottom = Math.ceil((rect.y + rect.height) * devicePixelRatio) / devicePixelRatio;\n return { x, y, width: Math.max(right - x, 0), height: Math.max(bottom - y, 0) };\n}\n\n/**\n * Pack resolved surfaces into the storage buffer, with centres made relative to\n * the group's rect so the shader's coordinates stay small however far down a long\n * page the group sits — f32 loses resolution at large magnitudes, and a field\n * evaluated at y = 40000 would quantise its own corner.\n */\nexport function packInstances(\n surfaces: readonly ResolvedSurface[],\n origin: readonly [number, number],\n into?: Float32Array,\n): { readonly data: Float32Array; readonly count: number } {\n const needed = Math.max(surfaces.length, 1) * INSTANCE_FLOATS;\n const data =\n into !== undefined && into.length >= needed ? into : new Float32Array(needed);\n\n for (let i = 0; i < surfaces.length; i += 1) {\n const s = surfaces[i] as ResolvedSurface;\n const o = i * INSTANCE_FLOATS;\n data[o + 0] = s.centre[0] - origin[0];\n data[o + 1] = s.centre[1] - origin[1];\n data[o + 2] = s.field.halfW;\n data[o + 3] = s.field.halfH;\n data[o + 4] = s.field.reach;\n data[o + 5] = s.field.k[0];\n data[o + 6] = s.field.k[1];\n data[o + 7] = s.field.k[2];\n data[o + 8] = s.field.k[3];\n data[o + 9] = s.field.k[4];\n data[o + 10] = s.inset;\n data[o + 11] = s.shape.channels.thickness;\n data[o + 12] = s.channels.press;\n data[o + 13] = s.channels.glow;\n // The shader's `lensThick` slot (W12 G2): the authored thickness in CSS px\n // scaled by the `lensStrength` motion channel. The fragment stage evaluates\n // BOTH depths from it and the span — the lens's (the reference's height law)\n // and the inner shadow's (W2's size gain, kept) — so a strength of 0 turns\n // the lens off exactly as the resolved depth used to, and neither depth can\n // be rounded through the other. Until W12 G2 this slot carried the resolved\n // lens depth itself; the CPU still resolves it (`lensDepthPx`) for readers.\n //\n // **The clamp is `0..LENS_STRENGTH_MAX` rather than `0..1`** (W27a). This\n // multiplied by `min(1, max(0, lensStrength))`, and the channel's documented\n // range is `0..1+`: `@vitrea/motion`'s table drives it to 1.03 focused, 1.06\n // hover, 1.10 morphing and 1.14 pressed, so a clamp at 1 meant `disabled`\n // (0.5) was the only interaction state that reached the shader at all and\n // every state that DEEPENS the lens arrived as the resting material.\n //\n // The ceiling that replaces it is a **guard on the buffer, not on the\n // optics**: the fragment stage already clamps the lens depth to `span * 0.5`\n // and scales the magnitude by the same ratio, so the material saturates far\n // below it and nothing between the motion table's 1.14 and the ceiling is\n // reachable by any driver. What the ceiling is for is the value no driver\n // produces — the channel is read off a host's own custom property, where an\n // app can write anything a `parseFloat` accepts, and `Infinity` or `1e40`\n // packed into a `Float32Array` becomes a non-finite uniform that blanks a\n // whole pass rather than drawing a strange lens.\n //\n // At rest the channel is exactly 1, where every form of this arithmetic\n // agrees, so the resting material is byte-identical and the golden bed does\n // not move.\n data[o + 14] = Math.max(s.shape.channels.thickness, 0) * boundedLensStrength(s.channels.lensStrength);\n // The shader's `tintK` slot, and the only per-surface half of the author\n // tint: the seed is a group uniform, this is how much of it this pixel gets.\n data[o + 15] = s.tintStrength;\n // The size law's per-pixel input: the surface's own span, in CSS px. The\n // fragment stage evaluates the thickness curve AND the scatter curve from it\n // (W11c), with the band constants and the accessibility fold as uniforms —\n // one slot, two curves, and nothing the CPU resolved that the shader has to\n // re-derive from geometry it cannot see.\n data[o + 16] = s.spanPx;\n // The shader's `mat` slot (W27d): the surface's presence, in the float the\n // struct's 8-byte alignment already required and which was written as zero\n // until this wave. Presence is per SURFACE and reaches the fragment stages\n // per pixel, because one group is one field pass and one optics pass while\n // its members each materialize on their own timeline — a toolbar can\n // dissolve one item and keep the rest.\n //\n // At rest the channel is exactly 1, where every term it multiplies is a\n // multiplication by one, so the resting material is byte-identical and the\n // golden bed does not move.\n data[o + 17] = s.materialization;\n }\n\n return { data, count: surfaces.length };\n}\n","/**\n * Pass-by-pass timing, for the benchmark §Performance envelope pins the ~2 ms\n * hypothesis to.\n *\n * The spec asks for the budget to be \"measured per pass (backdrop import, blur,\n * analysis, body, highlight, composite) alongside browser end-to-end frame time\",\n * which needs GPU-side timestamps: wall-clock around `submit()` measures the\n * queue, not the work. WebGPU's only timestamp mechanism is `timestampWrites` on\n * a pass descriptor — `encoder.writeTimestamp` was removed from the spec — so the\n * timeline hands out begin/end query indices by label and each pass spreads them\n * into its descriptor.\n *\n * Where `timestamp-query` is unavailable the timeline is simply absent and the\n * benchmark falls back to wall-clock totals, reported as such. A number labelled\n * as a GPU pass time that was actually a CPU submit time would be worse than no\n * number, and §Risks already names timestamp-query availability as an engine\n * variance to record rather than to assume.\n *\n * One caveat worth stating because it changes how the results read: Chrome\n * quantises timestamp results to 100 µs by default, so a single short pass reads\n * as 0. The benchmark works around it the way S2's harness did — by launching with\n * `--disable-dawn-features=timestamp_quantization`, and by measuring many\n * repetitions when it cannot.\n */\n\nexport interface PassTimeline {\n /** Query indices for a render pass, or undefined when timing is off. */\n renderSlot(label: string): GPURenderPassTimestampWrites | undefined;\n computeSlot(label: string): GPUComputePassTimestampWrites | undefined;\n}\n\nexport interface TimingCollector extends PassTimeline {\n readonly capacity: number;\n readonly used: number;\n /** Queue the resolve + copy. Call once, after the last pass of the frame. */\n resolve(encoder: GPUCommandEncoder): void;\n /** Read the resolved timings. Labels map to elapsed nanoseconds. */\n read(): Promise<ReadonlyMap<string, number>>;\n /**\n * Slots whose resolved pair was not a positive duration, since the collector\n * was created. A non-zero count means some number reported here is missing a\n * pass, and saying so is better than quietly averaging it in.\n */\n readonly anomalies: number;\n reset(): void;\n destroy(): void;\n}\n\nexport function supportsTimestamps(device: GPUDevice): boolean {\n return device.features.has(\"timestamp-query\");\n}\n\nexport function createTimingCollector(device: GPUDevice, capacity = 64): TimingCollector {\n const querySet = device.createQuerySet({\n label: \"vitrea:timing\",\n type: \"timestamp\",\n count: capacity * 2,\n });\n const byteLength = capacity * 2 * 8;\n const resolveBuffer = device.createBuffer({\n label: \"vitrea:timing:resolve\",\n size: byteLength,\n usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,\n });\n const staging = device.createBuffer({\n label: \"vitrea:timing:staging\",\n size: byteLength,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n });\n\n let used = 0;\n let anomalies = 0;\n const labels: string[] = [];\n\n const take = (label: string): { begin: number; end: number } | undefined => {\n if (used >= capacity) return undefined;\n const index = used;\n used += 1;\n labels[index] = label;\n return { begin: index * 2, end: index * 2 + 1 };\n };\n\n return {\n capacity,\n get used() {\n return used;\n },\n\n get anomalies() {\n return anomalies;\n },\n\n renderSlot(label) {\n const slot = take(label);\n if (slot === undefined) return undefined;\n return {\n querySet,\n beginningOfPassWriteIndex: slot.begin,\n endOfPassWriteIndex: slot.end,\n };\n },\n\n computeSlot(label) {\n const slot = take(label);\n if (slot === undefined) return undefined;\n return {\n querySet,\n beginningOfPassWriteIndex: slot.begin,\n endOfPassWriteIndex: slot.end,\n };\n },\n\n resolve(encoder) {\n if (used === 0) return;\n encoder.resolveQuerySet(querySet, 0, used * 2, resolveBuffer, 0);\n encoder.copyBufferToBuffer(resolveBuffer, 0, staging, 0, used * 2 * 8);\n },\n\n async read() {\n const out = new Map<string, number>();\n if (used === 0) return out;\n await staging.mapAsync(GPUMapMode.READ, 0, used * 2 * 8);\n const view = new BigInt64Array(staging.getMappedRange(0, used * 2 * 8).slice(0));\n staging.unmap();\n for (let i = 0; i < used; i += 1) {\n const begin = view[i * 2] ?? 0n;\n const end = view[i * 2 + 1] ?? 0n;\n const label = labels[i] ?? `pass-${i}`;\n const elapsed = Number(end - begin);\n // Zero IS a legitimate duration — a clear-only pass with no draw really\n // does take no measurable time. What is not legitimate is a *negative*\n // one, or a pair where both endpoints are zero: WebGPU leaves a slot\n // unspecified when its pass did not run, and averaging that in would\n // corrupt every number in the report. Those are dropped and counted.\n if (!Number.isFinite(elapsed) || elapsed < 0 || (begin === 0n && end === 0n)) {\n anomalies += 1;\n continue;\n }\n // Several passes share a label (one per group, one per pyramid level), and\n // the interesting number is the total the budget is spent on, so labels\n // accumulate rather than overwrite.\n out.set(label, (out.get(label) ?? 0) + elapsed);\n }\n return out;\n },\n\n reset() {\n used = 0;\n labels.length = 0;\n },\n\n destroy() {\n querySet.destroy();\n resolveBuffer.destroy();\n staging.destroy();\n },\n };\n}\n\n/** Pass labels, so the benchmark's report and the passes agree on the names. */\nexport const PASS_LABEL = {\n import: \"backdrop-import\",\n chain: \"blur-chain\",\n bodyBlur: \"body-blur\",\n analysis: \"analysis\",\n field: \"group-field\",\n optics: \"optics\",\n highlight: \"highlight\",\n} as const;\n","/**\n * The f32 cross-check pass (Decision Log #20's obligation on C6).\n *\n * S2 measured family D's WGSL against an f64 evaluation of the same arithmetic and\n * got 4.08e-5 px — 0.024% of the declared 0.170 px bound. Family C, the quality\n * governor's first within-tier step, was priced but only inspection-verified, and\n * the spec makes its shipping conditional on it going through the same check.\n *\n * The reason this pass lives in `src/` rather than in a test harness is the point\n * of the whole exercise: it compiles **the same kernel strings the renderer\n * ships** — `WGSL_FIELD_KERNELS`, the constants `fieldPassSource` is assembled\n * from — over a caller-supplied point set. A check that compiled a separate copy\n * of the algebra would prove something about the copy.\n *\n * It is a compute pass rather than a render pass because the output is numbers:\n * a render target would quantise them at whatever the attachment format is, and\n * `rgba16float` has ten mantissa bits, which is coarser than the difference being\n * measured by three orders of magnitude.\n */\n\nexport const CROSS_CHECK_SHAPE_FLOATS = 12;\nexport const CROSS_CHECK_WORKGROUP = 64;\n\nexport const WGSL_CROSS_CHECK_PASS = `struct CheckShape {\n centre : vec2f,\n half : vec2f,\n re : f32,\n k0 : f32,\n k1 : f32,\n k2 : f32,\n k3 : f32,\n k4 : f32,\n _pad0 : f32,\n _pad1 : f32,\n};\n\n/// point.xy = shape-local coordinates, point.z = shape index, point.w unused\n@group(0) @binding(0) var<storage, read> checkShapes : array<CheckShape>;\n@group(0) @binding(1) var<storage, read> checkPoints : array<vec4f>;\n@group(0) @binding(2) var<storage, read_write> outRsupn : array<f32>;\n@group(0) @binding(3) var<storage, read_write> outRsup : array<f32>;\n@group(0) @binding(4) var<uniform> checkCount : vec4u;\n\n@compute @workgroup_size(${CROSS_CHECK_WORKGROUP})\nfn cs_cross_check(@builtin(global_invocation_id) gid : vec3u) {\n let i = gid.x;\n if (i >= checkCount.x) { return; }\n\n let p = checkPoints[i];\n let s = checkShapes[u32(p.z)];\n let k = vec4f(s.k0, s.k1, s.k2, s.k3);\n let local = p.xy - s.centre;\n\n outRsupn[i] = sd_rsupn(local, s.half, s.re, k, s.k4);\n outRsup[i] = sd_rsup(local, s.half, s.re, k, s.k4);\n}`;\n","/**\n * Backdrop import and the blur pyramid.\n *\n * ## Import (X3, X5)\n *\n * One pass normalises every source kind into level 0 of the pyramid:\n * **premultiplied, linear-light, sRGB-primaries `rgba16float`**. The three\n * things that differ between providers — encoding, alpha mode, colour space —\n * arrive as uniforms resolved on the CPU, where the provider's contract is\n * known, so no shader ever guesses at them. That is what X3's \"the compositor\n * normalizes at import\" means operationally: imported video is unpremultiplied\n * and copied images are premultiplied, and after this pass neither fact is\n * visible downstream.\n *\n * The unpremultiply happens *before* the transfer-function decode and the\n * re-premultiply *after* it. Decoding a premultiplied value is meaningless — the\n * curve is not linear, so `decode(c·a) != decode(c)·a` — and getting that order\n * wrong shows up as dark fringes on every soft edge.\n *\n * ## The chain\n *\n * Progressive downsample, 13 taps per level, sampled bilinearly so the 13 taps\n * cover a 4×4 footprint. This is the standard bloom-pyramid filter, and it is\n * here for the reason it exists there: it is the cheapest filter whose repeated\n * application does not produce the boxy, aliasing-prone result a naive 2×2 average\n * gives, and it is one pass per level rather than the three a\n * downsample-then-separable-blur chain needs.\n *\n * With `mipmapFilter: \"linear\"` on the sampler, `textureSampleLevel(chain, s, uv,\n * lod)` is then a continuously variable blur — which is exactly what the optics\n * pass needs for \"LOD by thickness/size\".\n *\n * ## The body blur\n *\n * The chain gives blur in powers of two. The material's own σ is not a power of\n * two, so the body — the large, flat region of frost behind a surface — gets one\n * dedicated separable Gaussian at the residual σ on top of the nearest chain\n * level. Two passes for the whole scene, not two per level: the refraction path\n * has no use for it, because a rim sample wants the sharpest level it can get.\n */\n\n/**\n * `srcEncoded`: 1 when the sampled values are sRGB-encoded (every 8-bit copy and\n * every external video texture), 0 when they are already linear (an app-supplied\n * float view can be either, so the provider declares it).\n *\n * `alphaMode`: 0 premultiplied, 1 unpremultiplied, 2 opaque — the enumeration\n * `alphaNormalisationMode` in `color.ts` produces.\n */\nexport const WGSL_IMPORT_PASS = `struct ImportUniforms {\n m0 : vec4f, // colour matrix row 0 (xyz), srcEncoded (w)\n m1 : vec4f, // row 1 (xyz), alphaMode (w)\n m2 : vec4f, // row 2 (xyz), unused (w)\n fit : vec4f, // uv scale (xy), uv offset (zw) — the source's fit into the target\n};\n\n@group(0) @binding(0) var<uniform> iu : ImportUniforms;\n@group(0) @binding(1) var srcSampler : sampler;\n@group(0) @binding(2) var srcTexture : SRC_TEXTURE_TYPE;\n\nfn sample_src(uv : vec2f) -> vec4f {\n return SRC_SAMPLE_EXPR;\n}\n\n@fragment\nfn fs_import(in : FullscreenOut) -> @location(0) vec4f {\n let uv = in.uv * iu.fit.xy + iu.fit.zw;\n var raw = sample_src(clamp(uv, vec2f(0.0), vec2f(1.0)));\n\n let alphaMode = iu.m1.w;\n var alpha = raw.a;\n var colour = raw.rgb;\n\n if (alphaMode > 1.5) {\n alpha = 1.0;\n } else if (alphaMode > 0.5) {\n // Already unpremultiplied: nothing to undo.\n } else {\n // Premultiplied input — undo it before the non-linear decode. A fully\n // transparent texel carries zero colour, so the floored divide returns zero\n // there without a branch.\n colour = colour / max(alpha, 1e-6);\n }\n\n if (iu.m0.w > 0.5) {\n colour = srgb_to_linear(clamp(colour, vec3f(0.0), vec3f(1.0)));\n }\n\n // Colour-space conversion in linear light. Identity for sRGB sources.\n colour = vec3f(dot(iu.m0.xyz, colour), dot(iu.m1.xyz, colour), dot(iu.m2.xyz, colour));\n\n return vec4f(max(colour, vec3f(0.0)) * alpha, alpha);\n}`;\n\n/** `SRC_TEXTURE_TYPE`/`SRC_SAMPLE_EXPR` per source kind. */\nexport function importPassSource(kind: \"sampled\" | \"external\"): string {\n const type = kind === \"external\" ? \"texture_external\" : \"texture_2d<f32>\";\n const expr =\n kind === \"external\"\n ? \"textureSampleBaseClampToEdge(srcTexture, srcSampler, uv)\"\n : \"textureSampleLevel(srcTexture, srcSampler, uv, 0.0)\";\n return WGSL_IMPORT_PASS.replace(\"SRC_TEXTURE_TYPE\", type).replace(\"SRC_SAMPLE_EXPR\", expr);\n}\n\n/**\n * 13-tap progressive downsample. Offsets are in the SOURCE level's texels; the\n * caller passes `1 / srcSize` so the pass needs no texture-dimension query.\n */\nexport const WGSL_DOWNSAMPLE_PASS = `struct ChainUniforms {\n texel : vec4f, // 1/srcSize (xy), unused (zw)\n params : vec4f, // sigma in texels (x), direction (yz), unused (w)\n};\n\n@group(0) @binding(0) var<uniform> cu : ChainUniforms;\n@group(0) @binding(1) var chainSampler : sampler;\n@group(0) @binding(2) var chainTexture : texture_2d<f32>;\n\nfn tap(uv : vec2f, o : vec2f) -> vec4f {\n return textureSampleLevel(chainTexture, chainSampler, uv + o * cu.texel.xy, 0.0);\n}\n\n@fragment\nfn fs_downsample(in : FullscreenOut) -> @location(0) vec4f {\n let uv = in.uv;\n\n let a = tap(uv, vec2f(-2.0, 2.0));\n let b = tap(uv, vec2f( 0.0, 2.0));\n let c = tap(uv, vec2f( 2.0, 2.0));\n let d = tap(uv, vec2f(-2.0, 0.0));\n let e = tap(uv, vec2f( 0.0, 0.0));\n let f = tap(uv, vec2f( 2.0, 0.0));\n let g = tap(uv, vec2f(-2.0, -2.0));\n let h = tap(uv, vec2f( 0.0, -2.0));\n let i = tap(uv, vec2f( 2.0, -2.0));\n let j = tap(uv, vec2f(-1.0, 1.0));\n let k = tap(uv, vec2f( 1.0, 1.0));\n let l = tap(uv, vec2f(-1.0, -1.0));\n let m = tap(uv, vec2f( 1.0, -1.0));\n\n // Weights: the centre cross carries 0.5 across four inner taps, the corners\n // and edges the remaining 0.5. Sums to exactly 1, so the chain neither gains\n // nor loses energy — which is what keeps the analysis pass's luminance honest\n // however many levels it reads through.\n var out = (j + k + l + m) * 0.5 * 0.25;\n out = out + (a + b + d + e) * 0.125 * 0.25;\n out = out + (b + c + e + f) * 0.125 * 0.25;\n out = out + (d + e + g + h) * 0.125 * 0.25;\n out = out + (e + f + h + i) * 0.125 * 0.25;\n return out;\n}\n\n/// Separable Gaussian, nine taps, run once horizontally and once vertically to\n/// take the nearest chain level up to the material's exact sigma.\n@fragment\nfn fs_blur(in : FullscreenOut) -> @location(0) vec4f {\n let dir = cu.params.yz;\n let sigma = max(cu.params.x, 1e-4);\n let inv = -0.5 / (sigma * sigma);\n\n var sum = vec4f(0.0);\n var weight = 0.0;\n for (var t = -4; t <= 4; t = t + 1) {\n let ft = f32(t);\n let w = exp(ft * ft * inv);\n sum = sum + textureSampleLevel(chainTexture, chainSampler, in.uv + dir * ft * cu.texel.xy, 0.0) * w;\n weight = weight + w;\n }\n return sum / weight;\n}`;\n","/**\n * The group field pass (§Geometry: \"instances → group SDF/coverage field → one\n * optical pass\").\n *\n * Three contract points are structural here rather than conventional, which is\n * the only way a shader can be held to them:\n *\n * 1. **X8 rider 2 — a concentric child renders as a LEVEL SET of its parent's\n * field.** There is no second path. `Instance` carries the *parent's*\n * `half/re/k` plus its own `inset`, and the evaluator always computes\n * `field(p; parent params) + inset`. For an ordinary surface `inset` is 0 and\n * the expression is the surface's own field. So the instantiated-shape path —\n * whose offset error grows with inset and dominates the declared bound past\n * about 4 px — is not expressible in this shader at all.\n * 2. **The families come from `@vitrea/geometry` verbatim.** `sd_rsupn` and\n * `sd_rsup` are the fingerprinted strings that package owns, spliced in\n * unchanged, so the cost figures and the f32 result transfer with them. What\n * this module adds is their gradients and the union, which S2 did not price and\n * which are therefore written to be as close to free as the algebra allows.\n * 3. **The gradient is analytic and costs no extra field evaluations.**\n * `sd_rsupn_grad` is a port of `rsupnFieldAndGradient` — the ≤2.92° normal at\n * the free normal's price. Family C's normal is the closed-form level-set\n * normal (≤4.26°), which is the honest pairing: taking family C means taking\n * family C's gradient too. Being a port, it moves when the value moves:\n * `sd_rsupn` anchors its normalization at the contour radius, so this selects\n * the same arm and differentiates the arm it selected. `test/wgsl-contract.test.ts`\n * pins that pairing, because a normal computed from the unanchored form on top\n * of an anchored depth is exactly the kind of half-applied edit no fingerprint\n * would notice.\n *\n * The union mirrors `union.ts` exactly on the value — the same bulge cap applied\n * to `k`, the same separation gate, the same single clamp at the end of the fold.\n * `union_blend` returns that value **and the blend weight `h`**, because the pass\n * has more than a distance to fold: the gradient and the four per-surface optical\n * scalars have to travel through the same seam, and doing it with the same `h`\n * keeps one copy of the union's algebra instead of four. Blending the gradient by\n * `h` drops the union's term in `dk`, which makes it exact wherever `h` saturates\n * — everywhere except inside a real seam.\n */\n\nimport { WGSL_RSUP, WGSL_RSUPN } from \"@vitrea/geometry\";\n\n/**\n * Instance layout — `@vitrea/geometry`'s `Shape` struct widened by the render\n * channels, 64 bytes, every member 4- or 8-byte aligned so the CPU packing is a\n * flat `Float32Array` with a 16-float stride.\n *\n * `centre/half/re/k0..k4` are the X8 channel vector's geometric half plus the\n * six derived floats. `inset` is rider 2's level-set offset. The rest are motion\n * driver outputs, sampled by the host and handed in as data (§Motion: this\n * package consumes driver outputs, never time).\n */\nexport const WGSL_INSTANCE_STRUCT = `struct Instance {\n centre : vec2f, // 0 group-local CSS px\n half : vec2f, // 8 half-extents of the field's OWN shape (the parent's, for a concentric child)\n re : f32, // 16 corner reach\n k0 : f32, // 20\n k1 : f32, // 24\n k2 : f32, // 28\n k3 : f32, // 32\n k4 : f32, // 36\n inset : f32, // 40 X8 rider 2: level-set offset. 0 for an ordinary surface.\n thick : f32, // 44 material thickness, CSS px\n press : f32, // 48 interaction channel value, 0..1\n glow : f32, // 52 interaction channel value, 0..1\n lensThick : f32, // 56 authored thickness in CSS px times the lensStrength channel (W12 G2): both depths are evaluated from it per pixel\n tintK : f32, // 60 author tint strength, 0..1 — the seed itself is a group uniform\n span : f32, // 64 the surface's shorter extent, CSS px — the size law's input, both curves (W11c)\n mat : f32, // 68 presence, 0..1 (W27d): the slot the 8-byte alignment already required\n};`;\n\n/** `FieldSample` mirrors geometry's, minus `kink`: the shader has no use for it. */\nexport const WGSL_FIELD_SAMPLE = `struct FieldSample {\n d : f32,\n g : vec2f,\n};`;\n\n/**\n * Family D's value and exact gradient in one pass — the port of\n * `rsupnFieldAndGradient`.\n *\n * The masks at the end are what extend the corner-sector chain rule to every\n * region: `mx`/`my` gate the clamped-coordinate terms, and the box-branch term\n * carries the derivative where `max(qx, qy) <= 0`. The `<=` there is not a\n * typo — at `m == 0` both clamped terms are masked off, so the box term has to\n * fire or the gradient reads (0, 0) on the corner-sector boundary. C3 found and\n * fixed exactly that bug while deriving this.\n */\nexport const WGSL_RSUPN_GRAD = `fn sd_rsupn_grad(p : vec2f, half : vec2f, re : f32, k : vec4f, k4 : f32) -> FieldSample {\n let q = abs(p) - half + vec2f(re, re);\n let c = max(q, vec2f(0.0, 0.0));\n let r2 = max(dot(c, c), 1e-20);\n let inv = 1.0 / r2;\n let rho = sqrt(r2);\n let s2 = 2.0 * c.x * c.y * inv;\n let c2 = (c.x * c.x - c.y * c.y) * inv;\n\n // A = sum k_i s2^i, B = sum (i+2) k_i s2^i, C = sum (i+1)(i+2) k_i s2^i.\n var accA = k4;\n accA = accA * s2 + k.w;\n accA = accA * s2 + k.z;\n accA = accA * s2 + k.y;\n accA = accA * s2 + k.x;\n\n var accB = 6.0 * k4;\n accB = accB * s2 + 5.0 * k.w;\n accB = accB * s2 + 4.0 * k.z;\n accB = accB * s2 + 3.0 * k.y;\n accB = accB * s2 + 2.0 * k.x;\n\n var accC = 30.0 * k4;\n accC = accC * s2 + 20.0 * k.w;\n accC = accC * s2 + 12.0 * k.z;\n accC = accC * s2 + 6.0 * k.y;\n accC = accC * s2 + 2.0 * k.x;\n\n let R = re * (1.0 + s2 * s2 * accA);\n let dRds2 = re * s2 * accB;\n let d2Rds2 = re * accC;\n let dRdt = dRds2 * (2.0 * c2);\n\n let mm = min(max(q.x, q.y), 0.0);\n let base = rho + mm - R;\n // Anchored at the contour radius, mirroring sd_rsupn: the normalization's\n // slope is read at the foot of the Newton step, never at a sample radius\n // inside the contour. See geometry's field.ts, \"The normalization\".\n let atRho = rho >= R;\n let w = select(R, rho, atRho);\n let g = select(dRdt / R, dRdt * inv * rho, atRho);\n let norm = sqrt(1.0 + g * g);\n let n = 1.0 / norm;\n\n let ds2dcx = -2.0 * c.y * c2 * inv;\n let ds2dcy = 2.0 * c.x * c2 * inv;\n let dc2dcx = 2.0 * c.x * inv * (1.0 - c2);\n let dc2dcy = -2.0 * c.y * inv * (1.0 + c2);\n\n let drhodcx = c.x / rho;\n let drhodcy = c.y / rho;\n\n let dRdcx = dRds2 * ds2dcx;\n let dRdcy = dRds2 * ds2dcy;\n\n let dTermdcx = 2.0 * (d2Rds2 * ds2dcx * c2 + dRds2 * dc2dcx);\n let dTermdcy = 2.0 * (d2Rds2 * ds2dcy * c2 + dRds2 * dc2dcy);\n\n // w's derivative follows whichever of rho and R is larger. Exact across the\n // switch because the switch locus is rho == R, the contour, where base == 0\n // kills the only term the jump lives in.\n let dwdcx = select(dRdcx, drhodcx, atRho);\n let dwdcy = select(dRdcy, drhodcy, atRho);\n\n let dgdcx = dTermdcx / w - (dRdt * dwdcx) / (w * w);\n let dgdcy = dTermdcy / w - (dRdt * dwdcy) / (w * w);\n\n let n3 = n * n * n;\n let dddcx = (drhodcx - dRdcx) * n + base * (-g * n3 * dgdcx);\n let dddcy = (drhodcy - dRdcy) * n + base * (-g * n3 * dgdcy);\n\n let mx = select(0.0, 1.0, q.x > 0.0);\n let my = select(0.0, 1.0, q.y > 0.0);\n let inBox = max(q.x, q.y) <= 0.0;\n let dmmdqx = select(0.0, 1.0, inBox && q.x >= q.y);\n let dmmdqy = select(0.0, 1.0, inBox && q.y > q.x);\n\n let sx = select(1.0, -1.0, p.x < 0.0);\n let sy = select(1.0, -1.0, p.y < 0.0);\n\n var out : FieldSample;\n out.d = base * n;\n out.g = vec2f((dddcx * mx + n * dmmdqx) * sx, (dddcy * my + n * dmmdqy) * sy);\n return out;\n}`;\n\n/**\n * Family C's value and its closed-form level-set normal.\n *\n * The value is `sd_rsup` verbatim; the normal is\n * `normalize(rhoHat - (R'/rho) * thetaHat)`, which is free because every term is\n * already computed. It is identical to family D's gradient *on* the contour to\n * four decimal places — the normalization moves level sets only away from the\n * zero set — so rim lighting is indifferent between them and only refraction at\n * depth pays the 1.5–1.7× difference.\n */\nexport const WGSL_RSUP_GRAD = `fn sd_rsup_grad(p : vec2f, half : vec2f, re : f32, k : vec4f, k4 : f32) -> FieldSample {\n let q = abs(p) - half + vec2f(re, re);\n let c = max(q, vec2f(0.0, 0.0));\n let r2 = max(dot(c, c), 1e-20);\n let rho = sqrt(r2);\n let s2 = 2.0 * c.x * c.y / r2;\n\n var accA = k4;\n accA = accA * s2 + k.w;\n accA = accA * s2 + k.z;\n accA = accA * s2 + k.y;\n accA = accA * s2 + k.x;\n\n var accB = 6.0 * k4;\n accB = accB * s2 + 5.0 * k.w;\n accB = accB * s2 + 4.0 * k.z;\n accB = accB * s2 + 3.0 * k.y;\n accB = accB * s2 + 2.0 * k.x;\n\n let c2 = (c.x * c.x - c.y * c.y) / r2;\n let R = re * (1.0 + s2 * s2 * accA);\n\n let sx = select(1.0, -1.0, p.x < 0.0);\n let sy = select(1.0, -1.0, p.y < 0.0);\n\n var out : FieldSample;\n out.d = rho + min(max(q.x, q.y), 0.0) - R;\n\n if (c.x <= 0.0 && c.y <= 0.0) {\n // Straight-edge and deep-interior: the normal is the axis the box branch is\n // measuring along.\n out.g = select(vec2f(0.0, sy), vec2f(sx, 0.0), q.x > q.y);\n return out;\n }\n\n let dRdt = re * s2 * accB * (2.0 * c2);\n let rhoHat = c / rho;\n let gg = dRdt / rho;\n let nx = rhoHat.x + gg * rhoHat.y;\n let ny = rhoHat.y - gg * rhoHat.x;\n let len = max(length(vec2f(nx, ny)), 1e-20);\n out.g = vec2f(sx * nx / len, sy * ny / len);\n return out;\n}`;\n\n/**\n * The bounded smooth union of `union.ts`, value for value.\n *\n * `separation * 0.5` is floored away from zero because WGSL's `smoothstep` is\n * undefined when its two edges coincide, where the TypeScript's own `smoothstep`\n * degrades to a step. A group configured with no separation threshold therefore\n * blends everywhere, which is the same thing the TypeScript does.\n */\nexport const WGSL_SMOOTH_UNION = `fn union_blend(a : f32, b : f32, u : vec3f) -> vec2f {\n let neck = u.x;\n let maxBulge = u.y;\n let sep = max(u.z * 0.5, 1e-6);\n\n let nearest = min(a, b);\n let capped = min(neck, 4.0 * maxBulge);\n let gate = 1.0 - smoothstep(0.0, sep, max(nearest, 0.0));\n let k = capped * gate;\n\n if (k <= 0.0) {\n return vec2f(nearest, select(0.0, 1.0, a <= b));\n }\n\n let h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);\n return vec2f(b + h * (a - b) - k * h * (1.0 - h), h);\n}`;\n\n/**\n * The pass itself.\n *\n * Scoped to the group's bounds, never fullscreen: the target IS the group rect,\n * so the fullscreen triangle covers exactly the pixels the group can touch.\n * §Performance envelope prices the field at ~5% of the mobile budget on that\n * assumption, and a fullscreen field pass per group would multiply it by the\n * ratio of viewport area to group area.\n *\n * The output is one `rgba16float` texel per device pixel: signed field in CSS\n * px, the unit normal, and analytic coverage. Everything downstream — optics,\n * highlight, and any future pass — reads this and never re-evaluates the field.\n */\nexport const WGSL_FIELD_PASS = `struct FieldUniforms {\n /// screen.xy = target size in device px, screen.z = CSS px per device px,\n /// screen.w = coverage ramp width in CSS px\n screen : vec4f,\n /// neckWidth, maxBulge, separationThreshold, unused\n unionP : vec4f,\n counts : vec4u,\n};\n\n// Per-surface optical scalars ride through the union in 'aux': the group is one\n// field but its members are not one size, and carrying them per pixel is what\n// lets a 40 px button and a 320 px platter share a field pass and still lens by\n// their own depth — parent acceptance #2 inside a GlassEffectContainer.\n// aux = (lensThickPx, glow, spanPx, tintStrength)\n// aux2 = (p − centre, half.x, half.y) — W12 G2, group-local CSS px\n//\n// The third and fourth slots both changed hands, and neither of the values they\n// used to carry was ever read by a fragment stage. 'thick' left because\n// 'lensDepth' is the thickness times the size gain, so the raw number told the\n// shader nothing the depth had not already said; 'press' left because press\n// compression is resolved on the CPU, as a transform on the surface's own size\n// (instances.ts). Both are still packed into the instance buffer, unchanged, for\n// a future consumer that wants them per pixel; they simply no longer ride here.\n//\n// What replaced them are the two quantities that genuinely have to be per pixel,\n// because a group is one field pass and one optics pass while its members are\n// not one thing:\n//\n// 'spanPx' — the size law's input (W2): the surface's shorter extent in\n// CSS px. A 40 px button and a 320 px platter in one container\n// lens, scatter, occlude and shadow by their own size. Until\n// W11c this slot carried the folded thickness factor itself;\n// the scatter facet now rides a curve with a different band\n// top, so the span travels and each consumer evaluates its own\n// curve from it with the bands and the fold as uniforms.\n// 'tintStrength' — the author tint's strength (W3). One emphasised control\n// among plain ones is the composition Apple's guidance\n// describes; the seed itself is a group uniform.\n//\n// They compose rather than compete: the size law moves what the material does to\n// the backdrop, the tint moves what colour it does it in.\n//\n// One consequence of carrying the span rather than the thickness, stated so it\n// is not mistaken for a drift: the union below blends 'aux' linearly between two\n// members, so a pixel in the neck between a button and a platter now blends\n// their SPANS and evaluates the curves on the blend, where it used to blend the\n// evaluated thicknesses. Inside either member the two are identical; only the\n// smooth-min neck differs, and nothing measured claims a value there.\n//\n// 'aux2' (W12 G2) carries the pixel's offset from the owning surface's centre\n// and that surface's half-extents, which\n// the optics pass needs for the lens's direction: the reference displaces along\n// the gradient of its SDF blended toward the oval inscribed in the shape's box\n// (claims §5.50's 'gradientOvalization'), and an oval is a property of the box,\n// not of the distance field. Blended by the same weight as 'aux' in a neck, so\n// two merged members share one oval there — a value nothing measured either.\n// For a concentric child the box is the parent's (the child is the parent's\n// level set), which is the same centre and a slightly larger oval.\n//\n// 'presence' (W27d) is the fourth target and carries one number: the surface's\n// materialization, blended through the union on the same weight as everything\n// else. It is a target of its own rather than a component of one of the three\n// above because all three are full — the field carries the distance, the normal\n// and the coverage, 'aux' the four optical scalars, 'aux2' the surface's own box\n// — and repurposing a component would mean re-deriving a value the fragment\n// stages read, which is how a golden moves for a reason nobody named. It is\n// r16float rather than the working rgba16float for the same honesty: one scalar\n// costs one channel, and a wave that needs a second widens the format in the one\n// place it is declared ('passes.ts').\n\n@group(0) @binding(0) var<uniform> fu : FieldUniforms;\n@group(0) @binding(1) var<storage, read> instances : array<Instance>;\n\nstruct Member {\n d : f32,\n g : vec2f,\n aux : vec4f,\n aux2 : vec4f,\n mat : f32,\n};\n\nfn eval_instance(i : u32, p : vec2f) -> Member {\n let s = instances[i];\n let k = vec4f(s.k0, s.k1, s.k2, s.k3);\n // X8 rider 2 in one line: the child is the parent's field, shifted. There is\n // no branch and no second path, so no caller can opt into the instantiated\n // shape whose offset error the rider rules out.\n let f = FIELD_FN(p - s.centre, s.half, s.re, k, s.k4);\n var m : Member;\n m.d = f.d + s.inset;\n m.g = f.g;\n m.aux = vec4f(s.lensThick, s.glow, s.span, s.tintK);\n // The pixel relative to the surface's centre, and the half-extents: what the\n // oval's gradient needs, written here where the group-local position is exact.\n m.aux2 = vec4f(p - s.centre, s.half);\n m.mat = s.mat;\n return m;\n}\n\nstruct FieldOut {\n @location(0) field : vec4f,\n @location(1) aux : vec4f,\n @location(2) aux2 : vec4f,\n @location(3) presence : vec4f,\n};\n\n@fragment\nfn fs_field(in : FullscreenOut) -> FieldOut {\n // GROUP-LOCAL CSS px. The instance buffer's centres were already made relative\n // to the group's rect on the CPU (f32 loses resolution at large magnitudes, so\n // a field evaluated at viewport y = 40000 would quantise its own corner), and\n // adding the origin back here would offset every shape by it twice.\n let p = in.uv * fu.screen.xy * fu.screen.z;\n\n var out : FieldOut;\n let count = fu.counts.x;\n if (count == 0u) {\n // Large but FINITE: rgba16float overflows to +Inf past ~65504, and NaN\n // coverage downstream is not reliably zero.\n out.field = vec4f(65000.0, 0.0, -1.0, 0.0);\n out.aux = vec4f(0.0);\n out.aux2 = vec4f(0.0);\n // The idle, not zero: no surface here means nothing to be absent, and a\n // reader that walks off the instances (the outer shadow's offset read) must\n // not find a material it has to fade.\n out.presence = vec4f(1.0, 0.0, 0.0, 0.0);\n return out;\n }\n\n var acc = eval_instance(0u, p);\n var nearest = acc.d;\n for (var i = 1u; i < count; i = i + 1u) {\n let s = eval_instance(i, p);\n let blend = union_blend(acc.d, s.d, fu.unionP.xyz);\n let h = blend.y;\n acc.d = blend.x;\n acc.g = mix(s.g, acc.g, h);\n acc.aux = mix(s.aux, acc.aux, h);\n acc.aux2 = mix(s.aux2, acc.aux2, h);\n acc.mat = mix(s.mat, acc.mat, h);\n nearest = min(nearest, s.d);\n }\n // One clamp at the end of the fold, so |union - min| <= maxBulge holds for any\n // member count and any order rather than per blend step.\n acc.d = max(acc.d, nearest - fu.unionP.y);\n\n let len = max(length(acc.g), 1e-6);\n let normal = acc.g / len;\n let coverage = clamp(0.5 - acc.d / max(fu.screen.w, 1e-6), 0.0, 1.0);\n\n out.field = vec4f(acc.d, normal.x, normal.y, coverage);\n out.aux = acc.aux;\n out.aux2 = acc.aux2;\n out.presence = vec4f(acc.mat, 0.0, 0.0, 0.0);\n return out;\n}`;\n\n/** The field module for one family. `FIELD_FN` is bound at assembly time. */\nexport function fieldPassSource(family: \"rsupn\" | \"rsup\"): string {\n const kernels = family === \"rsupn\" ? [WGSL_RSUPN, WGSL_RSUPN_GRAD] : [WGSL_RSUP, WGSL_RSUP_GRAD];\n const fn = family === \"rsupn\" ? \"sd_rsupn_grad\" : \"sd_rsup_grad\";\n return [\n WGSL_INSTANCE_STRUCT,\n WGSL_FIELD_SAMPLE,\n ...kernels,\n WGSL_SMOOTH_UNION,\n WGSL_FIELD_PASS.replace(\"FIELD_FN\", fn),\n ].join(\"\\n\\n\");\n}\n\n/**\n * Both families' value kernels plus both gradients, with no pass around them.\n *\n * This is what the f32 cross-check compiles: Decision Log #20 makes family C's\n * shipping conditional on its WGSL going through the same check family D passed,\n * and a check that compiled a *different* string from the one the renderer ships\n * would prove nothing. So the pass source above and the harness below are both\n * assembled from these same constants.\n */\nexport const WGSL_FIELD_KERNELS = [\n WGSL_INSTANCE_STRUCT,\n WGSL_FIELD_SAMPLE,\n WGSL_RSUPN,\n WGSL_RSUP,\n WGSL_RSUPN_GRAD,\n WGSL_RSUP_GRAD,\n WGSL_SMOOTH_UNION,\n].join(\"\\n\\n\");\n","/**\n * The highlight pass: specular sweep and press glow.\n *\n * X1 puts this canvas **above** the semantic host DOM, which is the whole reason\n * it is a separate pass and not three more lines in the optics shader: a\n * highlight has to fall across the label, and the label is real DOM sitting\n * between the two canvases. Nothing else about the material does.\n *\n * Both effects are driven by motion-driver *outputs*, never by time (§Motion —\n * the renderer consumes driver values as data):\n *\n * - **`sweep`** ∈ [0, 1] is the shimmer's position along the rim. The band is a\n * Gaussian in the angular coordinate of the gradient, so it travels around the\n * contour rather than sliding across a bounding box, and it exists only where\n * the rim exists.\n * - **`shimmer`** ∈ [0, 1] is that band's amplitude, and it is what makes \"the\n * band is not drawn stationary, it is not drawn\" true rather than aspirational.\n * The angular coordinate covers the whole contour, so there is no phase that\n * means \"not shimmering\" — 0 radians is the left edge, not nowhere — and until\n * W22 the channel's idle 0 parked a band of gain `sweepGain` on the left of\n * every resting surface in both colour schemes (claims §5.90 §4). The gain the\n * CPU packs into `sweep.z` is therefore `sweepGain × shimmer(lead)`: at rest\n * the sweep term is exactly zero and this pass writes nothing, and a driven\n * surface draws the band at its driven phase and amplitude unchanged. Nothing\n * in v1 drives the channel; it is the amplitude a shimmer driver will output\n * when one exists (§Motion). Reduced Motion sets `shimmer: \"none\"`, which the\n * CPU turns into a zero gain by the same seam.\n * - **`glow`** ∈ [0, 1] is the press illumination, from the fast-attack /\n * slow-decay driver. It arrives **per pixel**, unioned through the field pass,\n * multiplied by a radial falloff around the press point and clipped to the\n * surface's coverage so it never leaks past the material's edge.\n *\n * The sweep phase and the press *point* are per group rather than per surface:\n * there is one pointer, and a sweep travelling around a `GlassEffectContainer`'s\n * unioned contour is the behaviour the container exists to produce. v1's\n * components never register two simultaneous presses inside one group.\n *\n * Output is additive over the page: premultiplied with the glow's own alpha, so a\n * zero-intensity highlight writes nothing at all rather than a transparent black\n * that a wrong blend state could darken with.\n */\n\nexport const WGSL_HIGHLIGHT_PASS = `struct HighlightUniforms {\n /// viewport size in device px (xy), CSS px per device px (z), unused (w)\n screen : vec4f,\n /// sweep position 0..1 (x), band width in radians (y), sweep gain (z), rim width px (w)\n sweep : vec4f,\n /// press point in viewport CSS px (xy), glow radius px (z), glow gain (w)\n glow : vec4f,\n /// highlight colour, linear light (xyz), unused (w)\n colour : vec4f,\n /// fieldSize.xy, fieldUpsampled (z), local tone field present (w, W28)\n flags : vec4f,\n /// backdrop tone adaptation (W7), exactly as the optics pass takes it:\n /// backdropToneLow, backdropToneHigh, the size bias already divided by the\n /// accessibility refraction cap, and the resolved strength — zero where there\n /// is no measured backdrop tone, which stands the fade down\n toneAdapt : vec4f,\n /// the backdrop source's own average luminance (x), and the size law's band\n /// and fold — sizeSpanMin (y), sizeSpanMax (z), the accessibility fold (w) —\n /// so this pass evaluates the thickness curve off the per-pixel span exactly\n /// as the optics pass does (W11c: the span rides the field, not the factor)\n toneLevel : vec4f,\n /// this pass's uv into the FIELD texture's uv: scale (xy), offset (zw).\n ///\n /// The identity for a pass whose scissor is the field's own rect, and not the\n /// identity since W8: the outer shadow made the field rect much larger than\n /// anything this pass draws in, so the highlight is scoped back to the rect it\n /// had before and reads the field through this remap instead. Derived from the\n /// two rects by highlightPass in passes.ts.\n fieldFit : vec4f,\n};\n\n@group(0) @binding(0) var<uniform> hu : HighlightUniforms;\n@group(0) @binding(1) var fieldTexture : texture_2d<f32>;\n@group(0) @binding(2) var auxTexture : texture_2d<f32>;\n@group(0) @binding(3) var fieldSampler : sampler;\n/// The surface's presence per pixel (W27d) — the field pass's fourth target,\n/// bound here for the same reason the optics pass binds it: a highlight is the\n/// material catching light, and a material that is not there catches none.\n@group(0) @binding(4) var presenceTexture : texture_2d<f32>;\n@group(0) @binding(5) var localToneTexture : texture_2d<f32>;\n\nconst TAU = 6.283185307179586;\n\n/// Shortest angular distance, so the band wraps continuously past the seam\n/// instead of stalling there for one revolution.\n///\n/// THE RESULT IS FLOORED AT ZERO, AND THE FLOOR IS THE IDENTITY (W31 G2; claims\n/// 5.163). A distance is non-negative, and this expression is only non-negative\n/// while 'raw' stays inside one revolution: past 'TAU' the second branch goes\n/// negative and 'min' takes it. The single caller squares the quotient through\n/// 'pow(x, 2.0)', whose base WGSL leaves UNDEFINED below zero — the same shape\n/// of defect as 5.159b's 'tanh', one function along. Both arguments are angles\n/// only while the sweep phase is inside [0, 1], and the phase is read off a CSS\n/// custom property that nothing clamps (platform-web's 'readHostChannels'\n/// clamps 'materialization' and not 'sweep'), so '--vitrea-sweep: 3' puts the\n/// centre at 3 TAU and this function at -12.6 radians. 'max(., 0)' returns the\n/// same bits at every input the unfloored form was defined at, so no pixel any\n/// material or any bed reaches moves; what it removes is the undefined one.\n/// Where the phase IS out of range the band is now centred on the pixel rather\n/// than NaN, which is a defensible reading of nothing in particular — wrapping\n/// the phase where it is read is the fix that would make it mean something, and\n/// it is outside this gate's contract.\nfn angle_delta(a : f32, b : f32) -> f32 {\n let raw = abs(a - b);\n return max(min(raw, TAU - raw), 0.0);\n}\n\n@fragment\nfn fs_highlight(in : FullscreenOut) -> @location(0) vec4f {\n // Exact load nominally; filtered when the governor's resolution knob had the\n // field rasterised below the group's rect. The sweep rides the rim, which is\n // the one place a nearest read of a coarse field would show its grid.\n let fieldUv = in.uv * hu.fieldFit.xy + hu.fieldFit.zw;\n var field : vec4f;\n var aux : vec4f;\n var presence : vec4f;\n if (hu.flags.z > 0.5) {\n field = textureSampleLevel(fieldTexture, fieldSampler, fieldUv, 0.0);\n aux = textureSampleLevel(auxTexture, fieldSampler, fieldUv, 0.0);\n presence = textureSampleLevel(presenceTexture, fieldSampler, fieldUv, 0.0);\n } else {\n let texel = vec2i(fieldUv * hu.flags.xy);\n field = textureLoad(fieldTexture, texel, 0);\n aux = textureLoad(auxTexture, texel, 0);\n presence = textureLoad(presenceTexture, texel, 0);\n }\n var toneStrength = hu.toneAdapt.w;\n var toneLevel = hu.toneLevel.x;\n if (hu.flags.w > 0.5) {\n if (hu.flags.z > 0.5) {\n toneLevel = textureSampleLevel(localToneTexture, fieldSampler, fieldUv, 0.0).w;\n } else {\n toneLevel = textureLoad(localToneTexture, vec2i(fieldUv * hu.flags.xy), 0).w;\n }\n }\n if (toneLevel < 0.0) { toneStrength = 0.0; }\n let mat = clamp(presence.x, 0.0, 1.0);\n let d = field.x;\n let normal = field.yz;\n let coverage = field.w;\n\n if (coverage <= 0.0) {\n return vec4f(0.0);\n }\n\n // Specular sweep: a travelling band in the rim's angular coordinate.\n let rim = clamp(1.0 - abs(d) / max(hu.sweep.w, 1e-4), 0.0, 1.0);\n let theta = atan2(normal.y, normal.x) + TAU * 0.5;\n let centre = hu.sweep.x * TAU;\n let width = max(hu.sweep.y, 1e-4);\n let band = exp(-pow(angle_delta(theta, centre) / width, 2.0));\n let sweep = rim * rim * band * hu.sweep.z;\n\n // Press glow: radial, in CSS px, clipped by coverage so it cannot leak past\n // the material's edge.\n let posCss = in.position.xy * hu.screen.z;\n let dist = length(posCss - hu.glow.xy);\n let radial = clamp(1.0 - dist / max(hu.glow.z, 1e-4), 0.0, 1.0);\n // 'aux.y' is the per-pixel glow channel, unioned in the field pass, so a group\n // whose members glow independently does not need a pass each.\n let press = radial * radial * hu.glow.w * aux.y;\n\n /*\n * Backdrop tone adaptation (W7) fades this pass with the rest of the surface's\n * own appearance. A highlight is the material catching light, and a material\n * that has taken its backdrop's tone is not there to catch any — the settled\n * reference's capsule over a near-black backdrop is byte-identical to that\n * background, sweep included.\n *\n * The curve is the optics pass's, evaluated the same way off the same uniforms\n * and the same per-pixel 'sizeK', because two statements of one curve is how\n * they drift. This pass would otherwise have gone on drawing a bright crescent\n * around a surface the optics pass had made invisible — measured at 60 pixels\n * past 2/255, peaking at 97/255, on exactly that cell.\n */\n // The thickness curve off the per-pixel span, written out as the optics pass\n // writes it, so the two passes fade on one curve and not on two copies.\n let spanT = clamp(\n (aux.z - hu.toneLevel.y) / max(hu.toneLevel.z - hu.toneLevel.y, 1e-6),\n 0.0,\n 1.0,\n );\n let sizeK = clamp(spanT * spanT * (3.0 - 2.0 * spanT) * hu.toneLevel.w, 0.0, 1.0);\n var toneAdapt = 0.0;\n if (toneStrength > 0.0) {\n let toneX = toneLevel + hu.toneAdapt.z * sizeK;\n let toneT = clamp(\n (toneX - hu.toneAdapt.x) / max(hu.toneAdapt.y - hu.toneAdapt.x, 1e-6),\n 0.0,\n 1.0,\n );\n toneAdapt = clamp(toneStrength, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));\n }\n\n /*\n * The presence (W27d) fades both lights on one factor, exactly as the collapse\n * above fades them: the sweep is the material's own rim catching a travelling\n * light and the glow is the material lit from a press, so neither survives a\n * surface that is not there. It is applied to the composed intensity rather\n * than to each term, because a highlight that fades on two statements of one\n * rule is a highlight that will one day fade on one of them.\n */\n let intensity = clamp(sweep + press, 0.0, 1.0) * coverage * (1.0 - toneAdapt) * mat;\n if (intensity <= 0.0) {\n return vec4f(0.0);\n }\n return encode_output(hu.colour.rgb, intensity);\n}`;\n","/**\n * The optics pass: refraction, adaptive tint, inner shadow, rim and specular —\n * the glass body.\n *\n * Reads the group's two field targets (value + unit normal + coverage, and the\n * per-surface optical scalars) and the backdrop pyramid; writes premultiplied sRGB\n * into the optics canvas over the group's rect. Everything optical happens in\n * linear light and is encoded exactly once, on the way out (X5).\n *\n * The pass is scoped, not fullscreen: the render pass sets its viewport *and* its\n * scissor to the group's device-pixel rect, so `in.uv` runs 0..1 over the group\n * and indexes the group's own field textures one-to-one, while `in.position.xy`\n * stays in canvas device pixels and gives the backdrop coordinate. Nothing outside\n * the group's bounds is touched — §Performance envelope prices the field and\n * optics passes on exactly that assumption.\n *\n * ## The size law, and the four things it moves\n *\n * Parent acceptance #2 asks for the *mechanism*, not a look: \"a larger surface\n * shows deeper shadow and stronger lensing than a small button over the same\n * backdrop.\" Apple states it as one mechanism with four consequences — a larger\n * surface \"casts deeper, richer shadows, has more pronounced lensing and\n * refraction effects, and a softer scattering of light\" (S219), and \"a larger\n * size is more opaque. A smaller size is clearer\" (S284) — so this pass reads one\n * per-pixel number and applies four gains to it.\n *\n * The number is `aux.z`, the surface's span in CSS px, carried **per pixel**\n * through the field pass's union; this pass evaluates `material.ts`'s\n * `sizeThickness(span)` from it, and the scatter facet's own span curve beside\n * it. Since W13 the scattering reads the pixel's own depth under the contour as\n * well (`scatterSharpShare`, claims §5.61 §2): the span curve is the mix deep\n * inside the surface and the ramp is an excursion on it near the contour. The\n * span is what lets a 40 px button and a 320 px platter share one group's field\n * pass and still read as different thicknesses. The occlusion and the inner shadow\n * are applied below, each multiplied by `sizeK`, so both are exactly inert at\n * `sizeK = 0`; the scattering is applied by `kScatter`, which is per pixel and\n * whose floor keeps it at the material's own frost rather than at nothing. The inner\n * shadow's depth is W2's law, kept: `min(thickness * (1 + (gain − 1) * sizeK),\n * span / 2)`, with a square profile on it.\n *\n * ## The lens (W12 G2, claims §5.51)\n *\n * The lens reads its own law since W12 G2 — the reference's, taken from its\n * layer tree (§5.50) and fitted on the pixels (§5.51). Two clamped linear\n * functions of the span give the depth and the magnitude, scaled by the author's\n * thickness over the reference's unit of 8:\n *\n * ```\n * lensDepth = min((thickness / 8) * min(0.25 * span, 20), span / 2) 8 / 11 / 20 on 32 / 44 / ≥ 80\n * S = lensRefractionGain * (thickness / 8) * min(0.8 * span, 60) 44.7 at saturation\n * D(u) = S * max(0, 1 − u / (lensExtentGain * lensDepth)) ^ lensProfileExponent\n * ```\n *\n * One steep power (26.7 px extent, exponent 3.69 on a saturated span): the\n * reference's band is the plate folded from 34 / 24 / 12 px in at 2 / 4 / 8 px\n * from the contour (§5.49). It is the SAME two-component body the interior\n * shows, read at the displaced position — blur before displacement, measured.\n * The direction is not the field's normal alone: the reference ovalizes its SDF\n * gradient (`gradientOvalization`, 0.5 on thick shapes), which magnifies the\n * band *along* the edge by up to 1.31×; so the displacement runs along the\n * gradient of the field blended toward the oval inscribed in the surface's box,\n * `(1 − ω)·n̂ + ω·∇d_oval`, with the magnitude fixed. ω is `lensOvalization` on a\n * thick surface, 0 on a thin one, a smoothstep over the reference's knee at\n * 64–72 px between. The half-extent clamp is what keeps a small control from\n * being all lens: a 24 px-tall button cannot bend more than 12 px of backdrop\n * however thick it is authored — and the magnitude is clamped by the same\n * ratio, so the profile keeps its shape.\n *\n * Every coefficient is advisory and calibration-delegated (C7), named on the CPU.\n *\n * ## The dual cap\n *\n * `refractionScale` arrives as one number the CPU already resolved through\n * `effectiveRefraction(accessibilityCap, stateQuality)` — Decision Log #19's rule\n * that renderers honour the lower of the two caps. The shader never sees them\n * separately, so it cannot honour the wrong one.\n */\n\nexport const WGSL_OPTICS_PASS = `struct OpticsUniforms {\n /// viewport size in device px (xy), CSS px per device px (z), coverage ramp px (w)\n screen : vec4f,\n /// backdrop uv transform on viewport-normalised coords: scale (xy), offset (zw)\n fit : vec4f,\n /// refractionScale, lensRefractionGain (W12 G2: the gain on the reference's\n /// amount law), the inner shadow's depth gain (W2's lensSizeGainMax, which the\n /// shadow keeps), chainMaxLod\n lens : vec4f,\n /// fixed tint colour, linear light (xyz), tint alpha (w)\n tint : vec4f,\n /// adapted tint colour, linear light (xyz), adaptation strength (w)\n adapt : vec4f,\n /// author tint seed, linear light (xyz), tone adaptation under the contrast regime (w)\n seed : vec4f,\n /// the author tint's shade law (W10): tintShadeDark, tintShadeLight,\n /// tintShadeStrength (the profile's provenance gate); and (w) the size law's\n /// accessibility fold — the refraction ladder read at the preference's cap,\n /// which every facet's span-dependent rise is multiplied by (W11c)\n tone : vec4f,\n /// rimWidthPx, rimAlpha; the slots retired by W24 now carry W27c's\n /// tintChromaScale (z) and tintShadeCollapseRetention (w).\n rim : vec4f,\n /// light direction, unit (xy), shadowDepth (z), shadowAlpha (w)\n light : vec4f,\n /// hasBackdrop, fieldSize.xy, fieldUpsampled\n flags : vec4f,\n /// the size law's gains (W2): scatterGainMax — resolved at the group's device\n /// ratio since W15 G1, claims 5.69 section 1 — occlusionGain, shadowGainMax,\n /// bodyChainLod — the last being the chain level whose blur already matches the\n /// body texture, which is what the scattering term measures its octaves from\n size : vec4f,\n /// backdrop tone adaptation (W7): backdropToneLow, backdropToneHigh, the size\n /// bias ALREADY divided by the accessibility refraction cap (so that it may be\n /// multiplied by the policy-folded 'sizeK' below and still mean the geometric\n /// thickness), and the strength the accessibility policy resolved — zero where\n /// the host could not measure a backdrop tone, which stands the axis down\n toneAdapt : vec4f,\n /// the backdrop source's own average colour, linear (xyz), and its luminance (w)\n toneColour : vec4f,\n /// the outer shadow (W8, amplitude re-read by W14 G1): the THIN regime's peak\n /// LINEAR occlusion, already resolved at this group's backdrop luminance and\n /// already folded under the accessibility policy (x) — a linear occlusion and\n /// no longer a compositing alpha, because the shader now blends two regimes\n /// before it converts; the blur's sigma in group-local CSS px (y), the\n /// silhouette's outward spread in the same units (z), and the downward offset\n /// expressed in field-texture UV (w) — a UV so the offset silhouette is one\n /// texture read rather than a gradient extrapolation, which is exact only on a\n /// straight edge and a capsule is mostly not one\n shadow : vec4f,\n /// the outer shadow's size-law gain (x), read against the casting surface's own\n /// thickness, and the field rect's height in CSS px (y) — the conversion the\n /// shadow's shift needs when it lands outside the texture; the body depth\n /// ramp's THICK start (z, W13 G1's third form — the thin end is scatter.y and\n /// this pass mixes the two by the pixel's own sizeThickness), and (w) the\n /// heavy width's gain at the TOP of the scatter span curve, resolved at this\n /// group's device ratio (W15 G1's re-form, claims §5.70 §4 and §7) — the\n /// padding slot this vec4's alignment already required, taken because the\n /// gain's near end (size.x) has no free neighbour and this vec4 already\n /// carries the body ramp's other span-graded end; at dpr 1 it equals size.x\n /// and the grading is flat\n shadowSize : vec4f,\n /// the backdrop tone response's anchors (W9): the three solid anchors'\n /// ENCODED-space means (xyz), and the backdrop's linear-space mean (w) — the\n /// quantity the response solve composites against\n toneAnchor : vec4f,\n /// the response law's thin row: the reference's settled interior levels at the\n /// three anchors for a surface of sizeThickness 0 (xyz); w is the law's\n /// per-profile authority — 0 on dark profiles, whose response is unmeasured\n toneRowThin : vec4f,\n /// the thick row (sizeThickness saturated), xyz as the thin row's; w is the\n /// collapse's transmission (W24 G1), in the padding slot this vec4's alignment\n /// already required — it belongs to the tone block and the tone block's other\n /// three vec4s are full. At 0 the collapse's target is the group's mean\n /// backdrop colour and this pass is W7's to the bit.\n toneRowThick : vec4f,\n /// the size law's bands: the scatter facet's floor (x, resolved at the\n /// group's device ratio since W15 G1 — the deep value is per-scale, claims\n /// 5.69 section 2 — and read here for both the deep curve and the fold) and\n /// the depth ramp's\n /// THIN start s0 at the ratio this group draws at (y, W13 G1 — the CPU has\n /// already interpolated it between the profile's 1x and 2x anchors; the thick\n /// end is shadowSize.z), and the\n /// thickness curve's sizeSpanMin (z) and sizeSpanMax (w); the fold both\n /// multiply by is tone.w. The scatter span curve's own band top is lensOval.w,\n /// and it starts at the same z.\n scatter : vec4f,\n /// the lens law (W12 G2): the reference's height law (lensHeightPerSpan,\n /// lensHeightMax) and amount law (lensAmountPerSpan, lensAmountMax)\n lensLaw : vec4f,\n /// the lens profile (W12 G2): lensExtentGain, lensProfileExponent,\n /// lensOvalization, lensThicknessReference\n lensShape : vec4f,\n /// the ovalization's knee (W12 G2): spanMin (x), spanMax (y); the body depth\n /// ramp's reach in group-local CSS px (z, W13 G1) — the profile names it in\n /// device px and the CPU divides by the ratio, so that this shader can read\n /// the field's own CSS-px depth without a second conversion; the scatter span\n /// curve's band top sizeScatterSpanMax (w, W11c, resolved at the group's\n /// device ratio since W15 G1), which W13 G1 keeps underneath the ramp as its\n /// deep value\n lensOval : vec4f,\n /// the outer shadow's THICK regime (W14 G1): the composite's peak linear\n /// occlusion at casting spans 96, 128 and 160 CSS px (xyz), already folded\n /// under the accessibility policy, piecewise-linear between and held outside;\n /// and (w) the body depth ramp's FAR start (W13 G1's fourth form) — the start\n /// at span >= sizeScatterSpanMax, which the ramp declines to from the thick\n /// end along the scatter span curve, in the slot W14 left free\n shadowThick : vec4f,\n /// the lift (W14 G1), the shadow's second term and GPU-tier only: its peak\n /// amplitude in LINEAR light as a fraction of the blurred backdrop's own\n /// luminance (x), the span rise's foot and top in CSS px (yz), and the chain\n /// LOD whose blur is the profile's liftBlurSigmaCss — resolved on the CPU,\n /// which is the only place the CSS-px-to-texel conversion is knowable, and\n /// already clamped to chainMaxLod (w)\n shadowLift : vec4f,\n /// the rim's amplitude law (W23): the gain on the surface's own rendered\n /// luminance (x), the rim the COLLAPSED appearance keeps — bare (y) and at the\n /// author tint's full coverage (z) — which rises with the adaptation the\n /// scheme's own rim falls with, and how much of an author tint's own colour\n /// the rim's light is spent in (w)\n rimLaw : vec4f,\n /// the lit edge (W24): the axis the rim's directional factor is symmetric\n /// about, unit, viewport coordinates with y down (xy), and the factor's\n /// exponent (z) — 0 leaves the factor at 1 for every normal and the rim\n /// exactly as W23 left it. (w) is the along-side field's slope (W25), in the\n /// slot W24 left free — 0 leaves the factor at 1 at every position.\n rimLit : vec4f,\n /// the thick-span composite (W25; claims 5.113): the heavy share's thick-end\n /// lift on 'sizeThickness', resolved at this group's device ratio (x), and the\n /// level term's gain above the thickness knee (y). Both 0 on the landed\n /// material, so both terms are one multiplication by zero. (z) and (w) free.\n thickSpan : vec4f,\n /// the heavy blur's enable (W26; 'MaterialProfile.sizeHeavyTapSigma', and the\n /// measured cause in claims 5.116 section 2) — 1 where this group's source\n /// carries a heavy texture, 0 where it does not. The WIDTH is not here: the\n /// pyramid blurred it into 'backdropHeavy' before any group was drawn, so all\n /// this pass decides is which of two textures the deep sample comes from.\n /// (y) is the DOM material mode (0 off, 1 unknown tone, 2 measured tone);\n /// (z) and (w) carry its reference level and minimum tint contrast.\n /// Texture draws keep those lanes zero, so their input bytes do not move.\n heavyTap : vec4f,\n /// Decision Log 18's optional fourth response knot: encoded x, thin y,\n /// thick z, and a length gate w. Appended so every three-knot field keeps its\n /// byte offset and its original shader branch.\n toneExtra : vec4f,\n /// W28: whether the per-surface reference field is present (x).\n localTone : vec4f,\n /// W30's span-graded shadow sigma (claims 5.156 section 2): the law's slope\n /// in CSS px of sigma per CSS px of casting span (x), the reference span it\n /// pivots about (y) and the signed floor it is clamped below at, as an offset\n /// from 'shadow.y' (z). (w) free. At the shipped zeros this evaluates to\n /// 'shadow.y' at every span, identically, which is why the 34 goldens do not\n /// move. No device ratio: the cut rejected the device-px reading of the thin\n /// regime, so the law is one function of CSS span on both tiers.\n shadowSigma : vec4f,\n /// W30's scale-selective scatter, candidate (ii) (claims 5.156 section 3): the\n /// gain on 'kScatter' per unit of the source's measured scale statistic (x),\n /// the reference that statistic is measured about (y), and the statistic\n /// itself for THIS group's source (z) — the analysis pass's edge density,\n /// resolved on the CPU because it arrives by readback. (w) free.\n scatterScale : vec4f,\n /// W30's scale-selective scatter, candidate (i) (claims 5.156 section 3): the\n /// second heavy sample's SIGNED share in the deep mix (x), and whether this\n /// group's source carries a second heavy texture at all (y) — 1 where the\n /// pyramid built one, 0 where the share declined it. A vec4 of its own rather\n /// than two lanes in the layout above, on 'heavyTap's precedent: a width's\n /// switch living in another facet's spare lane is a layout nobody could read\n /// back. (z) and (w) free.\n scatterHeavy2 : vec4f,\n /// W31's body chroma retention (claims 5.161 section 5, 5.164): how much of\n /// the blurred backdrop's CHROMATICITY the body restores, at the luma the\n /// tone solve produced (x). A vec4 of its own on W30's rule — 132 is the next\n /// vec4 boundary and an operator packed into the block above would read two\n /// of its neighbour's lanes. (y), (z) and (w) free. At the shipped 0 the mix\n /// below is multiplied by zero and the composite is bit-identical to the one\n /// W30 left, which is why the 34 goldens do not move.\n bodyChroma : vec4f,\n};\n\n@group(0) @binding(0) var<uniform> ou : OpticsUniforms;\n@group(0) @binding(1) var fieldTexture : texture_2d<f32>;\n@group(0) @binding(2) var auxTexture : texture_2d<f32>;\n@group(0) @binding(3) var backdropSampler : sampler;\n@group(0) @binding(4) var backdropChain : texture_2d<f32>;\n@group(0) @binding(5) var backdropBody : texture_2d<f32>;\n@group(0) @binding(6) var fieldSampler : sampler;\n/// The owning surface's box per pixel (W12 G2): the pixel's offset from its\n/// centre (xy) and its half-extents (zw), group-local CSS px — the lens's oval.\n@group(0) @binding(7) var aux2Texture : texture_2d<f32>;\n\n/// The heavy blur (W26) — the backdrop taken to the profile's heavy width by the\n/// pyramid's own separable passes, at the extent of the chain level it was built\n/// from. Bound at every draw; read only where 'heavyTap.x' says there is one.\n@group(0) @binding(8) var backdropHeavy : texture_2d<f32>;\n\n/// The surface's PRESENCE per pixel (W27d; contract X6): the 'materialization'\n/// channel, unioned in the field pass like every other per-surface scalar. One\n/// channel, in the field pass's fourth target — see 'wgsl/field.ts'.\n@group(0) @binding(9) var presenceTexture : texture_2d<f32>;\n@group(0) @binding(10) var localToneTexture : texture_2d<f32>;\n\n/// The SECOND heavy blur (W30 G2) — the same construction one width along, and\n/// read only where 'scatterHeavy2.y' says the pyramid built one. A bind group's\n/// layout is one layout, so the slot exists at every draw and the placeholder\n/// view stands in it where the material declined the operator; what costs\n/// nothing at the inert share is the allocation and the two separable passes,\n/// which is where the price of this mechanism actually is (W26 Decision Log\n/// 2 (b)).\n@group(0) @binding(11) var backdropHeavy2 : texture_2d<f32>;\n\n/// One encoded sRGB channel from a linear one — the space the backdrop tone\n/// response's anchors live in (W9). Mirrors material.ts's 'linearToSrgbChannel'.\nfn srgb_encode(c : f32) -> f32 {\n let x = clamp(c, 0.0, 1.0);\n return select(1.055 * pow(x, 1.0 / 2.4) - 0.055, x * 12.92, x <= 0.0031308);\n}\n\n/// The backdrop tone response R(encodedInput, sizeK) (W9): monotone\n/// (Fritsch–Carlson) interpolation through the three anchors, clamped to their\n/// span; smoothstep between the thin and thick rows. Mirrors material.ts's\n/// 'backdropToneResponse' term for term — the constants are authored there.\nfn tone_response(x : f32, sizeK : f32, levelFar : f32) -> f32 {\n let f = sizeK * sizeK * (3.0 - 2.0 * sizeK);\n let ys = mix(ou.toneRowThin.xyz, ou.toneRowThick.xyz, vec3f(f));\n let xs = ou.toneAnchor.xyz;\n if (ou.toneExtra.w > 0.5) {\n let ys4 = vec4f(ys, mix(ou.toneExtra.y, ou.toneExtra.z, f));\n let xs4 = vec4f(xs, ou.toneExtra.x);\n let xc4 = clamp(x, xs4.x, xs4.w);\n let h0 = max(xs4.y - xs4.x, 1e-4);\n let h1 = max(xs4.z - xs4.y, 1e-4);\n let h2 = max(xs4.w - xs4.z, 1e-4);\n let d0 = (ys4.y - ys4.x) / h0;\n let d1 = (ys4.z - ys4.y) / h1;\n let d2 = (ys4.w - ys4.z) / h2;\n var m1 = 0.0; var m2 = 0.0;\n if (d0 * d1 > 0.0) { m1 = 2.0 * d0 * d1 / (d0 + d1); }\n if (d1 * d2 > 0.0) { m2 = 2.0 * d1 * d2 / (d1 + d2); }\n var h = h0; var t = (xc4 - xs4.x) / h0;\n var y0 = ys4.x; var y1 = ys4.y; var s0 = d0; var s1 = m1;\n if (xc4 > xs4.y) {\n h = h1; t = (xc4 - xs4.y) / h1;\n y0 = ys4.y; y1 = ys4.z; s0 = m1; s1 = m2;\n }\n if (xc4 > xs4.z) {\n h = h2; t = (xc4 - xs4.z) / h2;\n y0 = ys4.z; y1 = ys4.w; s0 = m2; s1 = d2;\n }\n return y0 * (1.0 + 2.0 * t) * (1.0 - t) * (1.0 - t)\n + s0 * h * t * (1.0 - t) * (1.0 - t)\n + y1 * t * t * (3.0 - 2.0 * t)\n + s1 * h * t * t * (t - 1.0)\n + levelFar;\n }\n let xc = clamp(x, xs.x, xs.z);\n let h0 = max(xs.y - xs.x, 1e-4);\n let h1 = max(xs.z - xs.y, 1e-4);\n let d0 = (ys.y - ys.x) / h0;\n let d1 = (ys.z - ys.y) / h1;\n // The interior slope: the harmonic mean where the secants agree, 0 across a\n // sign change — what keeps the curve monotone between monotone anchors.\n var m1 = 0.0;\n if (d0 * d1 > 0.0) { m1 = 2.0 * d0 * d1 / (d0 + d1); }\n var h = h0; var t = (xc - xs.x) / h0;\n var y0 = ys.x; var y1 = ys.y; var s0 = d0; var s1 = m1;\n if (xc > xs.y) {\n h = h1; t = (xc - xs.y) / h1;\n y0 = ys.y; y1 = ys.z; s0 = m1; s1 = d1;\n }\n // 'levelFar' is W25's level term above the thickness knee (claims 5.113; W25\n // Decision Log 3 (b)) - an OFFSET on the settled level this curve returns, in\n // its own encoded units, and not a continuation of the thin-to-thick blend\n // above. The rows chose the shape: the residual against vitrea above span 96\n // is backdrop-INDEPENDENT where the blend's direction is different at every\n // backdrop level (G2 'fit-level.txt'). Exactly 0 at and below sizeSpanMax by\n // the shape of its span curve, and 0 at every span on the landed material.\n return y0 * (1.0 + 2.0 * t) * (1.0 - t) * (1.0 - t)\n + s0 * h * t * (1.0 - t) * (1.0 - t)\n + y1 * t * t * (3.0 - 2.0 * t)\n + s1 * h * t * t * (t - 1.0)\n + levelFar;\n}\n\n/// Rim proximity: 1 exactly on the contour, falling to 0 by 'width' on either\n/// side. Symmetric, so the rim is a band on the boundary rather than a plateau\n/// that keeps burning outward where coverage has already faded.\nfn rim_weight(d : f32, width : f32) -> f32 {\n let t = clamp(1.0 - abs(d) / max(width, 1e-4), 0.0, 1.0);\n return t * t;\n}\n\n/// The Gaussian CDF the outer shadow's edge falls off by: 1 deep inside the\n/// shadow's silhouette, 0.5 exactly on it, 0 far outside. The tanh form of the\n/// normal CDF — WGSL has no erf, and this is within 1.8e-4 of it everywhere,\n/// which is 0.015 of one 8-bit code at the shipped occlusion. Mirrors\n/// material.ts's 'outerShadowFalloff' term for term.\n///\n/// THE ARGUMENT IS CLAMPED, AND THE CLAMP IS THE IDENTITY (W30 G3b; claims\n/// 5.159b, corrected at 5.159b section 10). 'tanh' saturates to exactly 1.0 in\n/// f32 by |t| = 9.011 and in f64 by |t| = 19.061547465398498 — measured, not\n/// 18.2, which the first recording of this comment said and which is the last\n/// magnitude that still returns 1 - 1e-16. Either way 20 is above both, so\n/// replacing every |t| > 20 with 20 returns the same bits in both precisions at\n/// every input the unclamped form evaluates finitely; the bound has 0.94 of\n/// margin over f64 rather than 1.8, which is what the corrected reading\n/// changes. What it\n/// removes is a NaN: a backend that lowers 'tanh' to (exp(2t) - 1)/(exp(2t) + 1)\n/// — which Metal's fast-math path does — overflows f32's 'exp' at 2t > 88.72 and\n/// hands back Inf/Inf. The cubic makes that threshold reachable at a modest\n/// distance: t passes 44.36 at x ~ 10.06, so any pixel more than about 10 sigma\n/// inside the shadow's silhouette returned NaN, and the NaN travelled into the\n/// composite's alpha through 'shadowAlpha * (1 - coverage)', where a coverage of\n/// exactly 1 does not stop it (NaN times 0 is NaN). At every sigma the project\n/// had shipped, 10 sigma was further than any caster is deep and nothing reached\n/// it; macOS 27's thin regime draws sigma 2.13 at a span-44 caster, where 10\n/// sigma is 21.4 CSS px and a 44 px capsule's own centre line is 25 CSS px\n/// inside its silhouette — which is the strip 5.159 section 6 measured.\nfn outer_shadow_falloff(signedDistance : f32, sigma : f32) -> f32 {\n let x = -signedDistance / max(sigma, 1e-4);\n let t = clamp(0.7978845608028654 * (x + 0.044715 * x * x * x), -20.0, 20.0);\n return 0.5 * (1.0 + tanh(t));\n}\n\n/// The outer shadow's sigma at a casting span, CSS px (W30 G2; claims 5.156\n/// section 2). Mirrors material.ts's 'outerShadowSigmaPx' term for term:\n///\n/// sigma(span) = shadow.y + max(shadowSigma.z, shadowSigma.x * (span - shadowSigma.y))\n///\n/// Read PER PIXEL from the CASTING surface's own span, which the field pass has\n/// already unioned into the aux target — the span this shader has been reading\n/// the thick regime's amplitude from since W14 G1, now read twice. At the\n/// shipped zeros both arms of the max are zero and this is 'ou.shadow.y'\n/// exactly, for every span, which makes the law's landing a no-op on every\n/// existing pixel by construction rather than by measurement.\nfn outer_shadow_sigma(spanCss : f32) -> f32 {\n return ou.shadow.y\n + max(ou.shadowSigma.z, ou.shadowSigma.x * (spanCss - ou.shadowSigma.y));\n}\n\n/// What one pixel's outer shadow is made of: the compositing-space alpha the\n/// black term composites at, the falloff BOTH terms ride, and the span of the\n/// surface that cast it — which the lift's own rise is read from.\n///\n/// One struct rather than three calls because there is one falloff (W14 G0,\n/// claims §5.62 §4): the black term's free fit and the lift's free fit return\n/// the same sigma, offset and spread, so evaluating a second geometry for the\n/// second term would be asserting a difference the measurement denies.\nstruct ShadowSample {\n alpha : f32,\n falloff : f32,\n castSpanCss : f32,\n /// The presence of the surface that CAST the shadow (W27d), read at the offset\n /// position beside its span. A shadow belongs to the surface above it, so it\n /// fades with that surface's materialization and not with the one under this\n /// pixel — which is a real difference wherever a dissolving surface's shadow\n /// falls across a present one.\n castMat : f32,\n};\n\n/// The composite's peak linear occlusion above the knee, at a casting span —\n/// piecewise linear through the three measured anchors (96 / 128 / 160 CSS px)\n/// and held flat outside them. Mirrors material.ts's\n/// 'outerShadowThickOcclusion'.\nfn outer_shadow_thick(spanCss : f32) -> f32 {\n let y = ou.shadowThick.xyz;\n if (spanCss <= 96.0) { return y.x; }\n if (spanCss >= 160.0) { return y.z; }\n if (spanCss <= 128.0) { return y.x + (y.y - y.x) * (spanCss - 96.0) / 32.0; }\n return y.y + (y.z - y.y) * (spanCss - 128.0) / 32.0;\n}\n\n/// The outer shadow's alpha at this pixel (W8, amplitude W14 G1).\n///\n/// The shadow is the group's OWN field, translated down by 'shadow.w' in field\n/// UV and outset by 'shadow.z', then blurred. Reading the offset silhouette from\n/// the field texture rather than extrapolating the local distance along the\n/// normal is what keeps a corner a corner: the first-order estimate is exact only\n/// on a straight edge, and a capsule is mostly not one.\n///\n/// The value is an ALPHA on pure black, so what it composites to is the backdrop\n/// times '1 - alpha' — multiplicative occlusion, and exactly zero over black,\n/// with no branch for it.\nfn outer_shadow(uv : vec2f, upsampled : f32, fieldSize : vec2f) -> ShadowSample {\n var out : ShadowSample;\n out.alpha = 0.0;\n out.falloff = 0.0;\n out.castSpanCss = 0.0;\n out.castMat = 1.0;\n if (ou.shadow.x <= 0.0 && ou.shadowThick.x <= 0.0) {\n return out;\n }\n /*\n * The shift can leave the field texture, and clamping alone reads a lie there.\n *\n * Two ways it happens, and the second is not an edge case: the rect is clipped\n * to the canvas, so a surface within the shadow's reach of the viewport's TOP\n * has no rows above it to shift into; and even unclipped, the rect's pad is the\n * shadow's reach, so the topmost band of every group needs rows a further\n * 'offset' above that. Clamped, both repeat the edge texel — a distance that is\n * too SMALL, which reads as a flat, too-dark falloff exactly where the shadow\n * should be fading out, and diverges from the CSS tier, which has no texture to\n * run out of.\n *\n * Reconstructed instead of clamped. A signed distance field is 1-Lipschitz, and\n * in the region this happens in — directly above the surface — moving away from\n * it increases the distance by exactly the displacement. So adding back the\n * distance that was clamped off is exact there, and past the surface's corners\n * it over-estimates, which errs toward LESS shadow rather than more.\n */\n let shiftedY = uv.y - ou.shadow.w;\n let clampedOffCss =\n (max(0.0, -shiftedY) + max(0.0, shiftedY - 1.0)) * ou.shadowSize.y;\n let shadowUv = clamp(vec2f(uv.x, shiftedY), vec2f(0.0), vec2f(1.0));\n var shadowField : vec4f;\n var shadowAux : vec4f;\n var shadowPresence : vec4f;\n if (upsampled > 0.5) {\n shadowField = textureSampleLevel(fieldTexture, fieldSampler, shadowUv, 0.0);\n shadowAux = textureSampleLevel(auxTexture, fieldSampler, shadowUv, 0.0);\n shadowPresence = textureSampleLevel(presenceTexture, fieldSampler, shadowUv, 0.0);\n } else {\n let texel = clamp(vec2i(shadowUv * fieldSize), vec2i(0), vec2i(fieldSize) - vec2i(1));\n shadowField = textureLoad(fieldTexture, texel, 0);\n shadowAux = textureLoad(auxTexture, texel, 0);\n shadowPresence = textureLoad(presenceTexture, texel, 0);\n }\n let castMat = clamp(shadowPresence.x, 0.0, 1.0);\n\n // The size law reaches the amplitude and nothing else — the reference's three\n // lengths are span-invariant across 32…160 px. Every span-keyed quantity here\n // rides the thickness and the span of the surface that CAST the shadow, which\n // is the one read at the offset position rather than the one under the pixel\n // being shaded.\n //\n // The thickness curve off the casting surface's span (W11c: the span rides\n // the field), written as the body's own is below.\n let castT = clamp(\n (shadowAux.z - ou.scatter.z) / max(ou.scatter.w - ou.scatter.z, 1e-6),\n 0.0,\n 1.0,\n );\n let sizeK = clamp(castT * castT * (3.0 - 2.0 * castT) * clamp(ou.tone.w, 0.0, 1.0), 0.0, 1.0);\n\n // The two regimes and the knee between them (W14 G1). The thin amplitude is\n // resolved on the CPU because its key — the backdrop's luminance — is one\n // number for the whole group; the thick one is a span law and has to be per\n // pixel. The blend is the smoothstep of 'sizeK', which is exactly the curve\n // 'tone_response' blends its own thin and thick rows across: one knee for the\n // face and the shadow, which is the charter's third binding rule read from\n // the other side.\n let blend = sizeK * sizeK * (3.0 - 2.0 * sizeK);\n let regime = mix(ou.shadow.x, outer_shadow_thick(shadowAux.z), blend);\n // The size gain, on the relative form 'sizeOuterShadowOcclusionAt' uses, in\n // LINEAR light; then the one conversion to the canvas's compositing space,\n // which is where the black term is actually composited.\n let occ = clamp(regime + ou.shadowSize.x * sizeK * (1.0 - regime), 0.0, 1.0);\n // Times the casting surface's presence (W27d): a material that is not there\n // occludes nothing. At presence 1 this is the alpha the bed measures.\n out.alpha = (1.0 - pow(1.0 - occ, 1.0 / 2.4)) * castMat;\n out.falloff = outer_shadow_falloff(\n shadowField.x + clampedOffCss - ou.shadow.z,\n outer_shadow_sigma(shadowAux.z),\n );\n out.castSpanCss = shadowAux.z;\n out.castMat = castMat;\n return out;\n}\n\n/// The lift (W14 G1) — the shadow's second term, in LINEAR light, premultiplied\n/// by nothing yet: a blurred copy of the backdrop's own light, at an amplitude\n/// that is zero below the knee and saturating above it, on the SAME falloff the\n/// black term rides.\n///\n/// 'V' is the backdrop chain read at the pixel's OWN position — the copy is of\n/// the backdrop beneath the shadow, not of the backdrop under the surface — at\n/// the LOD whose blur is the profile's 40 CSS px. The chain's uv transform is on\n/// viewport-normalised coordinates, so every pixel this pass draws has a valid\n/// sample: unlike the field texture, which the offset shift can walk off the top\n/// of, the chain covers the whole viewport and there is nothing to reconstruct.\n///\n/// Zero over black by construction (V = 0), zero below the knee by the rise, and\n/// zero where the group has no backdrop to copy — so 'dark-solid', 'impulse',\n/// every thin cell and every unsampled group stay byte-for-byte what they were.\nfn outer_shadow_lift(viewport01 : vec2f, shadow : ShadowSample) -> vec3f {\n if ((ou.flags.x <= 0.5 && ou.heavyTap.y < 1.5) ||\n ou.shadowLift.x <= 0.0 || shadow.falloff <= 0.0) {\n return vec3f(0.0);\n }\n // Written out rather than through WGSL's 'smoothstep', which is undefined\n // where the two edges coincide — a profile is entitled to set the rise's foot\n // and top to one number, and material.ts's own 'smoothstep' degrades that to a\n // step rather than to a NaN. Same rule as the tone band's divide above.\n let riseT = clamp(\n (shadow.castSpanCss - ou.shadowLift.y) / max(ou.shadowLift.z - ou.shadowLift.y, 1e-6),\n 0.0,\n 1.0,\n );\n let rise = riseT * riseT * (3.0 - 2.0 * riseT);\n if (rise <= 0.0) {\n return vec3f(0.0);\n }\n if (ou.flags.x <= 0.5) {\n // A DOM page has no exterior texture: this is the law at the stated tone,\n // not a claim to reproduce the colour or structure beyond the silhouette.\n return ou.toneColour.rgb * (ou.shadowLift.x * rise * shadow.falloff);\n }\n let uv = clamp(viewport01 * ou.fit.xy + ou.fit.zw, vec2f(0.0), vec2f(1.0));\n let chainSample = textureSampleLevel(backdropChain, backdropSampler, uv, ou.shadowLift.w);\n // Premultiplied linear in, straight colour out — the same unpremultiply the\n // body's own samples take, for the same reason: a partially transparent\n // backdrop must not darken what the material adds back.\n let v = chainSample.rgb / max(chainSample.a, 1e-6);\n // The black term's presence, on the shadow's second term: the two are one\n // shadow with one falloff (W14 G0), so one channel fades both.\n return v * (ou.shadowLift.x * rise * shadow.falloff * shadow.castMat);\n}\n\n/// The DOM branch is the per-pixel mirror of platform-web's materialAtBackdrop.\n/// It evaluates the linear response, collapse, paint and rim at the stated tone,\n/// then solves the encoded layer the browser composites. A union's span stays\n/// per pixel, and the conversion reference never enables an unknown tone.\nfn dom_material_backdrop() -> vec3f {\n if (ou.heavyTap.y > 1.5) { return ou.toneColour.rgb; }\n return vec3f(ou.heavyTap.z);\n}\n\n/// The cssTintAlpha secant, at the actual tone rather than before the response.\nfn dom_material_alpha(composite : vec3f, backdrop : vec3f, alpha : f32) -> f32 {\n if (alpha <= 1e-6) { return 0.0; }\n let weights = vec3f(0.2126, 0.7152, 0.0722);\n let neutral = max((composite - backdrop * (1.0 - alpha)) / alpha, vec3f(0.0));\n let b = srgb_encode(dot(backdrop, weights));\n let span = srgb_encode(dot(neutral, weights)) - b;\n if (abs(span) < ou.heavyTap.w) { return alpha; }\n return clamp((srgb_encode(dot(composite, weights)) - b) / span, 0.0, 1.0);\n}\n\n/// The final encoded solve, including paint and contour light. The least opacity\n/// needed to keep every channel in gamut is an algebraic constraint, not a fit.\n/// At the reference B this returns E(C) exactly after browser source-over; away\n/// from B the scalar layer cannot reproduce the sampled path's local structure.\nfn dom_material_output(encodedComposite : vec3f, encodedBackdrop : vec3f, alpha : f32) -> vec4f {\n let c = clamp(encodedComposite, vec3f(0.0), vec3f(1.0));\n let b = clamp(encodedBackdrop, vec3f(0.0), vec3f(1.0));\n let need = select((b - c) / max(b, vec3f(1e-6)),\n (c - b) / max(vec3f(1.0) - b, vec3f(1e-6)), c >= b);\n let a = clamp(max(alpha, max(need.x, max(need.y, need.z))), 0.0, 1.0);\n return vec4f(clamp(c - b * (1.0 - a), vec3f(0.0), vec3f(a)), a);\n}\n\n/// W31 — the body's chroma retention, at a held linear luma (claims 5.161\n/// section 5, fitted in 5.164).\n///\n/// The body is a neutral plate over the blurred backdrop, so what a\n/// photograph's hues survive the composite at is '1 - sizedAlpha'. This\n/// restores the colour's CHROMATICITY toward the blurred backdrop's, carried to\n/// the colour's OWN linear luma, by the material's retention.\n///\n/// **Luma is held by construction rather than by correction.** Both endpoints\n/// of the mix have linear luma exactly 'Y' — 'colour' by definition and\n/// 'target' because it is the backdrop scaled to 'Y' — and linear luma is a\n/// linear functional, so the mix has luma 'Y' in exact arithmetic. The\n/// renormalisation afterwards is an f32 rounding guard and nothing else.\n///\n/// Gamut by scaling chroma toward the neutral AT that luma, never by clipping\n/// per channel: a per-channel clamp moves the level, which is the one thing\n/// this operator may not do.\n///\n/// The retention is the identity outside 'Y' in (1e-6, 1], which is a\n/// finiteness guard rather than a restriction: 'backdrop' and 'adapted' are both\n/// in [0, 1] and 'presentAlpha' is in [0, 1], so their mix is too. Writing it as\n/// a branch on the retention as well makes the identity at 0 EXACT — no\n/// division, no rounding, the composite left as it arrived.\nfn gamut_at_luma(c : vec3f, Y : f32) -> vec3f {\n var t = 1.0;\n for (var i = 0u; i < 3u; i = i + 1u) {\n let d = c[i] - Y;\n if (d > 1e-7) { t = min(t, (1.0 - Y) / d); }\n else if (d < -1e-7) { t = min(t, -Y / d); }\n }\n return mix(vec3f(Y), c, clamp(t, 0.0, 1.0));\n}\n\nfn body_chroma_retention(colour : vec3f, backdrop : vec3f, retention : f32) -> vec3f {\n if (retention <= 0.0) { return colour; }\n let W = vec3f(0.2126, 0.7152, 0.0722);\n let Y = dot(colour, W);\n if (!(Y > 1e-6 && Y <= 1.0)) { return colour; }\n let Yb = dot(backdrop, W);\n if (Yb <= 1e-6) { return colour; }\n // 'toward' and not 'target': WGSL reserves the latter.\n let toward = backdrop * (Y / Yb);\n var restored = mix(colour, toward, clamp(retention, 0.0, 1.0));\n let Yr = dot(restored, W);\n if (Yr > 1e-6) { restored = restored * (Y / Yr); }\n return gamut_at_luma(restored, Y);\n}\n\n@fragment\nfn fs_optics(in : FullscreenOut) -> @location(0) vec4f {\n // Nominally the field is one texel per device pixel, so the read is an exact\n // load and no filter touches the distance or the normal. Under the governor's\n // 'refractionResolutionScale' the field was rasterised smaller than the group's\n // rect, and then it has to be filtered: a nearest read would quantise the\n // contour to the coarse grid and the rim would step along it.\n var field : vec4f;\n var aux : vec4f;\n var aux2 : vec4f;\n var presence : vec4f;\n if (ou.flags.w > 0.5) {\n field = textureSampleLevel(fieldTexture, fieldSampler, in.uv, 0.0);\n aux = textureSampleLevel(auxTexture, fieldSampler, in.uv, 0.0);\n aux2 = textureSampleLevel(aux2Texture, fieldSampler, in.uv, 0.0);\n presence = textureSampleLevel(presenceTexture, fieldSampler, in.uv, 0.0);\n } else {\n let texel = vec2i(in.uv * ou.flags.yz);\n field = textureLoad(fieldTexture, texel, 0);\n aux = textureLoad(auxTexture, texel, 0);\n aux2 = textureLoad(aux2Texture, texel, 0);\n presence = textureLoad(presenceTexture, texel, 0);\n }\n\n // The complete reference changes together: response, collapse colour and\n // compensation, nominal composition, opacity solve, and the tint/rim readouts.\n // The source branch retains the old uniforms and arithmetic exactly.\n var toneStrength = ou.toneAdapt.w;\n var toneColour = ou.toneColour;\n var toneLinearMean = ou.toneAnchor.w;\n if (ou.localTone.x > 0.5) {\n if (ou.flags.w > 0.5) {\n toneColour = textureSampleLevel(localToneTexture, fieldSampler, in.uv, 0.0);\n } else {\n toneColour = textureLoad(localToneTexture, vec2i(in.uv * ou.flags.yz), 0);\n }\n toneLinearMean = dot(toneColour.rgb, vec3f(0.2126, 0.7152, 0.0722));\n // A fully transparent mask measured no colour and has no local authority.\n if (toneColour.w < 0.0) {\n toneStrength = 0.0;\n toneColour = ou.toneColour;\n toneLinearMean = ou.toneAnchor.w;\n }\n }\n\n let d = field.x;\n let normal = field.yz;\n let coverage = field.w;\n /*\n * The surface's PRESENCE at this pixel (W27d; contract X6) — the\n * 'materialization' channel, 1 on a surface nobody is driving.\n *\n * It multiplies every term the material ADDS to what is behind it: the lens's\n * depth and magnitude, the body's mix away from the unblurred backdrop, the\n * material's own alpha, the author tint's coverage, the inner shadow, the rim,\n * the outer shadow and the highlight pass's light. It does NOT multiply the\n * coverage: a presence spent there would be a crossfade of the whole composite,\n * which is the alpha Apple's rule rules out (\"prefer setting the effect\n * property over the alpha\") and which the runtime cannot afford either — the\n * host that wrote it would form a Backdrop Root and lose the group's sampling.\n *\n * Not to be confused with 'present' below, which is what survives the backdrop\n * COLLAPSE. The two multiply many of the same terms and mean different things:\n * one is the author's presence, the other is the material having taken its\n * backdrop's tone. Both are one multiplication by one on the resting bed.\n *\n * The channel is strictly ABOVE zero here. Exactly 0 is 'Glass.identity' and is\n * resolved on the CPU by dropping the member before this pass ever runs\n * ('instances.ts'), so a surface that is not there has no silhouette to draw a\n * faded material into and no shape to union with its neighbours. What this\n * shader owns is the continuum between the endpoints.\n */\n let mat = clamp(presence.x, 0.0, 1.0);\n\n /*\n * The outer shadow (W8) sits UNDER the material, so it is resolved before the\n * body and carried into the output's alpha rather than into its colour: the\n * pass writes premultiplied black there, and premultiplied black over the page\n * IS the multiplication. Outside the contour that is the whole of what this\n * pixel is; inside it the surface covers the shadow, exactly as a 'box-shadow'\n * is clipped out of its own border box, and the two meet across the coverage\n * ramp with no seam because it is one expression.\n */\n let shadowSample = outer_shadow(in.uv, ou.flags.w, ou.flags.yz);\n let shadowAlpha = shadowSample.alpha * shadowSample.falloff;\n let viewport01 = in.position.xy / ou.screen.xy;\n // Resolved once, for both sides of the coverage ramp: the lift fills exactly\n // what the surface's coverage leaves, on the same rule and in the same\n // expression as the black term's alpha at the bottom of this function, so the\n // two meet across the ramp with no seam. At full coverage it is not computed\n // at all and the chain read is not taken.\n var liftEncoded = vec3f(0.0);\n if (coverage < 1.0) {\n let lift = outer_shadow_lift(viewport01, shadowSample);\n liftEncoded = min(linear_to_srgb(max(lift, vec3f(0.0))), vec3f(shadowAlpha));\n }\n if (coverage <= 0.0) {\n /*\n * The lift (W14 G1) makes this a premultiplied COMPOSITE rather than an\n * alpha on black: the compositor produces 'page·(1 − shadowAlpha) + lift',\n * which is the reference's own two-term form outside the coverage.\n *\n * The added light is computed in linear light and encoded on its own before\n * it is emitted, because it IS its own light — over the checkerboard's black\n * squares, where the multiply is inert, what the reference adds is exactly\n * this term and nothing else, and encoding it alone reproduces G0's measured\n * +0.048 encoded at span 160 from its +0.0038 linear (claims §5.62 §2, §3).\n * Where the backdrop is bright the encoding of a sum and the sum of the\n * encodings differ, and this term is the second: the residual is bounded by\n * the term's own size and is well inside the bed's ±4/255, on the same\n * honest-floor argument 'outerShadowAlpha' makes for the black term's space.\n *\n * A premultiplied layer may not carry a channel above its own alpha, so the\n * emitted light is capped at 'shadowAlpha'. At the profile's constants the\n * cap is inert everywhere on the falloff: both terms are proportional to the\n * same F, and the lift's encoded value stays at about a sixth of the black\n * term's alpha from the deepest ring out to where the shadow stops moving a\n * code. It is here so that a swept amplitude produces a valid layer rather\n * than an implementation-defined one.\n */\n return vec4f(liftEncoded, shadowAlpha);\n }\n\n let viewportCss = ou.screen.xy * ou.screen.z;\n\n // Per-pixel, unioned through the field pass. See the module note. 'aux.x' is\n // the authored thickness times the lensStrength channel (W12 G2); the lens's\n // depth and the inner shadow's are both evaluated from it and the span below.\n //\n // Times the presence (W27d), because this is the one number Apple's own\n // description of materializing names — \"by gradually modulating the light\n // bending and lensing\" — and both depths are functions of it, so the lens\n // shallows and weakens together and the inner shadow's depth follows the same\n // channel rather than a second statement of it.\n let lensThick = max(aux.x, 0.0) * mat;\n // The thickness curve off the span of whichever surface owns this pixel\n // (W11c). 'sizeK' is the thickness factor, 0..1: zero on anything at or below\n // the profile's 'sizeSpanMin', saturated at 'sizeSpanMax', folded under the\n // preference — the occlusion, the inner shadow and the tone response multiply\n // by it, so a small control takes the pre-law path exactly. Written out as a\n // smoothstep with a guarded denominator, so a profile that collapses the band\n // degrades to a step rather than to NaN.\n let span = aux.z;\n let fold = clamp(ou.tone.w, 0.0, 1.0);\n let thickT = clamp((span - ou.scatter.z) / max(ou.scatter.w - ou.scatter.z, 1e-6), 0.0, 1.0);\n // The unfolded curve, which the depth ramp's start grades along below, and the\n // folded factor every other facet multiplies by. One smoothstep, two readings.\n let sizeThick = thickT * thickT * (3.0 - 2.0 * thickT);\n let sizeK = clamp(sizeThick * fold, 0.0, 1.0);\n /*\n * The body's mix is the span curve W11c fitted with a ramp in DEPTH riding on\n * top of it near the contour (W13 G1, from the measurement of claims §5.61 §2\n * and the re-forming its first runtime sweep forced):\n *\n * kDeep = floor + (1 - floor) * smoothstep(sizeSpanMin, sizeScatterSpanMax, span)\n * s0 = startThin + (startThick - startThin) * sizeThickness(span)\n * + (startFar - startThick) * smoothstep(sizeSpanMax, sizeScatterSpanMax, span)\n * s(u) = (1 - kDeep) + max(0, s0 - (1 - kDeep)) * max(0, 1 - u / U)\n * k(u) = 1 - s(u)\n *\n * The first form of the ramp replaced the span curve outright and its sweep\n * measured what that cost: the ramp's own projection onto one number per\n * surface runs 0.43-0.56 where the curve it replaced runs 0.41-1.00, so the\n * family is nearly span-flat where the bed is strongly span-graded and no\n * point in 81 reached the wave's stops. So the curve stays as the deep value\n * and the ramp is what it always measured as - a near-contour excursion.\n *\n * The SECOND form gave that excursion one start per scale, and its own sweep\n * refuted that arithmetically (claims §5.64 §2): the smallest cell's span is\n * exactly sizeSpanMin, so its deep sharp share is exactly 1 - floor and no\n * start at or below it can touch that cell, while the next span up only\n * improves BELOW a start lower still. So the start grades with span too, and\n * along the material's own thin/thick curve rather than a new one - the same\n * smoothstep 'sizeK' is built from above, unfolded, because s0 is a share the\n * reference has and not a rise a preference removes. The fold below still\n * applies once, on the composed mix.\n *\n * The THIRD form stopped there and its holdout failed on one row for the\n * form's own arithmetic (claims §5.67 §4): sizeThickness saturates at\n * sizeSpanMax, so every thick span got the same start while the reference's\n * start keeps FALLING across the thick spans, and because kDeep keeps rising\n * to sizeScatterSpanMax the excursion grew with span where the reference's\n * shrinks. So the FOURTH form declines the start past the knee along the\n * scatter span curve itself — the same smoothstep 'deepT' is built from, on\n * the band above the thickness knee — from the thick anchor to startFar at\n * sizeScatterSpanMax. Same curve read twice, no new span statistic.\n *\n * '-d' is the depth, in group-local CSS px and unclamped - the same quantity\n * the lens's 'lensT' and the inner shadow's 'shadowT' are evaluated from,\n * except that those two divide it by a depth of their own while this reads it\n * absolutely, because the reach measured as a LENGTH rather than as a fraction\n * of the span. The reach reaches this shader already divided by the device\n * ratio ('lensOval.z'), so the ratio 'u / U' is the same number in CSS px as\n * it is in the device px the profile names.\n *\n * 'max(s0 - sDeep, 0)' rather than a signed difference: the excursion is the\n * band the reference has ABOVE the body, and a span whose deep sharp share\n * already exceeds s0 has nothing to add rather than something to subtract.\n *\n * The floor and the span top arrive resolved at the ratio this group draws at\n * (W15 G1, claims 5.69 section 2): the reference's 2x deep interior is fully\n * heavy on the largest spans where this curve fitted at 1x leaves a sharp\n * share of 0.24-0.36, so kDeep is a per-scale law. Nothing about the\n * arithmetic here changes - the uniforms carry a different number, not a\n * different shape - and on the landed material the two anchors are equal.\n *\n * The fold keeps its W11c semantics on the composed law: the floor is the\n * frost the material has at any size and is not folded, everything above it -\n * the span curve's rise and the ramp's excursion alike - is depth and is, so\n * fold 1 renders the law and fold 0 sits at the floor exactly.\n */\n let scatterFloor = clamp(ou.scatter.x, 0.0, 1.0);\n let deepT = clamp((span - ou.scatter.z) / max(ou.lensOval.w - ou.scatter.z, 1e-6), 0.0, 1.0);\n // W25's share law (claims 5.113; W25 Decision Log 3 (a)): the thick end's lift\n // on the material's own thin/thick curve, ADDED to the W11c span curve rather\n // than replacing it, so the thin end keeps the constants it was fitted with and\n // 'sizeThick' being exactly 0 at sizeSpanMin makes the thin controls\n // bit-identical whatever the lift says.\n let kDeep = clamp(\n scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT)\n + ou.thickSpan.x * sizeThick,\n 0.0,\n 1.0,\n );\n let sDeep = 1.0 - kDeep;\n let rampT = max(1.0 - max(-d, 0.0) / max(ou.lensOval.z, 1e-6), 0.0);\n let farT = clamp((span - ou.scatter.w) / max(ou.lensOval.w - ou.scatter.w, 1e-6), 0.0, 1.0);\n let farS = farT * farT * (3.0 - 2.0 * farT);\n // W25's level term rides the very same curve (claims 5.113): one span\n // statistic, now read three times — the ramp's far decline, the 2x heavy\n // gain's rise and the body's level above the knee. Folded like the response it\n // extends, because a preference that has stopped the material transmitting has\n // no thin-to-thick step left to continue.\n let toneLevelFar = ou.thickSpan.y * farS * fold;\n let rampStart = ou.scatter.y + (ou.shadowSize.z - ou.scatter.y) * sizeThick\n + (ou.shadowThick.w - ou.shadowSize.z) * farS;\n let sharpShare = clamp(sDeep + max(rampStart - sDeep, 0.0) * rampT, 0.0, 1.0);\n let kScatterSpan = clamp(scatterFloor + ((1.0 - sharpShare) - scatterFloor) * fold, 0.0, 1.0);\n /*\n * W30's scale conditioning, candidate (ii) (claims 5.156 section 3): the deep\n * component's share moves with the BACKDROP's own spatial scale and not only\n * with the surface's span, which is what a residual that changes sign between\n * a 4 px pitch and a 16 px one needs. The statistic is the analysis pass's\n * per-source edge density, a reciprocal length; it arrives by readback, so the\n * CPU puts it in 'scatterScale.z' and the law is evaluated here.\n *\n * At the shipped gain of 0 the added term is a multiplied zero and the clamp\n * is the identity on a value already clamped to the same interval, so this is\n * 'kScatterSpan' to the bit.\n */\n let kScatter = clamp(\n kScatterSpan + ou.scatterScale.x * (ou.scatterScale.z - ou.scatterScale.y),\n 0.0,\n 1.0,\n );\n // The inner shadow's depth and profile: W2's law, byte for byte — the\n // thickness times the size gain (folded through 'sizeK'), clamped to the\n // shorter half extent, and a square on it. The lens ran on this until W12 G2;\n // the occlusion keeps it, because nothing measured it as wrong, and every\n // solid-backdrop cell renders exactly as it did.\n let shadowLensDepth = max(min(lensThick * (1.0 + (ou.lens.z - 1.0) * sizeK), span * 0.5), 1e-4);\n let shadowT = clamp(-d / shadowLensDepth, 0.0, 1.0);\n let shadowProfile = (1.0 - shadowT) * (1.0 - shadowT);\n\n // The lens (W12 G2, claims §5.51) — see the module note. The reference's\n // height and amount laws off the span, scaled by the thickness over the\n // reference's unit, folded like the W2 law (at fold 0 the depth is the\n // authored thickness and nothing more), and clamped to the shorter half\n // extent with the magnitude clamped by the same ratio.\n let thickScale = lensThick / max(ou.lensShape.w, 1e-4);\n let heightBase = min(ou.lensLaw.x * span, ou.lensLaw.y);\n let amountBase = min(ou.lensLaw.z * span, ou.lensLaw.w);\n let depthUnclamped = mix(lensThick, heightBase * thickScale, fold);\n let lensDepth = clamp(depthUnclamped, 0.0, span * 0.5);\n let clampRatio = select(0.0, lensDepth / depthUnclamped, depthUnclamped > 1e-6);\n let magnitude = ou.lens.y * mix(lensThick, amountBase * thickScale, fold) * clampRatio;\n let extent = max(ou.lensShape.x * lensDepth, 1e-4);\n // One steep power over the extent; '-d' is depth inside the surface.\n let lensT = max(1.0 - max(-d, 0.0) / extent, 0.0);\n let displacementCss = magnitude * pow(lensT, ou.lensShape.y) * ou.lens.x;\n\n // The direction: the field's gradient blended toward the oval inscribed in\n // the surface's box (the reference's 'gradientOvalization'), on from the\n // knee, with the magnitude fixed — which tilts the displacement toward the\n // edge's midpoint and magnifies the band along the edge.\n let ovalT = clamp((span - ou.lensOval.x) / max(ou.lensOval.y - ou.lensOval.x, 1e-6), 0.0, 1.0);\n let omega = ou.lensShape.z * ovalT * ovalT * (3.0 - 2.0 * ovalT);\n let halfExt = max(aux2.zw, vec2f(1e-4));\n let rel = aux2.xy;\n let unitR = max(length(rel / halfExt), 1e-6);\n let ovalGrad = (rel / (halfExt * halfExt)) * (min(halfExt.x, halfExt.y) / unitR);\n let blended = (1.0 - omega) * normal + omega * ovalGrad;\n let blendLen = length(blended);\n let direction = select(normal, blended / blendLen, blendLen > 1e-6);\n let displaceCss = -direction * displacementCss;\n let refracted01 = viewport01 + displaceCss / viewportCss;\n\n let refractedUv = clamp(refracted01 * ou.fit.xy + ou.fit.zw, vec2f(0.0), vec2f(1.0));\n\n /*\n * The scattering facet of the size law: \"a softer scattering of light\".\n *\n * The body texture is one blur for the whole backdrop source — it is built once\n * per source per frame, so it cannot be per-surface. The chain beside it can:\n * 'size.w' is the chain level whose blur already matches that body, so\n * 'size.w + log2(sizeScatterGainMax)' is the level whose blur is the gain times\n * wider — the HEAVY component, at one fixed level — and lerping the body toward\n * it by 'kScatter' is what the reference's interior measures (W11c, claims\n * §5.41): a sharp component near the body's σ and a heavy one near σ 10, mixed\n * by a share that is ≈ 0.4 on a small control and rises with the span. The\n * mix, not the level, is what the span moves.\n */\n // The gain is per PIXEL and not one number per group since W15 G1's re-form\n // (claims §5.70 §4 and §7): the reference's heavy kernel grows with the span,\n // so the gain rises from its near end 'size.x' to its far end 'shadowSize.w'\n // along 'farS' — the very smoothstep the ramp's far anchor already declines\n // along, computed above with the share. One curve, two quantities.\n let gainEff = ou.size.x + (ou.shadowSize.w - ou.size.x) * farS;\n /*\n * Everything above this point grades the GAIN, and claims §5.116 §2 measured\n * that the gain stops being a width: 'ou.lens.w' is the chain's own last level,\n * 4 on the bed's 320 × 200 backdrop, and 'ou.size.w + log2(8)' is 4.06, so the\n * clamp has been absorbing the gain since the material was fitted. This is the\n * path a material that names no heavy width still takes, and the heavy blur\n * below is what replaces it where one is named.\n */\n let scatterLod = clamp(ou.size.w + log2(max(gainEff, 1e-4)), 0.0, ou.lens.w);\n\n var backdrop = vec3f(0.0);\n let domMaterial = ou.heavyTap.y > 0.5;\n if (domMaterial) { backdrop = dom_material_backdrop(); }\n if (ou.flags.x > 0.5) {\n // Both components at the refracted position (W11c G2): the band and the\n // interior are one body, and the displacement alone is the lens.\n let bodySample = textureSampleLevel(backdropBody, backdropSampler, refractedUv, 0.0);\n var scatterSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, scatterLod);\n /*\n * The heavy blur (W26). Where the profile named a heavy width the deep sample\n * is not a chain level at all: the pyramid took the chain level whose own\n * blur is nearest below the target up to the target exactly, with the two\n * separable passes it already runs for the body, and this pass reads the\n * result at the same refracted uv the chain tap used.\n *\n * That is the whole mechanism, and it is here rather than in a grid of taps\n * for two measured reasons. The width the chain can reach is bounded by\n * 'chainMaxLod' — the pyramid stops when a level's shorter side would fall\n * under eight texels — so at dpr 1 on a 320 x 200 backdrop the deep sample\n * saturates at 13.4 device px against the reference's 19.5, and a residual\n * Gaussian is the only thing that carries the octave the chain does not have\n * (claims §5.119). And a 9 x 9 grid at the tap costs +1.1 ms on the optics\n * pass against 0.070 ms for the separable pair (W26 Decision Log 2 (b)).\n *\n * The price is that the width is one per SOURCE, not one per pixel: the\n * texture is built before any group is drawn, so the span grading the gain\n * carried above no longer reaches the deep sample where this is on. The\n * reference's heavy width does not grade with the span at 1x (claims\n * §5.113 §4), which is what says the material can afford it.\n */\n if (ou.heavyTap.x > 0.5) {\n scatterSample = textureSampleLevel(backdropHeavy, backdropSampler, refractedUv, 0.0);\n }\n // Premultiplied linear in, straight colour out: the material composites over\n // whatever is behind it, so a partially transparent backdrop must not darken\n // the glass.\n var scatterColour = scatterSample.rgb / max(scatterSample.a, 1e-6);\n /*\n * W30's second heavy tap, candidate (i) (claims 5.156 section 3): a second\n * texture at its own width, mixed into the deep sample by a SIGNED share.\n * A positive share widens the deep component toward that width; a negative\n * one subtracts it, which is an unsharp mask on the backdrop and the only\n * shape on offer that passes the middle pitch LESS than both ends — a mix of\n * two positive Gaussians is monotone in frequency and cannot.\n *\n * Gated on whether the pyramid built one, which it does only where\n * 'sizeHeavySecondShare' is non-zero. At the inert share the branch is not\n * taken, nothing is allocated and nothing is sampled, which is the state the\n * 34 goldens render.\n */\n if (ou.scatterHeavy2.y > 0.5) {\n let second = textureSampleLevel(backdropHeavy2, backdropSampler, refractedUv, 0.0);\n let secondColour = second.rgb / max(second.a, 1e-6);\n scatterColour = scatterColour + ou.scatterHeavy2.x * (secondColour - scatterColour);\n }\n backdrop = mix(bodySample.rgb / max(bodySample.a, 1e-6), scatterColour, kScatter);\n /*\n * The body's own half of the presence (W27d): a material at half presence\n * shows half the BLUR, not half the surface. What a surface at presence 0\n * stands over is the page as it is, so the two components' composite lerps\n * back to the unblurred backdrop — the chain's own level 0, which is the\n * texture before any of the pyramid's widths were applied.\n *\n * Read at 'refractedUv' rather than at this pixel's own position: the lens is\n * scaled by the same channel, so the sample walks back to the pixel as the\n * presence falls and arrives exactly there at 0. One uv, one read, and no\n * discontinuity between the two ends.\n *\n * The branch is what keeps the resting material byte-identical — at presence\n * 1 the extra tap is not taken at all — and it is also what keeps a present\n * surface from paying for a channel it is not using.\n */\n if (mat < 1.0) {\n let sharpSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, 0.0);\n backdrop = mix(sharpSample.rgb / max(sharpSample.a, 1e-6), backdrop, mat);\n }\n }\n\n // Adaptive tint. 'adapt.w' is the strength the accessibility policy and the\n // group's analysis quality already agreed on; at 0 the fixed tint stands, which\n // is what a 'hint' or 'none' group gets.\n let neutral = mix(ou.tint.rgb, ou.adapt.rgb, ou.adapt.w);\n\n /*\n * Backdrop tone adaptation (W7) — step two of the composition contract, between\n * the colour scheme's neutral and the author's tint.\n *\n * Read against 'toneColour': the backdrop SOURCE's own average, measured by the\n * host from the pixels it supplied and handed to both tiers as one number. Not a\n * per-pixel sample, and that is the load-bearing choice — see\n * 'GroupRenderInput.backdropTone' for the cross-tier measurement that settled\n * it, and note that the reference agrees: its capsule over a sparse bright grid\n * is a flat body rather than a window onto the grid.\n *\n * 'sizeK' is still per pixel, so a container holding a small control and a large\n * platter adapts each of them by its own thickness out of one pass.\n *\n * Strength is zero where the host measured no tone, and that strength is the\n * WHOLE gate (W22 G3). It used to be read together with 'hasBackdrop', because\n * a group with no pyramid to sample had no measured tone either and the pair\n * said one thing twice — until a group stacked over other glass acquired a\n * backdrop the host can state without a texture to sample ('backdrop-stack.ts').\n * The concern the flag stood in for is the zero vector being read as a black\n * backdrop, and 'toneAdapt.w' answers exactly that: it is zero wherever nothing\n * was measured, and zero wherever the policy has stood the axis down. Reading\n * the flag as well is what left a nested pane drawing its unadapted body over\n * glass it had measured — 0.0493 against the law's 0.0245 (claims 5.94 section 5).\n *\n * Written out instead of calling smoothstep() so that a profile patched with\n * low >= high degrades to a step rather than to NaN.\n */\n var toneAdapt = 0.0;\n if (ou.toneAdapt.w > 0.0) {\n let toneX = toneColour.w + ou.toneAdapt.z * sizeK;\n let toneT = clamp(\n (toneX - ou.toneAdapt.x) / max(ou.toneAdapt.y - ou.toneAdapt.x, 1e-6),\n 0.0,\n 1.0,\n );\n toneAdapt = clamp(toneStrength, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));\n }\n /*\n * Both the colour and the alpha move, together and not separately. What the\n * adaptation means is that the INTERIOR converges on the backdrop's tone —\n * mix(interior, tone, k) — and this is the (colour, alpha) pair that composites\n * to exactly that. Lerping the two independently makes a partially adapted\n * surface lighter than it started (more opaque toward a tint still mostly\n * neutral), which the 96 px cells caught at once: interior 0.4545 → 0.5179\n * against a reference of 0.4542. The alpha half is not a colour axis reaching\n * the occlusion axis — an adapting material stops transmitting, which is what\n * the reference's flat body over the impulse grid is. See 'adaptedTintColour'\n * and 'adaptedTintAlpha' in material.ts.\n */\n let sizedAlpha = ou.tint.w + ou.size.y * sizeK * (1.0 - ou.tint.w);\n\n /*\n * The backdrop tone response solve (W9) — the law that owns the interior\n * MEAN, where the collapse below owns texture and nothing else (claims\n * §5.33). The composite under this mechanism reduces exactly to\n * mean = (1 − k)·M₀ + k·toneLuma with M₀ = (1 − α)·bgLinear + α·L(neutral),\n * so the neutral's tone is solved in closed form: shift its luma so the\n * post-collapse mean lands on R(encodedInput, sizeK), the reference's own\n * measured response. Chroma is untouched — the shift is achromatic — and\n * the author tint still displaces the result per the composition contract.\n *\n * The solve reads the backdrop as 'toneAnchor.w' — the group's own linear mean\n * — and never as the per-pixel sample, so it is the same closed form whether\n * this pass composites the backdrop itself or writes a layer for the browser to\n * composite over a proxy carrying the same mean (W22 G3).\n *\n * Three stand-downs, each measured rather than defensive: the whole axis is\n * off where no backdrop tone was measured (same gate as the collapse); the\n * solve's authority fades to zero below the dark anchor, where the only\n * evidence is the impulse cell the collapse constants were fitted on; and\n * at k → 1 the collapse owns the pixel outright, so the solve's\n * extrapolation is never evaluated against a vanishing (1 − k).\n */\n var solvedNeutral = neutral;\n var solvedAlpha = sizedAlpha;\n if (toneStrength > 0.0 && ou.toneRowThin.w > 0.0 &&\n sizedAlpha > 1e-3 && toneAdapt < 0.995) {\n let encodedInput = srgb_encode(toneColour.w);\n let anchor = max(ou.toneAnchor.x, 1e-4);\n let authority =\n smoothstep(anchor * 0.5, anchor, encodedInput) * clamp(ou.toneRowThin.w, 0.0, 1.0);\n if (authority > 0.0) {\n let response = tone_response(encodedInput, sizeK, toneLevelFar);\n // The collapse's mean pull is toward L(toneColour.rgb) — the LINEAR\n // mean, which toneAnchor.w carries — not toward the encoded level.\n let preCollapse = (response - toneAdapt * toneLinearMean) / (1.0 - toneAdapt);\n let neutralLuma = dot(neutral, vec3f(0.2126, 0.7152, 0.0722));\n let nominal = (1.0 - sizedAlpha) * toneLinearMean + sizedAlpha * neutralLuma;\n let shift = (preCollapse - nominal) / sizedAlpha * authority * toneStrength;\n solvedNeutral = clamp(neutral + vec3f(shift), vec3f(0.0), vec3f(1.0));\n /*\n * The light attractor needs OPACITY. The light scheme's neutral is\n * already at white, so an upward shift clamps to nothing — and the\n * reference's light-adapted state is the material gone opaque-bright,\n * the same \"an adapting material stops transmitting\" the collapse's\n * alpha half was measured on. Whatever the clamp truncated is carried\n * by the alpha, solved against the same composite and folded by the\n * same authority. One-sided by design: darkward opacity is the\n * collapse's own axis with its own fitted constants.\n */\n let solvedLuma = dot(solvedNeutral, vec3f(0.2126, 0.7152, 0.0722));\n let achieved = (1.0 - sizedAlpha) * toneLinearMean + sizedAlpha * solvedLuma;\n if (preCollapse > achieved + 1e-4 && solvedLuma > toneLinearMean + 1e-3) {\n let alphaTarget = clamp(\n (preCollapse - toneLinearMean) / (solvedLuma - toneLinearMean),\n sizedAlpha,\n 1.0,\n );\n solvedAlpha = mix(sizedAlpha, alphaTarget, authority * toneStrength);\n }\n }\n }\n\n /*\n * The collapse's TARGET (W24 G1) — what the material converges on where it has\n * adapted, and the one place the transmission was lost.\n *\n * The pair below reduces exactly to 'colour = (1 − k)·M + k·target', with 'M'\n * the unadapted composite '(1 − α)·backdrop + α·neutral'. At 'target' =\n * 'toneColour.rgb', the group's MEAN backdrop colour, a fully collapsed\n * surface is one flat number and nothing under it comes through — which is\n * exactly what the reference's collapsed capsule over the impulse grid does\n * NOT do (claims §5.107 §2: it passes the centre dot at four times its own\n * body). So the target lerps toward the per-pixel blurred backdrop the\n * refraction path above already sampled, by the profile's own constant.\n *\n * Only the target moves. The tone axis's argument is still the group's mean\n * luminance and the response solve still composites against 'toneAnchor.w',\n * so 'k' and the law's level are the numbers W7 and W9 fitted: the collapse\n * still collapses the level, and stops flattening the structure.\n *\n * The alpha solve above needs no gate of its own, and this is arithmetic\n * rather than a choice: on a fully collapsed surface it never runs (its own\n * 'toneAdapt < 0.995' stands it down where the collapse owns the pixel), and\n * below that it is the (1 − k) half of the same lerp, which transmits already.\n *\n * Gated on 'flags.x': with no pyramid to sample 'backdrop' is the zero vector\n * and this pass writes a layer for the browser to composite, so a target\n * lerped toward it would be a black surface rather than a transmitting one.\n * There the CSS tier's own 'backdrop-filter' is what carries the transmission.\n */\n var toneTarget = toneColour.rgb;\n if (ou.flags.x > 0.5 || domMaterial) {\n toneTarget = mix(toneTarget, backdrop, clamp(ou.toneRowThick.w, 0.0, 1.0));\n }\n\n let adaptedAlpha = solvedAlpha + toneAdapt * (1.0 - solvedAlpha);\n var adapted = solvedNeutral;\n if (toneAdapt > 0.0 && adaptedAlpha > 0.0) {\n adapted =\n (solvedNeutral * ((1.0 - toneAdapt) * solvedAlpha) + toneTarget * toneAdapt) /\n adaptedAlpha;\n }\n\n // The material, untinted: the adapted neutral over what this pixel looks\n // through, at the material's own occlusion. That alpha is what reduced\n // transparency lifts and what the size law thickens (\"a larger size is more\n // opaque\" is a statement about how much material there is), and the backdrop\n // adaptation moved it above. The author's colour never touches it — but not\n // for the reason the composition contract first gave (claims §5.36).\n /*\n * The material's alpha, times the presence (W27d) — and applied HERE rather\n * than to 'adaptedAlpha' above, which is load-bearing: that alpha is the\n * divisor the collapse's own composite is un-premultiplied by, so scaling it\n * there would move the adapted COLOUR as well as the amount of it. Presence is\n * how much of the material is there, not what the material is.\n */\n let presentAlpha = adaptedAlpha * mat;\n var colour = mix(backdrop, adapted, presentAlpha);\n /*\n * W31's chroma retention, HERE and not later (claims 5.161 section 5).\n *\n * Immediately after the composite, because the composite is where the\n * chroma is lost — the plate is neutral and the backdrop's chromaticity\n * survives it scaled by '1 - presentAlpha'. Before the tint composition\n * below, so an author's tint still displaces the result per the composition\n * contract; the tint's shade law reads the untinted material's LUMINANCE,\n * which this preserves exactly, so 'shade', 'layer' and 'rimTintColour' are\n * bit-identical whatever the retention holds.\n *\n * Before the DOM branch as well, so the secant that solves an unsampled DOM\n * group's layer alpha solves it from the material the page will actually\n * show. That branch is NOT luma-transparent — 'dom_material_alpha' clamps per\n * channel inside a luma computation — so an unsampled DOM GROUP'S layer alpha\n * may move with the retention where a sampled composite does not (claims\n * 5.161 section 11, the second reading carried forward).\n *\n * That sentence said \"the 'dom' tier\", which is a different thing and is the\n * thing a reader will think of first (W31 G3c review closure; claims 5.164\n * section 13, finding N7). The 'dom' tier is the CSS tier, the one the\n * calibration matrix keys under that name, and it does not run this shader at\n * all; what is meant here is THIS shader's unsampled-material path, where a\n * group with no sampled backdrop writes a layer for the browser to composite.\n *\n * And on that path what the operator restores TOWARD is not the page's\n * backdrop, because nothing sampled it. 'dom_material_backdrop()' fabricates\n * one, and it has two modes. Mode 1, which a group with no declared\n * 'backdropTone' takes, returns 'vec3f(ou.heavyTap.z)' — a neutral at the\n * declared reference luminance — so the mix target is\n * 'backdrop * (Y / Yb)' = 'vec3f(Y)', the neutral at the colour's own luma.\n * That reads as a desaturation and is the IDENTITY in effect: on that path\n * 'adapted' is 'solvedNeutral' and the fabricated backdrop is a grey, so the\n * composite has no chromaticity for the target to differ from. Measured at\n * three retentions up to 1: zero bytes moved\n * ('e2e/gpu/w31-unsampled-dom-chroma.spec.ts').\n *\n * Mode 2 hands the DECLARED tone colour, which can be chromatic, and there\n * the operator runs — the body takes the hue the page STATED is behind it\n * rather than the hue that is. That is the residual, recorded in claims 5.164\n * section 10, and it is a statement about the target rather than about the\n * amount: the same spec reads the interior's chroma from 0.066 to 0.334 and\n * finds the gamut clamp binding at the shipped retention already.\n *\n * On the unsampled LAYER path ('flags.x <= 0.5' and not 'domMaterial')\n * 'colour' is overwritten with 'adapted' a few lines below: there is no\n * backdrop in hand and no chromaticity to restore toward, and the retention is\n * silently the identity. That is a declared residual, not an oversight.\n */\n colour = body_chroma_retention(colour, backdrop, ou.bodyChroma.x);\n /*\n * How much of this pixel the SURFACE owns, as the canvas will composite it.\n *\n * With a backdrop the composite above is the whole pixel — the pass sampled\n * what is behind the surface and mixed it in, so the output is opaque inside\n * the contour and the page beneath the canvas never shows. With no backdrop\n * the composite is not here to make: a 'css-backdrop' group's blurred\n * backdrop is a DOM proxy under this canvas, a 'none' group's is the page\n * itself, and the browser is the compositor. So the material leaves as a\n * LAYER — the adapted colour at the material's own alpha, premultiplied on\n * the way out — and every term below that would have shaped the composite\n * shapes the layer instead, in the form that composites to the same thing.\n *\n * Before W11a this path mixed the material over a black backdrop and wrote\n * it opaque: a nested surface over glass rendered as a flat 0.468 where the\n * reference reads 0.89 (claims §5.38 §5). The rows that floored were that\n * grey. The pair the layer is written at is the host's\n * ('GroupRenderInput.unsampledMaterial'): the browser composites this canvas\n * in encoded sRGB, so the alpha is the CSS tier's, not the linear profile's.\n */\n var bodyAlpha = 1.0;\n var domAlpha = 1.0;\n if (domMaterial) {\n // The collapse transmits k*c of the DOM proxy as well. Solve the secant\n // after the linear material, never feed its encoded alpha back into R.\n /*\n * Times the presence (W27d), on the same factor 'presentAlpha' carries into\n * 'colour' just above — this branch's body is a SOLVED layer rather than a\n * composite, so the secant's own input is where the channel reaches it.\n *\n * It has to be here rather than on the result. The secant divides the\n * composite by this alpha to recover the material's own neutral, so scaling\n * both together leaves that neutral (and the span it spans) at exactly what\n * presence 1 solves, and only the returned coverage travels. Left unscaled,\n * the neutral would walk toward the backdrop as the surface thins, the span\n * would fall under 'heavyTap.w', and the guard would hand back the FULL\n * alpha — a flat tone painted over a page the surface has left.\n *\n * At presence 1 the factor is exactly 1.0 and the expression is bit-identical\n * to the resting one; at 0 the secant's own '<= 1e-6' guard returns 0.\n */\n let transmission = toneAdapt * clamp(ou.toneRowThick.w, 0.0, 1.0);\n domAlpha = dom_material_alpha(colour, backdrop,\n clamp(adaptedAlpha - transmission, 0.0, 1.0) * mat);\n } else if (ou.flags.x <= 0.5) {\n colour = adapted;\n bodyAlpha = presentAlpha;\n }\n /*\n * One gap this tier cannot close from here, named rather than left to be\n * discovered (W27d): on an unsampled group the blurred backdrop is a DOM proxy\n * beneath this canvas, so the body's mix toward the unblurred backdrop above\n * has no texture to mix with. A layer that fades to alpha 0 there reveals the\n * PROXY's blur rather than the page — presence takes the tint, the rim and the\n * shadows out, and the blur is the host's to fade with it.\n */\n\n // The author tint (W10). 'aux.w' is the per-pixel strength, unioned in the\n // field pass, so a toolbar can carry one tinted control among plain ones; the\n // seed is a group uniform. At strength 0 this is the identity and the material\n // is the one the calibration bed measures, byte for byte.\n //\n // Apple's mechanism, measured per pixel: the tinted material is an OPAQUE\n // layer of the seed at a shade that is linear in the luminance the untinted\n // material shows at this pixel — about half the seed's light over black\n // content, the seed itself over white, the seed's chromaticity intact\n // throughout. That layer composites over the material at the AUTHOR's\n // opacity in the encoded space, which is what a CALayer with 'opacity' does\n // and how the reference's half-strength cell measures. So a tinted surface\n // over a checkerboard shows the checker as light and dark ORANGE, not as\n // orange glass with the checker behind it — the material's own alpha is not\n // what a tinted surface shows.\n //\n // 'seed.w' is the contrast regime's grip on the excursion, never on the hue;\n // 'tone.z' is the profile's provenance gate (the dark scheme renders the pure\n // seed); and '1 − toneAdapt' folds the shade out where the collapse has made\n // the material a dark body, where the reference renders the pure seed too.\n // At zero grip the layer is the bare seed — the author's colour, flat.\n /*\n * The material's own composite, kept beside the tinted one (W23; claims §5.100\n * §5). The rim is the MATERIAL's mark and the author's colour is painted over\n * it, so the amplitude law below reads the level the material reached and not\n * the level the paint left — which is what the reference does: its tinted rows\n * read +0.13…+0.17 of contour rim in BOTH colour schemes, where the two\n * materials' own laws on the PAINTED level differ by a factor of five and land\n * the dark bed's tinted rows 0.216 over.\n *\n * For an untinted pixel these carry exactly 'colour' and 'bodyAlpha', so the\n * rim below is bit-identical to the law without them.\n */\n var materialColour = colour;\n var materialAlpha = bodyAlpha;\n /*\n * The colour the rim's light is spent in (W23 G3; claims §5.102). White on a\n * bare surface, and on a PAINTED one the author's own CHROMATICITY: the\n * reference's rim on a tinted capsule is the paint lifted rather than white\n * added over it — orange (255, 148, 0) rises to (254, 188, 0) with its blue\n * channel still at 0, where vitrea drew (255, 192, 130).\n *\n * The layer is normalised by its own LUMINANCE and not by its brightest\n * channel, which is what the rows chose: on the collapsed orange capsule at 2x\n * the reference lifts the green channel by 0.213 of linear light where a white\n * rim of the same amount lifts it by 0.304, and 0.213 / 0.304 = 0.70 is exactly\n * the green coefficient of that orange divided by its luminance. Normalising by\n * the brightest channel instead reproduces the hue and loses the AMOUNT — it\n * divides the rim's luminance by the paint's, which on the same cell took the\n * contour rim from 0.115 to 0.030 against a reference of 0.118. Chromaticity is\n * unbounded as a paint darkens, so the divisor has a floor of 0.05: below that\n * the paint has no readable hue and the normalisation would be a colour cast of\n * arbitrary size rather than a rim.\n *\n * 'rimTintChroma' (rimLaw.w) is how much of that is taken, and it is\n * multiplied by the pixel's own tint strength, so an UNTINTED pixel keeps a\n * white rim at every value of the constant — which is what makes the mechanism\n * reach painted pixels only (W23 S10).\n */\n var rimTintColour = vec3f(1.0);\n /*\n * The author tint's coverage at this pixel, times the presence (W27d). The\n * paint is part of the material and not a thing painted onto the page, so a\n * dissolving surface takes its colour with it — at presence 0 the pixel is the\n * backdrop and not a flat orange over it. At presence 1 this is\n * 'clamp(aux.w, 0, 1)' exactly, which is what the tint's own law was fitted on.\n */\n let tintK = clamp(aux.w, 0.0, 1.0) * mat;\n if (tintK > 0.0) {\n // The untinted material's luminance at this pixel. Over a backdrop that is\n // the composite; as a layer it is the layer over the tone the host measured\n // for the group — zero where nothing was measured, the same reference-level\n // convention the CSS tier's 'materialLuminance' takes (within its 0.02).\n let u = bodyAlpha * dot(colour, vec3f(0.2126, 0.7152, 0.0722)) + (1.0 - bodyAlpha) * toneColour.w;\n let grip = clamp(ou.seed.w, 0.0, 1.0) * clamp(ou.tone.z, 0.0, 1.0) *\n (1.0 - toneAdapt * (1.0 - clamp(ou.rim.w, 0.0, 1.0)));\n let shade = mix(1.0, clamp(mix(ou.tone.x, ou.tone.y, clamp(u, 0.0, 1.0)), 0.0, 1.0), grip);\n // The identity branch preserves the active seed's arithmetic bit for bit.\n var seed = ou.seed.rgb;\n if (ou.rim.z < 1.0) {\n let neutral = max(seed.r, max(seed.g, seed.b));\n seed = mix(vec3f(neutral), seed, clamp(ou.rim.z, 0.0, 1.0));\n }\n let layer = seed * shade;\n /*\n * The recede's chroma collapse (W27c) shapes WHAT the paint is; presence\n * (W27d) is how much of it is there. They compose on this one strength and\n * each reaches it once: the collapse through 'seed', the presence through\n * 'tintK'. 's' is the coverage every consumer below reads — the rim's tint\n * mix, the encoded fold, and the DOM branch's own alpha — so folding the\n * presence in here is what keeps it from being applied twice downstream.\n */\n let s = tintK;\n if (domMaterial) { domAlpha = 1.0 - (1.0 - s) * (1.0 - domAlpha); }\n let layerLuma = max(dot(layer, vec3f(0.2126, 0.7152, 0.0722)), 0.05);\n rimTintColour = mix(vec3f(1.0), layer / layerLuma, clamp(ou.rimLaw.w, 0.0, 1.0) * s);\n let encodedMaterial = linear_to_srgb(clamp(colour, vec3f(0.0), vec3f(1.0)));\n let encodedLayer = linear_to_srgb(layer);\n if (ou.flags.x > 0.5) {\n colour = srgb_to_linear(mix(encodedMaterial, encodedLayer, vec3f(s)));\n } else {\n // The opaque layer at the author's opacity over the material's own layer,\n // premultiplied: the fold 'tintedCssOptics' makes into one rgba.\n let premultiplied = (1.0 - s) * bodyAlpha * encodedMaterial + s * encodedLayer;\n bodyAlpha = 1.0 - (1.0 - s) * (1.0 - bodyAlpha);\n colour = srgb_to_linear(premultiplied / max(bodyAlpha, 1e-6));\n }\n }\n\n /*\n * Everything below is the surface's own APPEARANCE — the marks that say a\n * surface is here rather than what is behind it — and all of it fades with the\n * adaptation, on the one factor.\n *\n * That is not symmetry for its own sake; it is what the reference does, and it\n * is a calibration cell rather than an inference: the reference's capsule over\n * the dark-solid backdrop is byte-identical to that background, rim included. A\n * material that has taken its backdrop's tone has no lit edge to show, because\n * there is no light in front of it to show one with.\n *\n * The gap was invisible until this axis existed. A rim of up to 130/255 sat\n * unnoticed inside a bright capsule body; with the body gone it is a white\n * outline around a surface that should not be there at all — 595 pixels past\n * 2/255 on that one cell, and OKLab ΔE max 0.47 where p95 already read 0.0000.\n * The same lesson W3 recorded from the other direction: a term that happens to\n * be hidden is one feature away from being visible.\n */\n let present = 1.0 - toneAdapt;\n\n // Inner shadow: the material's own occlusion, deepest where the lens is\n // strongest, which is what makes a thicker surface read as heavier — and the\n // shadow facet of the size law deepens it further with the span.\n let shadowDepth = ou.light.z * (1.0 + (ou.size.z - 1.0) * sizeK);\n // A multiplicative occlusion of the whole composite. As a layer that is the\n // colour scaled and the alpha raised — (k·a·c, 1 − k·(1 − a)) composites to\n // k times what (a·c, a) would — and at bodyAlpha 1 it is the plain product.\n // Times the presence (W27d) on the AMPLITUDE, beside the depth the same channel\n // already shallowed through 'lensThick': the occlusion is the material's own,\n // and a material that is half there occludes half as much of what is behind it.\n let shadowKeep = 1.0 - shadowProfile * shadowDepth * ou.light.w * present * mat;\n if (domMaterial) { domAlpha = 1.0 - shadowKeep * (1.0 - domAlpha); }\n let shadowedAlpha = 1.0 - shadowKeep * (1.0 - bodyAlpha);\n colour = colour * (shadowKeep * bodyAlpha / max(shadowedAlpha, 1e-6));\n bodyAlpha = shadowedAlpha;\n // The same occlusion on the material's own composite, so that the rim's law\n // reads a level the inner shadow has reached exactly as it always did.\n let materialShadowedAlpha = 1.0 - shadowKeep * (1.0 - materialAlpha);\n materialColour = materialColour * (shadowKeep * materialAlpha / max(materialShadowedAlpha, 1e-6));\n materialAlpha = materialShadowedAlpha;\n\n /*\n * The rim from the gradient. Its amplitude law is below and the direction it\n * is LIT from is the factor after it.\n *\n * The one-sided specular that used to be added here — 'pow(clamp(dot(normal,\n * light.xy), 0, 1), rim.z) * rim.w' — is retired (W24; claims §5.108 §1). Read\n * around the whole contour the reference's rim is symmetric about the diagonal\n * rather than one-sided, and a term that can only reach one end of it fits at\n * 0.288 of normalised RMS where the symmetric factor fits at 0.148. 'rim.z'\n * and 'rim.w' are written by the pass and no longer read.\n */\n let rw = rim_weight(d, ou.rim.x);\n /*\n * The rim's amplitude law, and the rim that survives the collapse (W23;\n * claims §5.100 §§3-4).\n *\n * - The amplitude is affine in the MATERIAL's own rendered luminance, taken\n * exactly as the tint shade takes it above — the composite where this layer\n * covers the pixel, the group's measured backdrop tone where it does not,\n * and in both cases before the author's colour is painted over it —\n * so that a rim fitted as 'a fraction of the body's headroom' (a negative\n * gain, the screen form the CSS tier's inset shadow already is) and a rim\n * fitted as 'a line that rides its own body up' (a positive one, which is\n * what the dark reference's rows read as) are the same expression with the\n * sign the rows chose. The environment term the wave chartered beside it is\n * not here: it is worse than this law on the reference in both schemes and\n * no row of either bed separates it, so it is not carried (C9a §6.2).\n * - 'rimCollapsed' rises with 'toneAdapt' exactly as the rest of the\n * appearance falls with it. At toneAdapt 1 the surface draws its backdrop\n * with this rim and nothing else, which is what the reference's collapsed\n * capsule does; at 0 it contributes nothing at all.\n * The collapsed rim it rises to is the AUTHOR TINT's coverage lerped between\n * two absolute constants: the reference's collapsed capsule keeps +0.020 of\n * contour rim bare and +0.115 painted, and both are absolutes rather than\n * fractions of the appearance's own rim, because the reference draws one\n * collapsed appearance out of two materials whose amplitude laws differ by\n * 1.8× (claims §5.100 §5). 'aux.w' is the same per-pixel tint strength the\n * author tint layer composites with sixty lines above.\n */\n let rimLuma = materialAlpha * dot(materialColour, vec3f(0.2126, 0.7152, 0.0722))\n + (1.0 - materialAlpha) * toneColour.w;\n let rimAmplitude = ou.rim.y + ou.rimLaw.x * rimLuma;\n let rimCollapsed = mix(ou.rimLaw.y, ou.rimLaw.z, tintK);\n /*\n * The lit edge (W24; claims §5.107) — the directional factor the whole rim is\n * multiplied by, symmetric about 'rimLit.xy'.\n *\n * Apple's rim is not one number around the contour. Read at 720 or more points\n * of the declared boundary and binned by the NORMAL's angle, the reference's\n * north-west and south-east bins are five to twenty-five times its north-east\n * and south-west ones on every untinted solid cell of both beds, while every\n * per-side reader in three waves read it flat — a light on the diagonal\n * projects equally on all four straight sides. This is the shape of that.\n *\n * '1.4142135' is the amplitude's re-expression and not a scale: it normalises\n * the dot product by 'cos 45 deg', so at the default axis the factor is exactly\n * 1 wherever the normal is horizontal or vertical, at EVERY exponent. W23\n * fitted 'rimAlpha' and 'rimLevelGain' on those straight spans, so they keep\n * their meaning untouched and only the corners and the arcs move — which is\n * also why the CSS tier, whose one inset layer cannot vary around a contour,\n * needs no counterpart and no re-fit.\n *\n * The factor multiplies the COLLAPSED rim as well as the appearance's own. That\n * is a measurement and not a symmetry: the reference's collapsed cells — the\n * 'dark-solid' capsule at both scales and the probe grids' 'dark-solid'\n * rrect-sm and rrect-lg — fit the same axis (136.0 deg) and the same exponent\n * (1.15 against 1.00) as the uncollapsed rows, so one factor outside the\n * bracket is what the rows say and two constants would be one more than they\n * separate.\n *\n * The floor is 1e-6 and not 0 so that 'pow' is defined where the normal is\n * exactly perpendicular to the axis; at exponent 0 it returns 1 there as it\n * does everywhere else, which is what makes this term inert at the defaults.\n */\n let lit = pow(max(abs(dot(normal, ou.rimLit.xy)) * 1.4142135, 1e-6), ou.rimLit.z);\n /*\n * The along-side field (W25; claims 5.113, W25 Decision Log 3 (c)) — the\n * POSITION half of the light whose direction half W24 landed.\n *\n * W24's factor is a function of the normal, so it is one number on a whole\n * straight side. Read by position along the side instead, on flat solid\n * backdrops where a lens has no gradient to refract, the reference's rim is\n * graded on every thick cell of both probe grids and flat at spans 32 and 44 —\n * a term on the thickness curve. Its four slopes are equal and OPPOSITE across\n * opposite sides, which a field linear in position cannot be and the product of\n * the two normalised coordinates is exactly: +1 at the top-left and\n * bottom-right corners, -1 at the other two, the same diagonal 'rimLit.xy' is\n * symmetric about.\n *\n * 'aux2.xy' is the pixel's offset from its own surface's centre in CSS px and\n * 'aux2.zw' its half-extents, so the field is the surface's own coordinate and\n * a container of differently sized members grades each of them by its own box\n * out of one pass. The field's mean over any straight side is exactly zero, so\n * W23's and W24's straight-span amplitudes keep the meaning they were fitted\n * with and the CSS tier's single inset needs no counterpart.\n *\n * 'sizeThick' is the unfolded thickness curve, exactly 0 at sizeSpanMin, so\n * rrect-sm and every thinner control are untouched by construction; at slope 0\n * the factor is exactly 1 everywhere.\n */\n let alongSide = clamp((rel.x / halfExt.x) * (rel.y / halfExt.y), -1.0, 1.0);\n let alongFactor = max(1.0 + ou.rimLit.w * sizeThick * alongSide, 0.0);\n // The whole rim — both the appearance's own and the one the collapse keeps —\n // times the presence (W27d). The rim is the mark that says a surface is HERE,\n // which is the first thing a surface that is not there stops saying; the same\n // argument the collapse's 'present' makes, from the author's side.\n let rim = rw * lit * alongFactor * (rimAmplitude * present + rimCollapsed * toneAdapt) * mat;\n let rimLight = rim * rimTintColour;\n if (ou.flags.x > 0.5 || domMaterial) {\n colour = colour + rimLight;\n if (domMaterial) { domAlpha = clamp(domAlpha + rim, 0.0, 1.0); }\n } else {\n // Added light has no premultiplied form of its own — a canvas colour may\n // not exceed its alpha — so the layer carries the light in its opacity:\n // (a·c + rim, a + rim) composites to dst·(1 − a) + a·c + rim − rim·dst,\n // the additive term short of rim × dst. Exact wherever the layer is\n // opaque (an author tint at full strength, or a lit contour pixel whose\n // alpha the rim fills), and never further off than the rim times what\n // shows through — where the mix form (\"white over the layer at the rim's\n // weight\") is short by the rim times the whole composite, which halved\n // the rim on a tinted panel.\n // The alpha the rim carries is its LIGHT and not its colour: a coloured rim\n // spends the same light through a narrower set of channels, so the layer's\n // opacity is still 'rim' and only the colour it carries is tinted.\n let carried = clamp(bodyAlpha + rim, 0.0, 1.0);\n colour = min((colour * bodyAlpha + rimLight) / max(carried, 1e-6), vec3f(1.0));\n bodyAlpha = carried;\n }\n\n // The material over its own shadow over the page, in one premultiplied vector:\n // the colour is the surface's, weighted by its coverage and by however much of\n // the pixel the layer owns, and the alpha is what the two of them together\n // leave the page. The shadow fills only what the surface's COVERAGE leaves —\n // clipped out of the silhouette exactly as a 'box-shadow' is clipped out of\n // its border box — never what the layer's own transparency leaves: a\n // translucent surface shows the page through it, not its own shadow. (With\n // an opaque body the two are the same quantity, which is how the shadow was\n // first written and why the difference only surfaced with the layer form.)\n if (domMaterial) {\n // Coverage precedes the gamut solve. The sampled rim may exceed white\n // before antialiasing; clipping it first would dim the half-covered edge.\n // Include the exterior shadow in the same target so its light and opacity\n // remain one valid premultiplied layer at that edge too.\n let b = linear_to_srgb(backdrop);\n let compositeEncoded = linear_to_srgb(max(colour, vec3f(0.0))) * coverage\n + (b * (1.0 - shadowAlpha) + liftEncoded) * (1.0 - coverage);\n let alpha = domAlpha * coverage + shadowAlpha * (1.0 - coverage);\n return dom_material_output(compositeEncoded, b, alpha);\n }\n let body = encode_output(max(colour, vec3f(0.0)), coverage * bodyAlpha);\n return vec4f(\n body.rgb + liftEncoded * (1.0 - coverage),\n body.a + shadowAlpha * (1.0 - coverage),\n );\n}`;\n","/**\n * Shared WGSL: the colour pipeline (X5) and the fullscreen-triangle vertex stage\n * every pass here uses.\n *\n * The marker comment on the first line is load-bearing beyond documentation:\n * `packages/core/test/bundle-shape.test.ts` greps built chunks for it to prove\n * that WGSL reaches exactly one lazily-imported chunk and never core's entry\n * chunk (X7). Keep it in a module every pass pulls in, and keep it spelled\n * exactly as it is.\n */\n\nexport const WGSL_PRELUDE = `// vitrea:wgsl-marker\n// ---------------------------------------------------------------------------\n// X5 colour pipeline. Piecewise sRGB, matching color.ts channel for channel:\n// a golden regenerated against one and asserted against the other must not\n// drift by a code unit, so the 2.2-gamma approximation is not used anywhere.\n// ---------------------------------------------------------------------------\n\nfn srgb_to_linear(c : vec3f) -> vec3f {\n let lo = c / 12.92;\n // The floor is the identity at every component the select below KEEPS: it\n // keeps hi only where c > 0.04045, and there the base is already above 0.0905.\n // Below zero the base is a pow WGSL leaves undefined, and a clamp in the\n // source is preferred to a proof of the select's discard (W31 G2 review\n // closure, claims §5.163 §8, finding N8). Same shape as linear_to_srgb's own\n // max, one line down.\n let hi = pow(max((c + vec3f(0.055)) / 1.055, vec3f(0.0)), vec3f(2.4));\n return select(hi, lo, c <= vec3f(0.04045));\n}\n\nfn linear_to_srgb(c : vec3f) -> vec3f {\n let lo = c * 12.92;\n let hi = 1.055 * pow(max(c, vec3f(0.0)), vec3f(1.0 / 2.4)) - vec3f(0.055);\n return select(hi, lo, c <= vec3f(0.0031308));\n}\n\n/// Rec.709 weights on LINEAR light. Weighting encoded values would make the\n/// analysis pass measure something that is not energy.\nfn luminance(linear : vec3f) -> f32 {\n return dot(linear, vec3f(0.2126, 0.7152, 0.0722));\n}\n\n/// The one output encoding: encode, then premultiply in the ENCODED space,\n/// because that is the space the browser composites a canvas in. Premultiplying\n/// in linear and encoding afterwards darkens every partially covered pixel.\nfn encode_output(linear : vec3f, alpha : f32) -> vec4f {\n let a = clamp(alpha, 0.0, 1.0);\n return vec4f(linear_to_srgb(linear) * a, a);\n}\n\n// ---------------------------------------------------------------------------\n// Fullscreen triangle. Three vertices, no vertex buffer, no index buffer: the\n// oversized triangle is clipped to the target and costs one fewer primitive\n// than a quad, and every pass here writes exactly one screen-space region.\n// ---------------------------------------------------------------------------\n\nstruct FullscreenOut {\n @builtin(position) position : vec4f,\n @location(0) uv : vec2f,\n};\n\n@vertex\nfn vs_fullscreen(@builtin(vertex_index) index : u32) -> FullscreenOut {\n // (-1,-1) (3,-1) (-1,3) in clip space; uv follows with y flipped so (0,0) is\n // the target's top-left, matching texture and viewport conventions.\n let x = f32((index << 1u) & 2u) * 2.0 - 1.0;\n let y = f32(index & 2u) * 2.0 - 1.0;\n var out : FullscreenOut;\n out.position = vec4f(x, y, 0.0, 1.0);\n out.uv = vec2f((x + 1.0) * 0.5, (1.0 - y) * 0.5);\n return out;\n}\n`;\n","import { WGSL_FIELD_KERNELS } from \"./field\";\nimport { WGSL_PRELUDE } from \"./prelude\";\n\n/** W28: reduce raw level-zero pixels, encoding EACH RGB before the Rec.709 sum.\n * Encoding a linear-light mip mean instead measures a different abscissa (Jensen's inequality).\n * The mask is G0's circular rounded rectangle, not the optical field's continuous shoulder.\n * Samples are full-resolution device-pixel centres; the field governor never thins this grid.\n */\nexport const silhouetteReductionModule = (): string => `${WGSL_PRELUDE}\nstruct ToneShape { rect : vec4f, radius : vec4f };\nstruct ToneStat { colour : vec4f, stats : vec4f };\nstruct ToneUniforms { viewport : vec4f, fit : vec4f };\n@group(0) @binding(0) var<uniform> u : ToneUniforms;\n@group(0) @binding(1) var source : texture_2d<f32>;\n@group(0) @binding(3) var<storage, read> shapes : array<ToneShape>;\n@group(0) @binding(4) var<storage, read_write> tones : array<ToneStat>;\nvar<workgroup> sums : array<vec4f, 256>;\nvar<workgroup> counts : array<f32, 256>;\nvar<workgroup> weights : array<f32, 256>;\nstruct RawTone { value : vec4f, alpha : f32 };\n\nfn raw_tone(texel : vec2i) -> RawTone {\n let dims = vec2i(textureDimensions(source));\n let rgba = textureLoad(source, clamp(texel, vec2i(0), dims - 1), 0);\n let rgb = rgba.rgb / max(rgba.a, 1e-6);\n return RawTone(vec4f(rgb, dot(linear_to_srgb(rgb), vec3f(0.2126, 0.7152, 0.0722))) * rgba.a, rgba.a);\n}\n\n@compute @workgroup_size(256)\nfn reduce_tone(@builtin(local_invocation_index) lane : u32,\n @builtin(workgroup_id) group : vec3u) {\n let shape = shapes[group.x];\n // G0 clips to the capture raster. Clip BEFORE deriving the iteration area so\n // offscreen geometry cannot create unbounded work or overflow its u32 product.\n // In-bounds rectangles retain exactly the same lane assignment and arithmetic.\n let lo = vec2i(clamp(floor(shape.rect.xy), vec2f(0.0), u.viewport.xy));\n let hi = vec2i(clamp(ceil(shape.rect.xy + shape.rect.zw), vec2f(0.0), u.viewport.xy));\n let extent = vec2u(max(hi - lo, vec2i(0)));\n let half = shape.rect.zw * 0.5;\n let centre = shape.rect.xy + half;\n let radius = min(shape.radius.x, min(half.x, half.y));\n var sum = vec4f(0.0);\n var count = 0.0;\n var weight = 0.0;\n for (var i = lane; i < extent.x * extent.y; i += 256u) {\n let pixel = lo + vec2i(vec2u(i % extent.x, i / extent.x));\n let p = vec2f(pixel) + 0.5;\n let q = abs(p - centre) - half + radius;\n let distance = length(max(q, vec2f(0.0))) + min(max(q.x, q.y), 0.0) - radius;\n if (distance > 0.0) { continue; }\n let uv = (p / u.viewport.xy) * u.fit.xy + u.fit.zw;\n // Interpolate encoded and linear statistics separately. Encoding after\n // bilinear filtering would reintroduce a Jensen gap on a scaled source.\n let at = uv * vec2f(textureDimensions(source)) - 0.5;\n let base = vec2i(floor(at));\n let f = fract(at);\n let a = raw_tone(base);\n let b = raw_tone(base + vec2i(1, 0));\n let c = raw_tone(base + vec2i(0, 1));\n let d = raw_tone(base + vec2i(1, 1));\n sum += mix(mix(a.value, b.value, f.x), mix(c.value, d.value, f.x), f.y);\n weight += mix(mix(a.alpha, b.alpha, f.x), mix(c.alpha, d.alpha, f.x), f.y);\n count += 1.0;\n }\n sums[lane] = sum;\n counts[lane] = count;\n weights[lane] = weight;\n workgroupBarrier();\n for (var stride = 128u; stride > 0u; stride /= 2u) {\n if (lane < stride) {\n sums[lane] += sums[lane + stride];\n counts[lane] += counts[lane + stride];\n weights[lane] += weights[lane + stride];\n }\n workgroupBarrier();\n }\n if (lane == 0u) {\n let mean = sums[0] / max(weights[0], 1e-6);\n let level = srgb_to_linear(vec3f(mean.w)).x;\n tones[group.x].colour = vec4f(mean.rgb, level);\n tones[group.x].stats = vec4f(mean.w, luminance(mean.rgb), counts[0], weights[0]);\n }\n}\n`;\n\n/** A separate field avoids exceeding WebGPU's 32-byte colour-attachment budget.\n * The same geometry kernels and union fold carry all four reference channels through a seam.\n * No nearest-member shortcut: merged members retain their own colour AND encoded level.\n */\nexport const silhouetteFieldModule = (family: \"rsupn\" | \"rsup\"): string => `${WGSL_PRELUDE}\n${WGSL_FIELD_KERNELS}\nstruct FieldUniforms { screen : vec4f, unionP : vec4f, counts : vec4u, fallback : vec4f };\nstruct ToneStat { colour : vec4f, stats : vec4f };\n@group(0) @binding(0) var<uniform> u : FieldUniforms;\n@group(0) @binding(1) var<storage, read> instances : array<Instance>;\n@group(0) @binding(2) var<storage, read> tones : array<ToneStat>;\nfn member_distance(i : u32, p : vec2f) -> f32 {\n let s = instances[i];\n return ${family === \"rsupn\" ? \"sd_rsupn_grad\" : \"sd_rsup_grad\"}(\n p - s.centre, s.half, s.re, vec4f(s.k0, s.k1, s.k2, s.k3), s.k4).d + s.inset;\n}\nfn member_tone(i : u32) -> vec4f {\n return select(u.fallback, tones[i].colour, tones[i].stats.w > 0.0);\n}\n@fragment\nfn fs_tone(in : FullscreenOut) -> @location(0) vec4f {\n let p = in.uv * u.screen.xy * u.screen.z;\n var distance = member_distance(0u, p);\n var colour = member_tone(0u);\n for (var i = 1u; i < u.counts.x; i += 1u) {\n let blend = union_blend(distance, member_distance(i, p), u.unionP.xyz);\n distance = blend.x;\n colour = mix(member_tone(i), colour, blend.y);\n }\n return colour;\n}\n`;\n","/**\n * Shader-module assembly.\n *\n * Every module is `prelude + pass`, so the colour pipeline and the fullscreen\n * vertex stage are defined once and there is no way for a pass to acquire its own\n * private transfer function. Assembly is a plain string concatenation performed\n * on demand and cached by the pipeline cache — no build step, no bundler plugin,\n * and the WGSL stays greppable in the built artifact, which is what core's X7\n * bundle test relies on.\n */\n\nimport { WGSL_ANALYSIS_PASS } from \"./analysis\";\nimport { WGSL_CROSS_CHECK_PASS } from \"./cross-check\";\nimport { importPassSource, WGSL_DOWNSAMPLE_PASS } from \"./backdrop\";\nimport { fieldPassSource, WGSL_FIELD_KERNELS } from \"./field\";\nimport { WGSL_HIGHLIGHT_PASS } from \"./highlight\";\nimport { WGSL_OPTICS_PASS } from \"./optics\";\nimport { WGSL_PRELUDE } from \"./prelude\";\nimport { silhouetteFieldModule, silhouetteReductionModule } from \"./silhouette-tone\";\n\nexport * from \"./analysis\";\nexport * from \"./cross-check\";\nexport * from \"./backdrop\";\nexport * from \"./field\";\nexport * from \"./highlight\";\nexport * from \"./optics\";\nexport * from \"./prelude\";\n\nconst withPrelude = (pass: string): string => `${WGSL_PRELUDE}\\n${pass}\\n`;\n\nexport type FieldFamily = \"rsupn\" | \"rsup\";\n\nexport const fieldModule = (family: FieldFamily): string => withPrelude(fieldPassSource(family));\n\nexport const importModule = (kind: \"sampled\" | \"external\"): string =>\n withPrelude(importPassSource(kind));\n\nexport const chainModule = (): string => withPrelude(WGSL_DOWNSAMPLE_PASS);\n\nexport const analysisModule = (): string => withPrelude(WGSL_ANALYSIS_PASS);\n\nexport const opticsModule = (): string => withPrelude(WGSL_OPTICS_PASS);\n\nexport const highlightModule = (): string => withPrelude(WGSL_HIGHLIGHT_PASS);\n\n/**\n * The kernel-only module the f32 cross-check compiles (Decision Log #20).\n *\n * It is assembled from the same constants the field pass is, which is the point:\n * a check that compiled a different string from the one the renderer ships would\n * prove nothing about the shipped shader.\n */\nexport const crossCheckKernelModule = (): string =>\n withPrelude([WGSL_FIELD_KERNELS, WGSL_CROSS_CHECK_PASS].join(\"\\n\\n\"));\n\n/**\n * Every shader this package can compile, concatenated.\n *\n * Exposed as `GlassRenderer.shaderSource` — the seam's honest answer to \"what\n * WGSL does this renderer carry\", and the string core's bundle-shape test finds\n * the marker in.\n */\nexport function allShaderSource(): string {\n return [\n WGSL_PRELUDE,\n fieldPassSource(\"rsupn\"),\n fieldPassSource(\"rsup\"),\n importPassSource(\"sampled\"),\n importPassSource(\"external\"),\n WGSL_DOWNSAMPLE_PASS,\n WGSL_ANALYSIS_PASS,\n silhouetteReductionModule(),\n silhouetteFieldModule(\"rsupn\"),\n silhouetteFieldModule(\"rsup\"),\n WGSL_OPTICS_PASS,\n WGSL_HIGHLIGHT_PASS,\n ].join(\"\\n\\n\");\n}\n","/**\n * The three drawing passes, as GPU work: field, optics, highlight.\n *\n * Each is scoped to the group's device-pixel rect. The field pass renders *into*\n * a group-sized pair of textures; the optics and highlight passes render into the\n * plane canvases with the viewport and the scissor both set to that rect, so the\n * fullscreen triangle's `uv` indexes the field textures one-to-one and\n * `position.xy` stays in canvas coordinates. X1 forbids two glass surfaces\n * overlapping inside one plane, so those rects are disjoint and the scissor is\n * enough — no depth, no stencil, no sorting.\n *\n * Blending is premultiplied source-over on both canvas passes. Against a cleared\n * canvas it is indistinguishable from no blending, and the reason to have it is\n * the case that is not that: an overlay-plane surface drawn over a base-plane one\n * during a cross-plane morph, where the promotion moves the surface as a unit but\n * the frame in flight can still hold both.\n */\n\nimport { OUTPUT_TEXTURE_FORMAT, WORKING_TEXTURE_FORMAT } from \"./color\";\nimport { type GpuContext, createUniformSlot, createStorageSlot, type StorageSlot, type UniformSlot } from \"./gpu-context\";\nimport type { FieldFamily } from \"./governor\";\nimport { INSTANCE_BYTES } from \"./instances\";\nimport { pipelineKey } from \"./pipeline-cache\";\nimport { poolKey } from \"./texture-pool\";\nimport { PASS_LABEL, type PassTimeline } from \"./timing\";\nimport { fieldModule, highlightModule, opticsModule } from \"./wgsl\";\n\n/**\n * Usage masks are computed on FIRST USE, never at module scope.\n *\n * `GPUTextureUsage` is a browser global, and this module is imported outside a\n * browser: `vitrea`'s lazy seam resolves this package in Node to check the\n * renderer's shape (`packages/core/test/renderer-seam.test.ts`). A mask evaluated\n * at module scope makes the whole package throw on import there — a\n * `ReferenceError` from a file that never intended to run, in a test that only\n * wanted to read `backend` and `ready`.\n */\nconst fieldUsage = (): GPUTextureUsageFlags =>\n GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;\n\n/**\n * The field pass's fourth target (W27d): one channel, carrying the surface's\n * presence per pixel.\n *\n * Not `WORKING_TEXTURE_FORMAT`, and the reason is arithmetic rather than taste.\n * The working format carries COLOUR, and this target carries none — it is a\n * per-pixel scalar in `[0, 1]` — so three of four `rgba16float` channels would be\n * bandwidth and memory nothing reads, on a texture allocated per group per frame.\n * The default `maxColorAttachmentBytesPerSample` limit is 32 and the three\n * `rgba16float` targets already spend 24 of it, so a fourth of the same format\n * would also sit the field pass exactly on the limit with no room for the next\n * per-pixel quantity; at two bytes this leaves six.\n *\n * `r16float` is renderable in WebGPU core, and the fragment stage writes a\n * `vec4f` to it — a wider output than the format is valid and the extra\n * components are dropped, while a narrower one is not — so the shader's own\n * declaration stays uniform with the other three targets.\n */\nconst PRESENCE_TEXTURE_FORMAT: GPUTextureFormat = \"r16float\";\n\n/** Premultiplied source-over. See the module note. */\nconst PREMULTIPLIED_OVER: GPUBlendState = {\n color: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n};\n\n/** A rect in device pixels. Integers by construction — see `snapRectToDevicePixels`. */\nexport interface DeviceRect {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface FieldPassArgs {\n /** The group's resource identity on this plane — see `groupResourceId`. */\n readonly resourceId: string;\n readonly family: FieldFamily;\n readonly rectDevice: DeviceRect;\n /** CSS px per device px. */\n readonly cssPerDevice: number;\n /** Coverage ramp width in CSS px. One device pixel, unless the governor widens it. */\n readonly coverageRampCss: number;\n /**\n * The governor's `refractionResolutionScale`, 0 < s <= 1. The field targets are\n * allocated at `rectDevice * s` and the optics and highlight passes upsample\n * them; the *rect* is unchanged, so the group still covers the same pixels.\n * `1` is the nominal path and takes exactly the arithmetic it took before the\n * knob existed.\n */\n readonly renderScale: number;\n readonly instances: Float32Array;\n readonly instanceCount: number;\n readonly union: { readonly neckWidth: number; readonly maxBulge: number; readonly separationThreshold: number };\n}\n\nexport interface FieldTargets {\n readonly field: GPUTexture;\n readonly aux: GPUTexture;\n /** The owning surface's centre and half-extents per pixel (W12 G2) — the lens's oval. */\n readonly aux2: GPUTexture;\n /** The owning surface's presence per pixel (W27d) — one channel, `r16float`. */\n readonly presence: GPUTexture;\n /** The field textures' extent in texels — the group's rect times `renderScale`. */\n readonly width: number;\n readonly height: number;\n /**\n * True when that extent is smaller than the group's rect, so a reader has to\n * filter rather than index. False on the nominal path, where one texel is one\n * device pixel and the read is an exact `textureLoad`.\n */\n readonly upsampled: boolean;\n}\n\ntype BackdropToneKnotRow =\n | readonly [number, number, number]\n | readonly [number, number, number, number];\n\nexport interface OpticsPassArgs {\n /** The group's resource identity on this plane — see `groupResourceId`. */\n readonly resourceId: string;\n readonly target: GPUTextureView;\n readonly targetFormat: GPUTextureFormat;\n readonly rectDevice: DeviceRect;\n readonly fields: FieldTargets;\n /** W28 local linear RGB and decoded encoded level, union-blended per surface. */\n readonly localTone?: GPUTextureView;\n /** Viewport in device px, and CSS px per device px. */\n readonly viewportDevice: readonly [number, number];\n readonly cssPerDevice: number;\n readonly coverageRampCss: number;\n /** Backdrop uv transform on viewport-normalised coordinates. */\n readonly fit: readonly [number, number, number, number];\n readonly refractionScale: number;\n /** The lens's magnitude gain (W12 G2) — `MaterialProfile.lensRefractionGain`. */\n readonly lensRefractionGain: number;\n /**\n * The lens law (W12 G2), evaluated per pixel from the thickness and the span\n * the field carries: the reference's height and amount laws, the thickness\n * they are read at, the profile's extent and exponent, and the direction's\n * ovalization with its knee — see `MaterialProfile.lensRefractionGain`.\n */\n readonly lensHeightPerSpan: number;\n readonly lensHeightMax: number;\n readonly lensAmountPerSpan: number;\n readonly lensAmountMax: number;\n readonly lensThicknessReference: number;\n readonly lensExtentGain: number;\n readonly lensProfileExponent: number;\n readonly lensOvalization: number;\n readonly lensOvalizationSpanMin: number;\n readonly lensOvalizationSpanMax: number;\n /**\n * The inner shadow's depth gain — W2's `lensSizeGainMax`, which the shadow\n * keeps reading after the lens moved to its own law (W12 G2); the shader\n * evaluates the shadow's depth from the same thickness and span.\n */\n readonly shadowDepthSizeGainMax: number;\n readonly chainMaxLod: number;\n readonly tint: readonly [number, number, number];\n readonly tintAlpha: number;\n readonly adaptTint: readonly [number, number, number];\n readonly adaptStrength: number;\n /** The group's author tint seed in linear light, and the shade law it is painted through (W10). */\n readonly tintSeed: readonly [number, number, number];\n readonly tintToneAdaptation: number;\n /** `[tintShadeDark, tintShadeLight, tintShadeStrength]`. */\n readonly tintShade: readonly [number, number, number];\n readonly tintChromaScale?: number;\n readonly tintShadeCollapseRetention?: number;\n readonly rimWidth: number;\n readonly rimAlpha: number;\n /**\n * The retired one-sided specular's two constants (W24; claims §5.108 §1).\n * Retained in this private call shape for the historical profile interface;\n * they are not uploaded. W27c reuses their two uniform slots for tint chroma\n * and shade retention, and its GPU regression test pins these constants inert.\n */\n readonly specularPower: number;\n readonly specularGain: number;\n /**\n * The rim's amplitude law (W23): the gain on the surface's own rendered\n * luminance, and the rim the collapsed appearance keeps — bare, and at an\n * author tint's full coverage.\n */\n readonly rimLevelGain: number;\n readonly rimCollapsed: number;\n readonly rimCollapsedTinted: number;\n /**\n * The lit edge (W24): the axis the rim's directional factor is symmetric about\n * and the factor's exponent. At exponent 0 the factor is 1 for every normal.\n */\n readonly rimLitAxis: readonly [number, number];\n readonly rimLitExponent: number;\n /**\n * W25's three mechanisms (claims §5.113; W25 Decision Log 3), each 0 on the\n * landed material: the along-side field's slope on the rim's amplitude, the\n * heavy share's thick-end lift on `kDeep` already resolved at this group's\n * device ratio, and the level term's gain above the thickness knee.\n */\n readonly rimAlongSideSlope: number;\n readonly sizeScatterHeavyShareThick: number;\n readonly sizeToneLevelFar: number;\n /**\n * The heavy blur (W26; `MaterialProfile.sizeHeavyTapSigma`) — whether this\n * group's source carries one, which is the whole of what this pass needs to\n * know about it.\n *\n * The width itself never reaches here: the pyramid built it into a texture of\n * its own before any group was drawn (`PyramidResources.heavy`), so what the\n * shader does is swap one `textureSampleLevel` of the chain for one\n * `textureSampleLevel` of that texture. False on the landed material and\n * wherever the source has no pyramid, and then the chain's own `scatterLod` tap\n * is what runs — the 0.14.0 path, to the bit.\n */\n readonly heavyTapEnabled: boolean;\n /**\n * W30's span-graded shadow σ (claims §5.156 §2), as three leaves rather than\n * one resolved width: the law is read PER PIXEL from the casting surface's own\n * span, which only the shader knows, so what crosses here is the law and not\n * its value. Slope, reference span and signed thin offset, in the order\n * `MaterialOuterShadow` declares them. All three 0 on the landed material,\n * where the law returns `outerShadow[1]` at every span.\n */\n readonly outerShadowSigmaLaw: readonly [number, number, number];\n /**\n * W30's scale-selective scatter (claims §5.156 §3), the two halves of the\n * spanning set this pass can see.\n *\n * `sizeScatterScaleGain` and `sizeScatterScaleRef` are the material's;\n * `backdropScaleStatistic` is the SOURCE's — the analysis pass's edge density\n * for the source this group samples, which arrives by readback and is\n * therefore resolved by the caller, as `bodyChainLod` is. Where the caller has\n * observed nothing it passes `sizeScatterScaleRef` — the value at which the\n * operator contributes nothing whatever the gain is, which \"no evidence\" has to\n * resolve to and 0 only coincidentally does. `heavySecondShare` is the signed\n * weight of the second heavy sample, and `heavySecondEnabled` says whether the\n * pyramid actually built that texture. Both amounts are 0 on the landed\n * material and the texture is not built there.\n */\n readonly sizeScatterScaleGain: number;\n readonly sizeScatterScaleRef: number;\n readonly backdropScaleStatistic: number;\n readonly sizeHeavySecondShare: number;\n readonly heavySecondEnabled: boolean;\n /**\n * W31's body chroma retention (claims §5.161 §5, §5.164) — how much of the\n * blurred backdrop's chromaticity the body restores, at the luma the tone\n * solve produced. 0 on the runtime default, where the composite is the one\n * W30 left, bit for bit.\n */\n readonly bodyChromaRetention: number;\n /** DOM-layer mode: 0 is off, 1 is unknown tone, and 2 has a measured tone. */\n readonly domMaterial?: {\n readonly mode: number;\n readonly referenceBackdropLuminance: number;\n readonly minimumTintContrast: number;\n };\n readonly rimTintChroma: number;\n readonly lightDirection: readonly [number, number];\n readonly shadowDepth: number;\n readonly shadowAlpha: number;\n /**\n * The size law's gains (W2), applied per pixel against the thickness the\n * shader evaluates from the field pass's span channel. `bodyChainLod` is not\n * a gain but the chain level whose blur already matches the body texture —\n * the origin the scattering term measures its extra octaves from, which only\n * the pyramid that built the body knows.\n *\n * `sizeScatterGainMax` arrives RESOLVED at the ratio the group draws at\n * (W15 G1, claims §5.69 §1): the profile anchors it at dpr 1 and dpr 2 and\n * the caller interpolates, as it already did for the ramp's anchors.\n */\n readonly sizeScatterGainMax: number;\n /**\n * The gain's FAR end at that ratio (W15 G1's re-form, claims §5.70 §4 and §7).\n *\n * The reference's heavy kernel grows with the span, so the gain is a curve and\n * not a number: the shader rises from `sizeScatterGainMax` at `sizeSpanMax` to\n * this at `sizeScatterSpanMax`, along the smoothstep the ramp's far anchor\n * already declines on. Resolved on the CPU like the near end, and equal to it\n * at dpr ≤ 1, where the curve is flat and this uniform changes nothing.\n */\n readonly sizeScatterGainFar: number;\n readonly sizeOcclusionGain: number;\n readonly sizeShadowGainMax: number;\n readonly bodyChainLod: number;\n /**\n * The thickness band (W2) and the scatter facet's frost (W11c), plus the\n * accessibility fold every span-dependent rise multiplies by — the refraction\n * ladder at the preference's cap, the same factor `sizeThicknessUnderPolicy`\n * applies on the CPU. The shader evaluates the thickness curve per pixel from\n * the span the field pass carries; the scattering reads the depth instead.\n */\n readonly sizeSpanMin: number;\n readonly sizeSpanMax: number;\n readonly sizeScatterFloor: number;\n /**\n * The scatter facet's span curve (W11c), which since W13 G1 is the depth\n * ramp's DEEP value: the shader evaluates `floor + (1 − floor) ·\n * smoothstep(sizeSpanMin, sizeScatterSpanMax, span)` per pixel from the span\n * the field pass carries, exactly as it did before the ramp.\n *\n * This and `sizeScatterFloor` also arrive RESOLVED at the ratio (W15 G1,\n * claims §5.69 §2): the deep value is a per-scale law now, and the shader\n * reads one floor and one span top whatever scale produced them.\n */\n readonly sizeScatterSpanMax: number;\n /**\n * The body depth ramp (W13 G1, claims §5.61 §2, §5.64 §5), resolved once per\n * group from the ratio the renderer draws at: the sharp share at the contour\n * at each end of the material's thin/thick curve, and the reach at which the\n * ramp's excursion vanishes into the span curve above, **in CSS px** — the\n * profile names the reach in device px and the caller divides, because the\n * depth the shader has is the field's own and that is in group-local CSS px.\n * All three are already interpolated between the profile's 1x and 2x anchors.\n *\n * The start arrives as its two ENDS rather than as one resolved number: it\n * grades along `sizeThickness(span)` and a group's members need not be one\n * size, so the shader mixes the two ends by the same span the field already\n * carries per pixel.\n */\n readonly sizeScatterRampStartThin: number;\n readonly sizeScatterRampStartThick: number;\n /** The start at `sizeScatterSpanMax` and beyond (the fourth form); the shader declines to it. */\n readonly sizeScatterRampStartFar: number;\n readonly sizeScatterRampReachCssPx: number;\n readonly sizeFold: number;\n /**\n * Backdrop tone adaptation (W7): `[low, high, sizeBiasUnderPolicy, strength]`.\n *\n * The bias is the profile's own divided by the accessibility refraction cap\n * (`backdropToneSizeBiasUnderPolicy`), because the shader multiplies it by the\n * policy-folded `sizeK` while the gate it expresses is geometric.\n */\n readonly backdropTone: readonly [number, number, number, number];\n /**\n * The backdrop source's average colour in linear light, and its luminance —\n * what the adaptation adapts toward, measured by the host. `backdropTone`'s\n * strength is 0 where there is none, so this is not read.\n */\n readonly backdropToneColour: readonly [number, number, number, number];\n /**\n * The outer shadow (W8): `[thinOcclusion, sigmaCss, spreadCss, offsetFieldUv]`.\n *\n * `thinOcclusion` is the THIN regime's peak occlusion in LINEAR light,\n * resolved at this group's backdrop luminance (W14 G1's adaptive alpha, whose\n * key is one number per group) and folded under the accessibility policy. It\n * is no longer a compositing-space alpha, because the shader blends the two\n * regimes before it converts, and the conversion is not linear. The size law\n * is per pixel and stays in the shader. The offset arrives as a **field-texture\n * UV** rather than as CSS px, because only the caller knows how tall the rect\n * the field was rasterised into is.\n */\n readonly outerShadow: readonly [number, number, number, number];\n /**\n * The outer shadow's thick regime (W14 G1): the composite's peak linear\n * occlusion at casting spans 96, 128 and 160 CSS px, folded under the same\n * policy. The shader interpolates between them per pixel from the span the\n * field carries and holds them outside.\n */\n readonly outerShadowThick: readonly [number, number, number];\n /**\n * The lift (W14 G1), the shadow's second term and this tier's alone:\n * `[amplitude, spanMinCss, spanFullCss, chainLod]`.\n *\n * `amplitude` is in LINEAR light, a fraction of the blurred backdrop's own\n * luminance, and is zero where the policy stood the term down. `chainLod` is\n * the continuous chain level whose blur is the profile's `liftBlurSigmaCss` —\n * resolved through the pyramid's own CSS-px-to-texel density and plan\n * downscale, exactly as `bodyChainLod` is, and clamped to `chainMaxLod`.\n */\n readonly outerShadowLift: readonly [number, number, number, number];\n /** The outer shadow's size-law gain — see `MaterialOuterShadow.sizeGain`. */\n readonly outerShadowSizeGain: number;\n /**\n * The field rect's height in CSS px — what the shadow's shift converts through\n * when it lands outside the field texture.\n *\n * The rect is clipped to the canvas and its pad is only the shadow's reach, so\n * the shift runs off the top of the texture both for a surface near the\n * viewport's top edge and, always, for the topmost band of every group. The\n * shader reconstructs the distance it could not read; this is the scale it\n * reconstructs in.\n */\n readonly outerShadowRectCssHeight: number;\n /**\n * The backdrop tone response's anchors (W9): the three solid anchors'\n * encoded-space means, and the reference's settled interior levels there for\n * a thin (`sizeThickness` 0) and a thick (saturated) surface. See\n * `MaterialProfile.backdropToneAnchorX`.\n */\n readonly backdropToneAnchorX: BackdropToneKnotRow;\n readonly backdropToneResponseThin: BackdropToneKnotRow;\n readonly backdropToneResponseThick: BackdropToneKnotRow;\n /** The response law's per-profile authority (0 on dark profiles) — see\n * `MaterialProfile.backdropToneResponseStrength`. */\n readonly backdropToneResponseStrength: number;\n /**\n * How far the collapse's target moves from the group's mean backdrop colour\n * to the per-pixel blurred sample (W24 G1) — see\n * `MaterialProfile.collapseTransmission`. At 0 the collapse is W7's.\n */\n readonly collapseTransmission: number;\n /**\n * The backdrop's LINEAR-space mean under the same weighting as the tone\n * colour — what the response solve composites against. Falls back to the\n * tone level where the host measured no separate linear mean.\n */\n readonly backdropToneLinearMean: number;\n readonly backdrop:\n | {\n readonly chain: GPUTextureView;\n readonly body: GPUTextureView;\n /** The heavy blur (W26), absent where the profile named no width. */\n readonly heavy: GPUTextureView | undefined;\n /**\n * The SECOND heavy blur (W30 G2), absent wherever\n * `MaterialProfile.sizeHeavySecondShare` is 0 — which is everywhere on\n * the landed material, and is what makes the operator cost nothing\n * until §5.159 turns it on.\n */\n readonly heavy2: GPUTextureView | undefined;\n }\n | undefined;\n}\n\nexport interface HighlightPassArgs {\n /** The group's resource identity on this plane — see `groupResourceId`. */\n readonly resourceId: string;\n readonly target: GPUTextureView;\n readonly targetFormat: GPUTextureFormat;\n readonly rectDevice: DeviceRect;\n readonly fields: FieldTargets;\n readonly localTone?: GPUTextureView;\n readonly viewportDevice: readonly [number, number];\n readonly cssPerDevice: number;\n readonly sweep: number;\n readonly sweepBandRadians: number;\n /**\n * The band's gain, already multiplied by the lead surface's `shimmer` channel\n * by the caller (W22). It is exactly 0 on a resting surface, which is what\n * makes the sweep term vanish rather than park itself on the left edge, and\n * this pass takes it as one number because the shader has no business knowing\n * which of the two factors was zero.\n */\n readonly sweepGain: number;\n readonly rimWidth: number;\n readonly pressPointCss: readonly [number, number];\n readonly glowRadiusCss: number;\n readonly glowGain: number;\n readonly colour: readonly [number, number, number];\n /**\n * The optics pass's `backdropTone` and the backdrop's own luminance, forwarded\n * unchanged (W7). A highlight is the material catching light, and a material\n * that has taken its backdrop's tone is not there to catch any — so this pass\n * evaluates the same curve off the same numbers rather than a second copy.\n */\n readonly backdropTone: readonly [number, number, number, number];\n readonly backdropToneLevel: number;\n /**\n * The thickness band and the accessibility fold (W11c), so this pass evaluates\n * the size curve off the per-pixel span exactly as the optics pass does.\n */\n readonly sizeSpanMin: number;\n readonly sizeSpanMax: number;\n readonly sizeFold: number;\n /**\n * The rect the FIELD textures were rasterised into, which since W8 is bigger\n * than `rectDevice`.\n *\n * The outer shadow made the field rect grow by the shadow's reach — about 46\n * CSS px against the rim-and-bulge margin's 3 — and this pass draws nothing out\n * there: `fs_highlight` returns on `coverage <= 0`, so every one of those\n * fragments was rasterised, read twice and discarded. So the pass keeps the\n * small rect as its viewport and scissor and reads the field through the remap\n * this pair implies.\n *\n * **Worth less than it looks, and the number is here rather than a hope.** A/B\n * against the same tree without this scoping, three interleaved bench runs\n * each, comparing the shadow-on to shadow-off ratio on the mobile scene: 3.11\n * against 3.35 at the median, with the two ranges overlapping (2.92…3.37\n * against 3.20…3.62). So this recovers roughly 7% of the shadow's cost, not the\n * third this pass's own timestamp suggested — most of that timestamp is the\n * field texture's write draining into the next pass rather than this pass's own\n * fragments. It stays because it is strictly less work for byte-identical\n * output (the `highlight-press-glow` golden does not move), not because the\n * benchmark can see it clearly.\n */\n readonly fieldRectDevice: DeviceRect;\n}\n\nexport interface PassRunner {\n fieldPass(encoder: GPUCommandEncoder, args: FieldPassArgs): FieldTargets;\n opticsPass(encoder: GPUCommandEncoder, args: OpticsPassArgs): void;\n highlightPass(encoder: GPUCommandEncoder, args: HighlightPassArgs): void;\n /** A 1×1 transparent texture, for binding a backdrop that is not there. */\n readonly placeholderView: GPUTextureView;\n /** Clear a plane canvas before the group passes, which load rather than clear. */\n clearPass(encoder: GPUCommandEncoder, target: GPUTextureView): void;\n /** Attach a timing collector for this frame, or `undefined` to time nothing. */\n setTimeline(timeline: PassTimeline | undefined): void;\n /**\n * Release everything allocated under one resource identity — the four field\n * textures, the instance storage buffer and the three uniform buffers.\n *\n * Idempotent, because it is reached on every frame a group draws nothing on\n * a plane and not only when the group goes away: the pool and both slot maps\n * treat a key that is not there as nothing to do.\n */\n forget(resourceId: string): void;\n destroy(): void;\n}\n\n/**\n * A group's resource identity, which is its id qualified by the plane it is\n * being drawn on.\n *\n * Every pooled texture, uniform buffer and storage buffer in this file is keyed\n * on this rather than on the group id, and the reason is that one group id can\n * legitimately draw on two planes at once. `GlassMorph transition=\"materialize\"`\n * registers both endpoints under one group (claims §5.132 §5) and the host draws\n * one plane per `drawFrame` against that plane's canvases, so the two endpoints\n * reach `fieldPass` with the same id and different rects. Keyed on the id alone\n * each plane's `acquire` failed the other's `sameShape` check and destroyed and\n * reallocated all four field textures — twice a frame for the length of the\n * transition, for pixels that were already correct.\n *\n * Only the resource namespace splits. The LOGICAL group — what `setGroup`,\n * `removeGroup`, the resolved-state readouts and the skipped-group reports name,\n * and the id an author sees — is one group on one id, and nothing here changes\n * that. The empty plane is the whole namespace for a host that draws one set of\n * canvases, so a standalone renderer and every golden key exactly as before.\n */\nexport const groupResourceId = (plane: string, groupId: string): string =>\n plane === \"\" ? groupId : `${plane}/${groupId}`;\n\nexport function createPassRunner(context: GpuContext): PassRunner {\n const { device, pool, cache } = context;\n const uniforms = new Map<string, UniformSlot>();\n const storages = new Map<string, StorageSlot>();\n\n // `rgba16float` tops out near 65504, so the \"no surface here\" distance is a\n // large FINITE value: an overflow to +Inf would make every later arithmetic on\n // it a NaN, and NaN coverage is not reliably zero.\n const EMPTY_DISTANCE = 65000;\n\n const placeholder = device.createTexture({\n label: \"vitrea:placeholder\",\n size: { width: 1, height: 1, depthOrArrayLayers: 1 },\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n });\n\n const uniformSlot = (key: string, floats: number): UniformSlot => {\n let slot = uniforms.get(key);\n if (slot === undefined) {\n slot = createUniformSlot(device, floats, `vitrea:uniform:${key}`);\n uniforms.set(key, slot);\n }\n return slot;\n };\n\n const storageSlot = (key: string): StorageSlot => {\n let slot = storages.get(key);\n if (slot === undefined) {\n slot = createStorageSlot(device, 8 * INSTANCE_BYTES, `vitrea:instances:${key}`);\n storages.set(key, slot);\n }\n return slot;\n };\n\n const fieldPipeline = (family: FieldFamily): GPURenderPipeline =>\n cache.renderPipeline(pipelineKey.field(family, WORKING_TEXTURE_FORMAT), () => {\n const module = cache.module(`module:field:${family}`, () => fieldModule(family));\n return {\n label: `vitrea:pipeline:field:${family}`,\n layout: \"auto\",\n vertex: { module, entryPoint: \"vs_fullscreen\" },\n fragment: {\n module,\n entryPoint: \"fs_field\",\n targets: [\n { format: WORKING_TEXTURE_FORMAT },\n { format: WORKING_TEXTURE_FORMAT },\n { format: WORKING_TEXTURE_FORMAT },\n { format: PRESENCE_TEXTURE_FORMAT },\n ],\n },\n primitive: { topology: \"triangle-list\" },\n };\n });\n\n const opticsPipeline = (format: GPUTextureFormat): GPURenderPipeline =>\n cache.renderPipeline(pipelineKey.optics(format, \"premultiplied-over\"), () => {\n const module = cache.module(\"module:optics\", opticsModule);\n return {\n label: \"vitrea:pipeline:optics\",\n layout: \"auto\",\n vertex: { module, entryPoint: \"vs_fullscreen\" },\n fragment: {\n module,\n entryPoint: \"fs_optics\",\n targets: [{ format, blend: PREMULTIPLIED_OVER }],\n },\n primitive: { topology: \"triangle-list\" },\n };\n });\n\n const highlightPipeline = (format: GPUTextureFormat): GPURenderPipeline =>\n cache.renderPipeline(pipelineKey.highlight(format, \"premultiplied-over\"), () => {\n const module = cache.module(\"module:highlight\", highlightModule);\n return {\n label: \"vitrea:pipeline:highlight\",\n layout: \"auto\",\n vertex: { module, entryPoint: \"vs_fullscreen\" },\n fragment: {\n module,\n entryPoint: \"fs_highlight\",\n targets: [{ format, blend: PREMULTIPLIED_OVER }],\n },\n primitive: { topology: \"triangle-list\" },\n };\n });\n\n const scoped = (\n pass: GPURenderPassEncoder,\n rect: DeviceRect,\n ): void => {\n pass.setViewport(rect.x, rect.y, rect.width, rect.height, 0, 1);\n // The oversized fullscreen triangle reaches past the viewport; the scissor is\n // what stops it writing another group's pixels.\n pass.setScissorRect(rect.x, rect.y, rect.width, rect.height);\n };\n\n const placeholderView = placeholder.createView();\n let timeline: PassTimeline | undefined;\n\n /** `timestampWrites` is only legal when the device enabled `timestamp-query`. */\n const timed = (label: string): { timestampWrites?: GPURenderPassTimestampWrites } => {\n const slot = timeline?.renderSlot(label);\n return slot === undefined ? {} : { timestampWrites: slot };\n };\n\n return {\n placeholderView,\n\n fieldPass(encoder, args) {\n // The rect the group occupies on the canvas, and the extent the field is\n // rasterised at. They differ only under the governor's resolution knob, and\n // at scale 1 the second is the first — `Math.round(w * 1)` on an integer.\n const rectWidth = Math.max(1, Math.round(args.rectDevice.width));\n const rectHeight = Math.max(1, Math.round(args.rectDevice.height));\n const width = Math.max(1, Math.round(args.rectDevice.width * args.renderScale));\n const height = Math.max(1, Math.round(args.rectDevice.height * args.renderScale));\n\n const field = pool.acquire(poolKey.groupField(args.resourceId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.resourceId}:field`,\n });\n const aux = pool.acquire(poolKey.groupAux(args.resourceId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.resourceId}:aux`,\n });\n const aux2 = pool.acquire(poolKey.groupAux2(args.resourceId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.resourceId}:aux2`,\n });\n const presence = pool.acquire(poolKey.groupPresence(args.resourceId), {\n width,\n height,\n format: PRESENCE_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.resourceId}:presence`,\n });\n\n // Twelve floats: screen, unionP, counts. The group's origin is deliberately\n // absent — instance centres are packed relative to it, so the shader works\n // in group-local coordinates and never adds it back.\n //\n // `screen.xy` is the group's extent in DEVICE px, not the target's, because\n // the shader multiplies it by `screen.z` to recover group-local CSS. Under\n // the resolution knob the target shrinks while the group does not, and it\n // is the group the geometry is expressed in.\n const slot = uniformSlot(`field:${args.resourceId}`, 12);\n slot.data[0] = rectWidth;\n slot.data[1] = rectHeight;\n slot.data[2] = args.cssPerDevice;\n // One TARGET pixel wide, so the analytic coverage stays one texel of\n // antialiasing however coarse the target is. At scale 1 the ratio is 1.\n slot.data[3] = args.coverageRampCss * (rectWidth / width);\n slot.data[4] = args.union.neckWidth;\n slot.data[5] = args.union.maxBulge;\n slot.data[6] = args.union.separationThreshold;\n slot.data[7] = 0;\n // `counts` is a vec4u in the shader; a Float32Array cannot write a u32, so\n // the count goes through a Uint32 view of the same words.\n slot.data[9] = 0;\n slot.data[10] = 0;\n slot.data[11] = 0;\n new Uint32Array(slot.data.buffer, slot.data.byteOffset + 32, 1)[0] = args.instanceCount;\n slot.write();\n\n const instances = storageSlot(args.resourceId);\n instances.ensure(Math.max(args.instanceCount, 1) * INSTANCE_BYTES);\n instances.write(args.instances, Math.max(args.instanceCount, 1) * (INSTANCE_BYTES / 4));\n\n const pipeline = fieldPipeline(args.family);\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:field:${args.resourceId}`,\n ...timed(PASS_LABEL.field),\n colorAttachments: [\n {\n view: field.createView(),\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: EMPTY_DISTANCE, g: 0, b: -1, a: 0 },\n },\n {\n view: aux.createView(),\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n {\n view: aux2.createView(),\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n {\n view: presence.createView(),\n loadOp: \"clear\",\n // Cleared to the IDLE presence rather than to zero: a texel the\n // fullscreen triangle never wrote must not read as a material that\n // has been asked to disappear.\n storeOp: \"store\",\n clearValue: { r: 1, g: 0, b: 0, a: 0 },\n },\n ],\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: { buffer: instances.buffer } },\n ],\n }),\n );\n pass.draw(3);\n pass.end();\n\n return {\n field,\n aux,\n aux2,\n presence,\n width,\n height,\n upsampled: width !== rectWidth || height !== rectHeight,\n };\n },\n\n opticsPass(encoder, args) {\n const slot = uniformSlot(`optics:${args.resourceId}`, 136);\n const d = slot.data;\n d[0] = args.viewportDevice[0];\n d[1] = args.viewportDevice[1];\n d[2] = args.cssPerDevice;\n d[3] = args.coverageRampCss;\n d[4] = args.fit[0];\n d[5] = args.fit[1];\n d[6] = args.fit[2];\n d[7] = args.fit[3];\n d[8] = args.refractionScale;\n d[9] = args.lensRefractionGain;\n // The inner shadow's depth gain (W12 G2): W2's size gain, which the\n // shadow keeps after the lens moved to its own law below.\n d[10] = args.shadowDepthSizeGainMax;\n d[11] = args.chainMaxLod;\n d[12] = args.tint[0];\n d[13] = args.tint[1];\n d[14] = args.tint[2];\n d[15] = args.tintAlpha;\n d[16] = args.adaptTint[0];\n d[17] = args.adaptTint[1];\n d[18] = args.adaptTint[2];\n d[19] = args.adaptStrength;\n d[20] = args.tintSeed[0];\n d[21] = args.tintSeed[1];\n d[22] = args.tintSeed[2];\n d[23] = args.tintToneAdaptation;\n d[24] = args.tintShade[0];\n d[25] = args.tintShade[1];\n d[26] = args.tintShade[2];\n d[27] = args.sizeFold;\n d[28] = args.rimWidth;\n d[29] = args.rimAlpha;\n // W27c reuses the two slots retired with W24's one-sided specular.\n d[30] = args.tintChromaScale ?? 1;\n d[31] = args.tintShadeCollapseRetention ?? 0;\n d[32] = args.lightDirection[0];\n d[33] = args.lightDirection[1];\n d[34] = args.shadowDepth;\n d[35] = args.shadowAlpha;\n d[36] = args.backdrop === undefined ? 0 : 1;\n d[37] = args.fields.width;\n d[38] = args.fields.height;\n d[39] = args.fields.upsampled ? 1 : 0;\n d[40] = args.sizeScatterGainMax;\n d[41] = args.sizeOcclusionGain;\n d[42] = args.sizeShadowGainMax;\n d[43] = args.bodyChainLod;\n d[44] = args.backdropTone[0];\n // The shader divides by `max(high - low, 1e-6)` rather than calling\n // `smoothstep`, so a coinciding pair degrades to a step instead of a NaN —\n // but the floor is kept here too so both tiers see the same edges.\n d[45] = Math.max(args.backdropTone[1], args.backdropTone[0] + 1e-4);\n d[46] = args.backdropTone[2];\n d[47] = args.backdropTone[3];\n d[48] = args.backdropToneColour[0];\n d[49] = args.backdropToneColour[1];\n d[50] = args.backdropToneColour[2];\n d[51] = args.backdropToneColour[3];\n d[52] = args.outerShadow[0];\n d[53] = args.outerShadow[1];\n d[54] = args.outerShadow[2];\n d[55] = args.outerShadow[3];\n d[56] = args.outerShadowSizeGain;\n d[57] = args.outerShadowRectCssHeight;\n // The depth ramp's THICK start (W13 G1's third form), in the first of\n // this vec4's two padding slots. The scatter vec4 holds four numbers\n // already and the ramp's second start needs a home; a padding slot of a\n // vec4 the shader reads anyway costs no bytes and no second binding, and\n // the shader's own comment names it where it is read.\n d[58] = args.sizeScatterRampStartThick;\n // The heavy width's gain at the scatter span curve's TOP (W15 G1's\n // re-form, claims §5.70 §4 and §7), in this vec4's second padding slot.\n // The gain's near end is `size.x` and that vec4 is full; this one already\n // carries the ramp's other span-graded end, so the body's two curves over\n // the same smoothstep sit beside each other. The layout's size is\n // unchanged — the slot was written as zero.\n d[59] = args.sizeScatterGainFar;\n // The response law's anchors and rows (W9), and the linear backdrop mean\n // the solve composites against.\n d[60] = args.backdropToneAnchorX[0];\n d[61] = args.backdropToneAnchorX[1];\n d[62] = args.backdropToneAnchorX[2];\n d[63] = args.backdropToneLinearMean;\n d[64] = args.backdropToneResponseThin[0];\n d[65] = args.backdropToneResponseThin[1];\n d[66] = args.backdropToneResponseThin[2];\n d[67] = args.backdropToneResponseStrength;\n d[68] = args.backdropToneResponseThick[0];\n d[69] = args.backdropToneResponseThick[1];\n d[70] = args.backdropToneResponseThick[2];\n // The collapse's transmission (W24 G1), in the tone block's one padding\n // slot; the other three vec4s of the block are full and a collapse\n // constant living outside it is a layout nobody could read. The slot was\n // written as zero, which is this constant's inert value, so the buffer's\n // size and every default render are unchanged.\n d[71] = args.collapseTransmission;\n d[72] = args.sizeScatterFloor;\n // The depth ramp's THIN start (W13 G1), in the slot the retired\n // `sizeScatterSpanMax` held — the scatter facet's second number, where its\n // second number has always been. The thick end is at d[58].\n d[73] = args.sizeScatterRampStartThin;\n d[74] = args.sizeSpanMin;\n d[75] = args.sizeSpanMax;\n // The lens law (W12 G2, claims §5.51): the reference's height and amount\n // laws, then the profile's extent, exponent and ovalization, then the\n // ovalization's knee. The shader evaluates every one per pixel from the\n // thickness and the span the field carries.\n d[76] = args.lensHeightPerSpan;\n d[77] = args.lensHeightMax;\n d[78] = args.lensAmountPerSpan;\n d[79] = args.lensAmountMax;\n d[80] = args.lensExtentGain;\n d[81] = args.lensProfileExponent;\n d[82] = args.lensOvalization;\n d[83] = args.lensThicknessReference;\n d[84] = args.lensOvalizationSpanMin;\n d[85] = args.lensOvalizationSpanMax;\n // The depth ramp's reach in CSS px (W13 G1), in the first of this vec4's\n // two padding slots rather than in a vec4 of its own — the slot W12 G3's\n // retired scale shift briefly held.\n d[86] = args.sizeScatterRampReachCssPx;\n // The scatter span curve's band top (W11c), in this vec4's second padding\n // slot: W13 G1's re-forming keeps the curve underneath the ramp as its\n // deep value, so the shader needs both the span and the depth.\n d[87] = args.sizeScatterSpanMax;\n // The outer shadow's second regime and its second term (W14 G1). The\n // buffer grows by two vec4s rather than borrowing the three free slots\n // above, because the shadow's own block is `shadow` / `shadowSize` and a\n // shadow constant living in `lensOval.zw` would be a layout nobody could\n // read. `d[91]` stays free.\n d[88] = args.outerShadowThick[0];\n d[89] = args.outerShadowThick[1];\n d[90] = args.outerShadowThick[2];\n // The depth ramp's FAR start (W13 G1's fourth form), in the padding slot\n // W14 left free beside the thick regime's three anchors; the shader's own\n // comment names it where it is read.\n d[91] = args.sizeScatterRampStartFar;\n d[92] = args.outerShadowLift[0];\n d[93] = args.outerShadowLift[1];\n d[94] = args.outerShadowLift[2];\n d[95] = args.outerShadowLift[3];\n // The rim's amplitude law (W23), in a vec4 of its own rather than in a\n // padding slot: the rim's own vec4 is full at four numbers and a rim\n // constant living in the shadow's block is a layout nobody could read.\n // Full since W23 G3, whose `rimTintChroma` took the slot left free.\n d[96] = args.rimLevelGain;\n d[97] = args.rimCollapsed;\n d[98] = args.rimCollapsedTinted;\n d[99] = args.rimTintChroma;\n // The lit edge (W24), in a vec4 of its own because `rimLaw` has been full\n // since W23 G3 and an axis living in the shadow's block is a layout nobody\n // could read. `d[103]` is W25's along-side slope, below.\n d[100] = args.rimLitAxis[0];\n d[101] = args.rimLitAxis[1];\n d[102] = args.rimLitExponent;\n // W25's three mechanisms (claims §5.113). The along-side field's slope\n // takes the slot W24 left free beside the lit edge it grades; the share\n // law's lift and the level term open one more vec4, whose (z) and (w) are\n // the next wave's.\n d[103] = args.rimAlongSideSlope;\n d[104] = args.sizeScatterHeavyShareThick;\n d[105] = args.sizeToneLevelFar;\n d[106] = 0;\n d[107] = 0;\n // The heavy blur's enable (W26). One vec4 of its own rather than a slot in\n // the thick-span composite's padding, because a width's switch living in\n // another facet's spare lane is a layout nobody could read back; the other\n // three components are free and stay zero. At the inert default this is 0\n // and the pass takes the chain tap it has always taken, so the bytes are\n // the 0.14.0 bed's.\n d[108] = args.heavyTapEnabled ? 1 : 0;\n // The DOM solve uses the otherwise idle lanes only on a host DOM group.\n // Texture draws keep all three padding words zero, including their bytes.\n d[109] = args.domMaterial?.mode ?? 0;\n d[110] = args.domMaterial?.referenceBackdropLuminance ?? 0;\n d[111] = args.domMaterial?.minimumTintContrast ?? 0;\n // Decision Log 18's optional fourth backdrop-response knot. Appended as a\n // vec4 so every existing uniform keeps its offset; w is the length gate.\n d[112] = args.backdropToneAnchorX[3] ?? args.backdropToneAnchorX[2];\n d[113] = args.backdropToneResponseThin[3] ?? args.backdropToneResponseThin[2];\n d[114] = args.backdropToneResponseThick[3] ?? args.backdropToneResponseThick[2];\n d[115] = args.backdropToneAnchorX.length === 4 ? 1 : 0;\n d[116] = args.localTone === undefined ? 0 : 1;\n // W30's two operators, each in a vec4 of its own rather than in the\n // padding of a facet it does not belong to (`heavyTap`'s own precedent).\n // Every word below is 0 on the landed material, so the bytes this pass\n // writes are the 0.19.0 bed's with three zeroed vec4s appended.\n // 117..119 are `localTone`'s own three padding words, which stay zero: a\n // vec4 starts every four floats, so the next one begins at 120 and an\n // operator packed from 117 would read three of its neighbour's lanes.\n d[120] = args.outerShadowSigmaLaw[0];\n d[121] = args.outerShadowSigmaLaw[1];\n d[122] = args.outerShadowSigmaLaw[2];\n d[123] = 0;\n d[124] = args.sizeScatterScaleGain;\n d[125] = args.sizeScatterScaleRef;\n d[126] = args.backdropScaleStatistic;\n d[127] = 0;\n d[128] = args.sizeHeavySecondShare;\n d[129] = args.heavySecondEnabled ? 1 : 0;\n d[130] = 0;\n d[131] = 0;\n // W31's body chroma retention, in a vec4 of its own on the same rule as\n // W30's three above: 132 is the next vec4 boundary and an operator packed\n // into 130 would read two of its neighbour's lanes. 0 on the landed\n // default, so the bytes this pass writes are the 0.20.0 bed's with one\n // zeroed vec4 appended.\n d[132] = args.bodyChromaRetention;\n d[133] = 0;\n d[134] = 0;\n d[135] = 0;\n slot.write();\n\n const chain = args.backdrop?.chain ?? placeholderView;\n const body = args.backdrop?.body ?? placeholderView;\n // The heavy texture is bound at every draw because the bind group's layout\n // is one layout; where there is none the placeholder stands in it and the\n // enable above is what keeps the shader from reading it.\n const heavy = args.backdrop?.heavy ?? placeholderView;\n // W30's second heavy texture, on the same rule: one layout, so the slot is\n // always filled, and the enable above is what keeps the shader from\n // reading the placeholder.\n const heavy2 = args.backdrop?.heavy2 ?? placeholderView;\n\n const pipeline = opticsPipeline(args.targetFormat);\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:optics:${args.resourceId}`,\n ...timed(PASS_LABEL.optics),\n colorAttachments: [{ view: args.target, loadOp: \"load\", storeOp: \"store\" }],\n });\n pass.setPipeline(pipeline);\n scoped(pass, args.rectDevice);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: args.fields.field.createView() },\n { binding: 2, resource: args.fields.aux.createView() },\n { binding: 3, resource: context.chainSampler },\n { binding: 4, resource: chain },\n { binding: 5, resource: body },\n // Linear, no mips: the field targets have one level, and this is only\n // read at all when the governor shrank them below the group's rect.\n { binding: 6, resource: context.flatSampler },\n { binding: 7, resource: args.fields.aux2.createView() },\n { binding: 8, resource: heavy },\n { binding: 9, resource: args.fields.presence.createView() },\n { binding: 10, resource: args.localTone ?? placeholderView },\n { binding: 11, resource: heavy2 },\n ],\n }),\n );\n pass.draw(3);\n pass.end();\n },\n\n highlightPass(encoder, args) {\n const slot = uniformSlot(`highlight:${args.resourceId}`, 32);\n const d = slot.data;\n d[0] = args.viewportDevice[0];\n d[1] = args.viewportDevice[1];\n d[2] = args.cssPerDevice;\n d[3] = 0;\n d[4] = args.sweep;\n d[5] = args.sweepBandRadians;\n d[6] = args.sweepGain;\n d[7] = args.rimWidth;\n d[8] = args.pressPointCss[0];\n d[9] = args.pressPointCss[1];\n d[10] = args.glowRadiusCss;\n d[11] = args.glowGain;\n d[12] = args.colour[0];\n d[13] = args.colour[1];\n d[14] = args.colour[2];\n d[15] = 0;\n d[16] = args.fields.width;\n d[17] = args.fields.height;\n d[18] = args.fields.upsampled ? 1 : 0;\n d[19] = args.localTone === undefined ? 0 : 1;\n d[20] = args.backdropTone[0];\n d[21] = Math.max(args.backdropTone[1], args.backdropTone[0] + 1e-4);\n d[22] = args.backdropTone[2];\n d[23] = args.backdropTone[3];\n d[24] = args.backdropToneLevel;\n d[25] = args.sizeSpanMin;\n d[26] = args.sizeSpanMax;\n d[27] = args.sizeFold;\n /*\n * This pass's uv into the field texture's uv (W8). The field rect is the\n * one the shadow needs; this pass is scoped to the one the surface needs,\n * which is smaller, so the two no longer index one-to-one.\n *\n * Derived from the two rects rather than passed in already-divided, so the\n * one place that knows both is the one place that computes it.\n */\n const fieldRect = args.fieldRectDevice;\n d[28] = args.rectDevice.width / Math.max(fieldRect.width, 1e-6);\n d[29] = args.rectDevice.height / Math.max(fieldRect.height, 1e-6);\n d[30] = (args.rectDevice.x - fieldRect.x) / Math.max(fieldRect.width, 1e-6);\n d[31] = (args.rectDevice.y - fieldRect.y) / Math.max(fieldRect.height, 1e-6);\n slot.write();\n\n const pipeline = highlightPipeline(args.targetFormat);\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:highlight:${args.resourceId}`,\n ...timed(PASS_LABEL.highlight),\n colorAttachments: [{ view: args.target, loadOp: \"load\", storeOp: \"store\" }],\n });\n pass.setPipeline(pipeline);\n scoped(pass, args.rectDevice);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: args.fields.field.createView() },\n { binding: 2, resource: args.fields.aux.createView() },\n { binding: 3, resource: context.flatSampler },\n { binding: 4, resource: args.fields.presence.createView() },\n { binding: 5, resource: args.localTone ?? placeholderView },\n ],\n }),\n );\n pass.draw(3);\n pass.end();\n },\n\n clearPass(encoder, target) {\n // Deliberately untimed. A render pass with no draw commands is resolved by\n // the driver without ever writing its timestamp pair, so a slot taken here\n // comes back as (0, 0) — indistinguishable from a query that failed. Leaving\n // it out is what lets a non-zero anomaly count mean something.\n const pass = encoder.beginRenderPass({\n label: \"vitrea:pass:clear\",\n colorAttachments: [\n {\n view: target,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n });\n pass.end();\n },\n\n setTimeline(next) {\n timeline = next;\n },\n\n forget(resourceId) {\n pool.release(poolKey.groupField(resourceId));\n pool.release(poolKey.groupAux(resourceId));\n pool.release(poolKey.groupAux2(resourceId));\n pool.release(poolKey.groupPresence(resourceId));\n storages.get(resourceId)?.destroy();\n storages.delete(resourceId);\n for (const pass of [\"field\", \"optics\", \"highlight\"]) {\n const key = `${pass}:${resourceId}`;\n uniforms.get(key)?.buffer.destroy();\n uniforms.delete(key);\n }\n },\n\n destroy() {\n for (const slot of uniforms.values()) slot.buffer.destroy();\n uniforms.clear();\n for (const slot of storages.values()) slot.destroy();\n storages.clear();\n placeholder.destroy();\n },\n };\n}\n\n/** The output format the plane canvases and the golden readback both use (X5). */\nexport const CANVAS_FORMAT = OUTPUT_TEXTURE_FORMAT;\n","/**\n * How large a backdrop's pyramid is, and which level each consumer reads —\n * decided on the CPU, in one pure function, before any texture exists.\n *\n * §Performance envelope: \"Effect-texture resolution is decoupled from DOM DPR.\"\n * That decoupling lives here: level 0 is the *source's* size scaled by the\n * resolution policy and capped by `maxDimension`, never the viewport's device\n * pixel count. A 4K video behind a 390-px-wide phone viewport does not get a 4K\n * pyramid, and a governor that halves `scale` halves the whole chain's cost\n * without touching a shader.\n *\n * ## Level count\n *\n * The chain stops when the shorter side would fall below `MIN_LEVEL_EXTENT`. Below\n * about 8 px a level carries no usable structure and the bilinear taps of the\n * 13-tap downsample start reading mostly clamped edge, so the levels past that\n * point cost bandwidth and add nothing. That also bounds the maximum LOD the\n * optics pass may ask for, which is why `maxLod` is part of the plan rather than\n * computed in the shader.\n *\n * ## The analysis level\n *\n * Not the coarsest: the coarsest level has had every edge blurred out of it, so an\n * edge-density measurement there would report the same small number for a\n * photograph and for a flat colour. The plan picks the level nearest\n * `ANALYSIS_TARGET_EXTENT`, which keeps the measurement's spatial frequency band\n * fixed as the source's resolution changes — a stat that moved when the\n * resolution policy moved would make the governor's own degradation look like a\n * change in the backdrop.\n */\n\nexport const MIN_LEVEL_EXTENT = 8;\nexport const MAX_CHAIN_LEVELS = 12;\n/** Shorter-side extent the analysis level aims for. */\nexport const ANALYSIS_TARGET_EXTENT = 96;\n\nexport interface PyramidPlan {\n /** Level 0 size in texture px. */\n readonly width: number;\n readonly height: number;\n readonly levelCount: number;\n /** The highest LOD the optics pass may sample: `levelCount - 1`. */\n readonly maxLod: number;\n /** Which level the analysis reduction reads. */\n readonly analysisLevel: number;\n /** Per-level sizes, index 0 = level 0. */\n readonly levels: readonly { readonly width: number; readonly height: number }[];\n}\n\nexport interface ResolutionPolicyView {\n readonly scale: number;\n readonly maxDimension: number;\n}\n\nexport function planPyramid(\n sourceWidth: number,\n sourceHeight: number,\n policy: ResolutionPolicyView,\n): PyramidPlan {\n const scale = Math.max(policy.scale, 1e-3);\n let width = Math.max(1, Math.round(sourceWidth * scale));\n let height = Math.max(1, Math.round(sourceHeight * scale));\n\n const cap = Math.max(MIN_LEVEL_EXTENT, Math.floor(policy.maxDimension));\n const longest = Math.max(width, height);\n if (longest > cap) {\n const shrink = cap / longest;\n width = Math.max(1, Math.round(width * shrink));\n height = Math.max(1, Math.round(height * shrink));\n }\n\n const levels: { width: number; height: number }[] = [{ width, height }];\n while (levels.length < MAX_CHAIN_LEVELS) {\n const previous = levels[levels.length - 1] as { width: number; height: number };\n const next = {\n width: Math.max(1, previous.width >> 1),\n height: Math.max(1, previous.height >> 1),\n };\n if (Math.min(next.width, next.height) < MIN_LEVEL_EXTENT) break;\n if (next.width === previous.width && next.height === previous.height) break;\n levels.push(next);\n }\n\n // Nearest level to the analysis target on the shorter side, in log space so\n // \"nearest\" means nearest by octave rather than by pixel count.\n let analysisLevel = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n for (let i = 0; i < levels.length; i += 1) {\n const level = levels[i] as { width: number; height: number };\n const shorter = Math.min(level.width, level.height);\n const distance = Math.abs(Math.log2(shorter / ANALYSIS_TARGET_EXTENT));\n if (distance < bestDistance) {\n bestDistance = distance;\n analysisLevel = i;\n }\n }\n\n return {\n width,\n height,\n levelCount: levels.length,\n maxLod: levels.length - 1,\n analysisLevel,\n levels,\n };\n}\n\n/**\n * The chain LOD whose blur is nearest σ, and the residual σ the separable pass\n * still has to apply on top of it.\n *\n * The 13-tap downsample's effective σ roughly doubles per level and is about 1.2\n * source texels at level 1; the constant is advisory (calibration-delegated like\n * every other optical number here) and exists so the body blur lands on the\n * material's σ rather than on the nearest power of two.\n */\nexport const CHAIN_SIGMA_AT_LEVEL_1 = 1.2;\n\n/**\n * The **continuous** chain level whose blur is σ level-0 texels — the same\n * doubling `bodyBlurPlan` steps through, inverted and left continuous because its\n * one consumer samples the chain trilinearly rather than picking a level.\n *\n * The size law's scattering facet needs it (W2). The body texture is one blur for\n * a whole backdrop source — built at most once per source per frame, so it cannot\n * be per-surface — while the chain beside it carries every octave at once. So the\n * optics pass reaches a wider kernel per surface by sampling the chain, and this\n * is the origin it measures its extra octaves from. Below level 1's own σ there\n * is no coarser level to name, so the answer ramps linearly to 0 at σ = 0 rather\n * than diverging the way a bare logarithm would.\n */\nexport function chainLodForSigma(sigmaTexels: number): number {\n if (!(sigmaTexels > 0)) return 0;\n if (sigmaTexels <= CHAIN_SIGMA_AT_LEVEL_1) return sigmaTexels / CHAIN_SIGMA_AT_LEVEL_1;\n return 1 + Math.log2(sigmaTexels / CHAIN_SIGMA_AT_LEVEL_1);\n}\n\nexport function bodyBlurPlan(\n sigmaPx: number,\n plan: PyramidPlan,\n): { readonly level: number; readonly residualSigmaTexels: number } {\n if (sigmaPx <= 0) return { level: 0, residualSigmaTexels: 0 };\n\n // Level n's sigma in level-0 texels.\n const sigmaAt = (level: number): number =>\n level === 0 ? 0 : CHAIN_SIGMA_AT_LEVEL_1 * Math.pow(2, level - 1);\n\n let level = 0;\n for (let i = 1; i < plan.levelCount; i += 1) {\n if (sigmaAt(i) > sigmaPx) break;\n level = i;\n }\n\n // The residual is applied at the chosen level's own resolution, so convert.\n const covered = sigmaAt(level);\n const residualLevel0 = Math.sqrt(Math.max(sigmaPx * sigmaPx - covered * covered, 0));\n return { level, residualSigmaTexels: residualLevel0 / Math.pow(2, level) };\n}\n\n/**\n * Level n's own width as a Gaussian σ in level-0 texels — **measured**, not the\n * advisory `CHAIN_SIGMA_AT_LEVEL_1`.\n *\n * `CHAIN_SIGMA_AT_LEVEL_1` is 1.2 and says so about itself, and the body blur can\n * afford that because its residual pass absorbs whatever the constant misses. The\n * heavy tap cannot: its whole purpose is that the σ it is given comes back out of\n * reader A, so the width it subtracts in quadrature has to be the width the chain\n * really draws. `results/2026-09-10-w26-heavy-width/g0/chain-kernel.txt` simulates\n * `WGSL_DOWNSAMPLE_PASS` exactly on a level-0 delta and reads a second-moment σ of\n * 1.570 / 3.340 / 6.799 / 13.660 / 27.351 texels at levels 1…5 — the advisory\n * constant under-states level 1 by 24 % — with a kurtosis of −0.23 at every level\n * from 2 on. The shape is therefore fixed and platykurtic: neither a Gaussian\n * (0) nor a box (−1.2), and 12 % of peak away from the best-fitting Gaussian.\n * The table below is that reading divided by the shape's own constant ratio of\n * second-moment σ to half-maximum σ (1.018), because half maximum is the\n * statistic W25 G0's reader A reduces a two-component kernel by and the plan and\n * the reader have to speak one width.\n */\nexport const CHAIN_LEVEL_SIGMA = [0, 1.542, 3.281, 6.679, 13.418, 26.867] as const;\n\n/**\n * Level n's own width as a Gaussian σ in level-0 texels, extended past the\n * measured table by the doubling the table itself settles into (the level 3 → 4\n * and 4 → 5 ratios read 2.009 and 2.002).\n */\nexport function chainLevelSigma(level: number): number {\n if (level <= 0) return 0;\n if (level < CHAIN_LEVEL_SIGMA.length) return CHAIN_LEVEL_SIGMA[level] as number;\n const last = CHAIN_LEVEL_SIGMA[CHAIN_LEVEL_SIGMA.length - 1] as number;\n return last * Math.pow(2, level - (CHAIN_LEVEL_SIGMA.length - 1));\n}\n\n/**\n * The plan for the **heavy** blur of σ level-0 texels (W26; `sizeHeavyTapSigma`):\n * the chain level to blur from and the residual σ in that level's own texels.\n *\n * The level is the deepest whose own blur is at or below the target, so the\n * residual never has to undo width the chain has already applied, and it is\n * clamped to what the chain actually has. Unlike `scatterLod`, that clamp is not\n * a ceiling on the RESULT: the residual Gaussian carries whatever octave the\n * chain is too short to supply, which is the whole reason this mechanism exists\n * (`MaterialProfile.sizeHeavyTapSigma`, and the measured cause in claims\n * §5.116 §2).\n *\n * This is `bodyBlurPlan`'s rule with one difference, and the difference is the\n * measured chain kernel: the body's residual pass absorbs whatever\n * `CHAIN_SIGMA_AT_LEVEL_1` misses, while the heavy blur's whole purpose is that\n * the σ it is given comes back out of reader A, so it subtracts `CHAIN_LEVEL_SIGMA`\n * — the width the chain really draws — in quadrature instead.\n */\nexport function heavyTapPlan(\n sigmaTexels: number,\n plan: PyramidPlan,\n): { readonly level: number; readonly residualSigmaTexels: number } {\n let level = 0;\n if (sigmaTexels > 0) {\n for (let i = 1; i < plan.levelCount; i += 1) {\n if (chainLevelSigma(i) > sigmaTexels) break;\n level = i;\n }\n }\n const scale = Math.pow(2, level);\n const covered = chainLevelSigma(level);\n const residual = Math.sqrt(Math.max(sigmaTexels * sigmaTexels - covered * covered, 0)) / scale;\n return { level, residualSigmaTexels: residual };\n}\n","/**\n * The §Core model invariant, as a testable object.\n *\n * > blur/analysis pyramids belong to `BackdropSource`, rebuilt **at most once per\n * > dirty source per frame** — never per group.\n *\n * core enforces one half of that: `consumeDirtyBackdropSources(frameId)` hands out\n * one pass over the dirty set per frame id, so a second caller in the same frame\n * gets nothing. What core cannot see is the renderer's side — a renderer that also\n * rebuilt lazily on first draw, or that rebuilt once per group from a single\n * request, would satisfy core's guard and still violate the invariant.\n *\n * So the ledger lives here, apart from the GPU work it guards, for one reason: it\n * makes the invariant assertable against core's real scheduler with no adapter and\n * no device. `pyramid.ts` claims through it before it encodes a single pass, and\n * `test/dirty-epoch.test.ts` drives core's own scene and scheduler over this same\n * object. An invariant tested only through a GPU is an invariant tested only where\n * a GPU exists.\n */\n\nexport interface RebuildLedger {\n /**\n * Begin a frame. Clears the per-frame tally — unless `frameId` is the frame\n * already being recorded, which is not a new frame and must not reopen the\n * tally. The renderer draws one plane per call with the same `FrameInfo`, so\n * that case is the ordinary one rather than the exception.\n */\n beginFrame(frameId: number): void;\n readonly frameId: number | undefined;\n /**\n * Claim the one rebuild this source is allowed this frame. `false` means it has\n * already had it — the caller must not encode a second one.\n */\n claim(sourceId: string): boolean;\n /** Record that a claim did no work because the source was clean. */\n recordClean(): void;\n /** Rebuilds recorded for `sourceId` in the frame being recorded. */\n countInFrame(sourceId: string): number;\n readonly rebuilds: number;\n readonly refusedDuplicates: number;\n readonly skippedClean: number;\n /**\n * Highest per-source rebuild count seen in any single frame. The invariant is\n * exactly the statement that this never exceeds 1.\n */\n readonly peakPerSourcePerFrame: number;\n}\n\nexport function createRebuildLedger(): RebuildLedger {\n const perFrame = new Map<string, number>();\n let frameId: number | undefined;\n let rebuilds = 0;\n let refused = 0;\n let clean = 0;\n let peak = 0;\n\n return {\n beginFrame(next) {\n // Repeating a frame id is not a new frame, and clearing the tally for one\n // would quietly hand every source a second rebuild. The renderer calls\n // `drawFrame` once per PLANE with the same `FrameInfo`, so this is the\n // ordinary case rather than a defensive one: without the guard the\n // \"at most once per dirty source per frame\" invariant is unguarded across\n // planes, and `countInFrame` reports 0 for a frame that rebuilt.\n // `FrameInfo.id` is contractually monotonic (core/src/frame.ts), so\n // equality is the whole test.\n if (frameId === next) return;\n frameId = next;\n perFrame.clear();\n },\n\n get frameId() {\n return frameId;\n },\n\n claim(sourceId) {\n const already = perFrame.get(sourceId) ?? 0;\n if (already > 0) {\n refused += 1;\n return false;\n }\n const count = already + 1;\n perFrame.set(sourceId, count);\n peak = Math.max(peak, count);\n rebuilds += 1;\n return true;\n },\n\n recordClean() {\n clean += 1;\n },\n\n countInFrame(sourceId) {\n return perFrame.get(sourceId) ?? 0;\n },\n\n get rebuilds() {\n return rebuilds;\n },\n\n get refusedDuplicates() {\n return refused;\n },\n\n get skippedClean() {\n return clean;\n },\n\n get peakPerSourcePerFrame() {\n return peak;\n },\n };\n}\n","/**\n * The blur/analysis pyramid, one per `BackdropSource`, and the ledger that proves\n * the §Core model invariant.\n *\n * > **Invariant:** blur/analysis pyramids belong to `BackdropSource`, rebuilt **at\n * > most once per dirty source per frame** — never per group. Static backdrops\n * > rebuild nothing.\n *\n * core enforces half of that already: `consumeDirtyBackdropSources(frameId)`\n * hands out one pass over the dirty set per frame id, so however many\n * participants ask, the second call returns nothing. What core *cannot* see is\n * this side of the wire — a renderer that also rebuilt lazily on first draw, or\n * that rebuilt once per group from one request, would satisfy core's guard and\n * violate the invariant. So the ledger here counts rebuilds per source per frame\n * on the renderer's own books, refuses a second one, and exposes the counters.\n * That is what makes the invariant *instrumented* rather than asserted.\n *\n * ## Pass structure per rebuild\n *\n * ```\n * import provider frame -> chain mip 0 (premultiplied linear, X5)\n * downsample mip n-1 -> chain mip n (13-tap, one pass per level)\n * blur x2 chain[bodyLvl] -> body (separable, residual sigma)\n * blur x2 chain[heavyLvl] -> heavy (separable, residual sigma; W26)\n * analysis chain[anaLvl] -> stats buffer (compute, one workgroup)\n * ```\n *\n * Reading mip n-1 while rendering into mip n is legal because they are distinct\n * subresources, and every view here is created with an explicit\n * `baseMipLevel`/`mipLevelCount: 1` so that is true by construction rather than by\n * the driver's interpretation of a full-texture view.\n */\n\nimport { ANALYSIS_STATS_FLOATS, ANALYSIS_GRID, ANALYSIS_WORKGROUP } from \"./wgsl/analysis\";\nimport {\n alphaNormalisationMode,\n importColorMatrix,\n WORKING_TEXTURE_FORMAT,\n} from \"./color\";\nimport { statsFromBuffer, type BackdropStats } from \"./analysis\";\nimport type { BackdropFrame, BackdropProvider } from \"./backdrop\";\nimport { texelsPerCssPx, type BackdropPlacement } from \"./backdrop-fit\";\nimport { type GpuContext, createUniformSlot, type UniformSlot } from \"./gpu-context\";\nimport { pipelineKey } from \"./pipeline-cache\";\nimport {\n bodyBlurPlan,\n heavyTapPlan,\n planPyramid,\n type PyramidPlan,\n type ResolutionPolicyView,\n} from \"./pyramid-plan\";\nimport { createRebuildLedger, type RebuildLedger } from \"./rebuild-ledger\";\nimport { poolKey } from \"./texture-pool\";\nimport { PASS_LABEL, type PassTimeline } from \"./timing\";\nimport { analysisModule, chainModule, importModule } from \"./wgsl\";\n\n/** Computed on first use, not at module scope — see the note in `passes.ts`. */\nconst chainUsage = (): GPUTextureUsageFlags =>\n GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING;\n\nexport interface PyramidResources {\n readonly sourceId: string;\n readonly plan: PyramidPlan;\n readonly chain: GPUTexture;\n readonly body: GPUTexture;\n /**\n * The **heavy** blur (W26; `MaterialProfile.sizeHeavyTapSigma`) — one more\n * texture beside the body, built by the same two separable passes from\n * whichever chain level `heavyTapPlan` names, and `undefined` where the\n * profile asked for no width.\n *\n * It is here rather than in the optics pass because the optics pass is a\n * fragment shader over the glass's own area: W26 G0 measured a 9 × 9 in-shader\n * grid at +1.1 ms on the mobile bench row against 0.070 ms for the two\n * separable passes the chain already runs (W26 Decision Log 2 (b)). The price\n * of building it here is that the width is **one per source** rather than one\n * per pixel — every group sampling this source gets the same heavy width,\n * because the texture is built before any group is drawn. The reference's heavy\n * width does not grade with the span at 1x (claims §5.113 §4), which is what\n * says the material can afford that.\n */\n readonly heavy: GPUTexture | undefined;\n /**\n * The **second** heavy blur (W30 G2; `MaterialProfile.sizeHeavySecondSigma`\n * gated on `sizeHeavySecondShare`) — the same construction one width along,\n * and `undefined` wherever the material leaves the share at 0, which is\n * everywhere on the landed material.\n *\n * It is a second texture and a second separable pair rather than a second tap\n * in the optics pass for the reason the first one is: the price of a width at\n * the fragment is +1.1 ms on the mobile bench row against 0.070 ms here (W26\n * Decision Log 2 (b)). The price of having it at all is therefore paid by the\n * material that names it and by nothing else.\n */\n readonly heavy2: GPUTexture | undefined;\n readonly stats: GPUBuffer;\n /** Source size epoch this allocation was made for. */\n readonly sizeEpoch: number;\n /** The dirty epoch the last successful rebuild satisfied. */\n readonly builtEpoch: number;\n /**\n * The body blur's σ in **level-0 texels** — the CSS-px σ the material asked\n * for, through the same cover fit and plan downscale the build applied.\n *\n * Published because the conversion is only knowable here: it needs the frame's\n * real extent, which is exactly why `bodySigmaCss` arrives in CSS px. The size\n * law's scattering facet consumes it (W2) — the optics pass widens the body blur\n * per surface by sampling the chain, and it cannot find the level to measure\n * from without knowing where the body already sits.\n */\n readonly bodySigmaTexels: number;\n /**\n * Source texels per CSS px the build converted `bodySigmaCss` with — the placed\n * density where the source had a placement, the cover ratio where it did not\n * (`backdrop-fit.ts`) — and the source extent it was computed from. Recorded so\n * a later request can tell whether the body it would produce differs from the\n * one on the chain: a static image never re-dirties, so a placement whose SIZE\n * moved is the only signal that the σ in texels has gone stale.\n */\n readonly texelsPerCss: number;\n readonly sourceWidth: number;\n readonly sourceHeight: number;\n /**\n * The CSS-px σ the build converted with (W13 G1, review finding). The density\n * alone does not determine the body: since the widths became device-pixel\n * quantities (W12 G3, claims §5.56) the material's σ in CSS px is\n * `blurSigma / dpr`, so a window dragged from a 1x display to a 2x one asks\n * for a different body from the same source at the same density. A static\n * image never re-dirties, so this recorded σ is the only signal that the\n * chain's body and `bodyChainLod` belong to the previous scale.\n */\n readonly bodySigmaCss: number;\n /**\n * The heavy blur's σ in **CSS px** the build converted with, for `sameBody`'s\n * reason and by the same rule: the heavy width is a device-px quantity\n * (claims §5.113 §2), so `sizeHeavyTapSigma / dpr` is what reaches the source's\n * texels, and a window dragged between displays asks for a different heavy\n * texture from the same clean source.\n */\n readonly heavySigmaCss: number;\n /**\n * The SECOND heavy blur's σ in **CSS px** the build converted with (W30 G2),\n * on `heavySigmaCss`'s own rule and for the same staleness reason.\n */\n readonly heavy2SigmaCss: number;\n}\n\nexport interface PyramidInstrumentation {\n /** Successful rebuilds since the store was created. */\n readonly rebuilds: number;\n /** Rebuild attempts refused because the source had already rebuilt this frame. */\n readonly refusedDuplicates: number;\n /** Rebuilds skipped because the source was clean. */\n readonly skippedClean: number;\n readonly reallocations: number;\n /** Rebuild count for one source within the frame currently being recorded. */\n rebuildsInFrame(sourceId: string): number;\n /** Highest per-source rebuild count seen in any single frame. Must stay <= 1. */\n readonly peakRebuildsPerSourcePerFrame: number;\n}\n\nexport interface PyramidBuildRequest {\n readonly sourceId: string;\n readonly epoch: number;\n readonly resolution: ResolutionPolicyView;\n /**\n * The material's body blur, in **CSS px**, with the viewport it is measured\n * against.\n *\n * Not in source texels, because the conversion between the two is a property of\n * the frame that has not been acquired yet: a 3840-wide video behind a 390 px\n * viewport packs ten source texels into every CSS px, so a σ of 8 texels would\n * be a σ of 0.8 CSS px on screen — a tenth of the frost the material asked for.\n * The build resolves it once the frame's real extent is known.\n */\n readonly bodySigmaCss: number;\n /**\n * The heavy blur's σ in **CSS px** (W26), 0 where the profile declines the\n * width — at which point nothing is allocated and nothing is drawn, so a\n * material that names no heavy width pays for none of this.\n */\n readonly heavySigmaCss: number;\n /**\n * The SECOND heavy blur's σ in **CSS px** (W30 G2), 0 where the material\n * leaves `sizeHeavySecondShare` at 0 — at which point nothing is allocated\n * and nothing is drawn, exactly as for the first one. The share is the gate\n * and `heavySecondTapSigmaAtScale` applies it, so this arrives already 0\n * rather than being re-decided here.\n */\n readonly heavy2SigmaCss: number;\n readonly viewportCss: readonly [number, number];\n /**\n * Where the source sits on the plane, in CSS px relative to the viewport, if\n * the host measured one. Absent, the source is cover-fit to the viewport.\n */\n readonly placement?: BackdropPlacement;\n}\n\nexport type PyramidBuildOutcome =\n | { readonly status: \"built\"; readonly resources: PyramidResources }\n | { readonly status: \"duplicate\" }\n | { readonly status: \"clean\"; readonly resources: PyramidResources }\n | { readonly status: \"unavailable\"; readonly reason: string };\n\nexport interface PyramidStore {\n readonly instrumentation: PyramidInstrumentation;\n /** The invariant's ledger, exposed so a test can drive it without a device. */\n readonly ledger: RebuildLedger;\n /** Start recording a new frame. Clears the per-frame rebuild tally. */\n beginFrame(frameId: number): void;\n /** Attach a timing collector for this frame, or `undefined` to time nothing. */\n setTimeline(timeline: PassTimeline | undefined): void;\n build(\n request: PyramidBuildRequest,\n provider: BackdropProvider,\n encoder: GPUCommandEncoder,\n ): PyramidBuildOutcome;\n /**\n * Release every provider acquired this frame.\n *\n * Split from `afterSubmit` because the two halves have opposite failure rules.\n * A release is owed whether or not the frame reached the queue — an acquired\n * `VideoFrame` held across a frame stalls decoding — so this belongs in a\n * `finally` around the whole encode/submit. Call it after `queue.submit` on the\n * success path: an imported external texture must outlive the submission that\n * samples it.\n */\n releaseAcquired(): void;\n /**\n * Start the analysis readback maps. **Success path only**: `mapAsync` makes a\n * buffer unavailable to submits from the moment it is called, so starting a map\n * for a copy that was never submitted is its own bug — see `requestStats`.\n */\n afterSubmit(): void;\n /**\n * The source's pyramid, or `undefined` when it has none the pool still owns.\n * A caller may bind what this returns without checking anything further.\n */\n resources(sourceId: string): PyramidResources | undefined;\n /** Copy a source's stats into a staging buffer and map it. Cadence-gated by the caller. */\n requestStats(sourceId: string, encoder: GPUCommandEncoder): boolean;\n /** Resolve any completed stats readbacks. Returns what arrived. */\n collectStats(): Promise<ReadonlyMap<string, BackdropStats>>;\n forget(sourceId: string): void;\n destroy(): void;\n}\n\ninterface StatsReadback {\n readonly staging: GPUBuffer;\n inFlight: boolean;\n}\n\nconst densityOf = (\n source: { readonly width: number; readonly height: number },\n request: PyramidBuildRequest,\n): number =>\n texelsPerCssPx(\n source.width,\n source.height,\n request.placement,\n request.viewportCss[0],\n request.viewportCss[1],\n );\n\n/** Relative-tolerance equality, the comparison both halves of the body key take. */\nconst same = (next: number, existing: number): boolean =>\n Math.abs(next - existing) <= 1e-6 * Math.max(1, Math.abs(existing));\n\n/**\n * Whether a request would produce the body the chain already carries — the same\n * σ in CSS px converted at the same density. Both halves are needed: the density\n * moves when a placement is resized or withdrawn, and the σ moves when the\n * device pixel ratio does, because the body's widths are device-pixel quantities\n * on this tier (W12 G3, claims §5.56; W15 G1, claims §5.69 §1) and\n * `bodySigmaCss` is `blurSigma / dpr`.\n *\n * The frame is not acquired at the clean check, so the source extent is the one\n * recorded at build — the same extent the recorded density came from, so the\n * comparison is exact for a source whose size held, and a source whose size\n * moved re-dirties through its own epoch anyway.\n */\n/**\n * Whether two heavy σ would produce the same heavy blur — the ON/OFF state\n * EXACTLY, and only then the tolerance.\n *\n * `same` is a relative tolerance, and a relative tolerance around zero is an\n * absolute one of 1e-6: it calls σ 1e-7 and σ 0 equal. Those two are not equal\n * here, because they differ in KIND rather than in width. At 0 there is no heavy\n * texture and the optics pass takes the chain tap; at 1e-7 there is one, and\n * `heavyTapPlan` resolves that σ to level 0 with no residual — an unsampled copy\n * of the backdrop, which is the narrowest thing the mechanism can draw and the\n * furthest from what σ 0 means. So a material returning to 0 from a tiny positive\n * width has to REBUILD, and the tolerance applies only between two widths that\n * are both on.\n *\n * Exported because `renderer.ts` asks the same question of a clean source before\n * it asks the store anything, and the two must not be able to disagree.\n */\nexport const sameHeavySigma = (next: number, existing: number): boolean =>\n next > 0 === existing > 0 && same(next, existing);\n\nconst sameBody = (existing: PyramidResources, request: PyramidBuildRequest): boolean =>\n same(densityOf({ width: existing.sourceWidth, height: existing.sourceHeight }, request), existing.texelsPerCss)\n && same(request.bodySigmaCss, existing.bodySigmaCss)\n // The heavy blur rides the same key: it is built from the same chain at the\n // same density, so a σ that moved makes the texture on the source stale in\n // exactly the way a moved body σ does.\n && sameHeavySigma(request.heavySigmaCss, existing.heavySigmaCss)\n // And the second heavy blur on the identical rule (W30 G2): its ON/OFF state\n // exactly, then the tolerance, because 0 and a tiny positive width differ in\n // kind and not in degree.\n && sameHeavySigma(request.heavy2SigmaCss, existing.heavy2SigmaCss);\n\nexport function createPyramidStore(context: GpuContext): PyramidStore {\n const { device, pool, cache } = context;\n\n const resources = new Map<string, PyramidResources>();\n const uniforms = new Map<string, UniformSlot>();\n const readbacks = new Map<string, StatsReadback>();\n const pendingRelease: BackdropProvider[] = [];\n const pendingStats = new Map<string, Promise<BackdropStats | undefined>>();\n /** Readbacks whose copy is encoded but whose map must wait for the submit. */\n const pendingMaps: string[] = [];\n\n let timeline: PassTimeline | undefined;\n const timedRender = (label: string): { timestampWrites?: GPURenderPassTimestampWrites } => {\n const slot = timeline?.renderSlot(label);\n return slot === undefined ? {} : { timestampWrites: slot };\n };\n const timedCompute = (label: string): { timestampWrites?: GPUComputePassTimestampWrites } => {\n const slot = timeline?.computeSlot(label);\n return slot === undefined ? {} : { timestampWrites: slot };\n };\n\n let frameId = -1;\n let reallocations = 0;\n const ledger: RebuildLedger = createRebuildLedger();\n\n const uniformSlot = (key: string, floats: number): UniformSlot => {\n let slot = uniforms.get(key);\n if (slot === undefined) {\n slot = createUniformSlot(device, floats, `vitrea:uniform:${key}`);\n uniforms.set(key, slot);\n }\n return slot;\n };\n\n const importPipeline = (kind: \"sampled\" | \"external\"): GPURenderPipeline =>\n cache.renderPipeline(pipelineKey.import(kind, WORKING_TEXTURE_FORMAT), () => ({\n label: `vitrea:pipeline:import:${kind}`,\n layout: \"auto\",\n vertex: {\n module: cache.module(`module:import:${kind}`, () => importModule(kind)),\n entryPoint: \"vs_fullscreen\",\n },\n fragment: {\n module: cache.module(`module:import:${kind}`, () => importModule(kind)),\n entryPoint: \"fs_import\",\n targets: [{ format: WORKING_TEXTURE_FORMAT }],\n },\n primitive: { topology: \"triangle-list\" },\n }));\n\n const chainPipeline = (entry: \"fs_downsample\" | \"fs_blur\"): GPURenderPipeline =>\n cache.renderPipeline(pipelineKey.chain(entry, WORKING_TEXTURE_FORMAT), () => ({\n label: `vitrea:pipeline:chain:${entry}`,\n layout: \"auto\",\n vertex: {\n module: cache.module(\"module:chain\", chainModule),\n entryPoint: \"vs_fullscreen\",\n },\n fragment: {\n module: cache.module(\"module:chain\", chainModule),\n entryPoint: entry,\n targets: [{ format: WORKING_TEXTURE_FORMAT }],\n },\n primitive: { topology: \"triangle-list\" },\n }));\n\n const analysisPipeline = (): GPUComputePipeline =>\n cache.computePipeline(pipelineKey.analysis(), () => ({\n label: \"vitrea:pipeline:analysis\",\n layout: \"auto\",\n compute: {\n module: cache.module(\"module:analysis\", analysisModule),\n entryPoint: \"cs_analysis\",\n },\n }));\n\n /**\n * The source's resources, or `undefined` when the handles it recorded are no\n * longer the pool's.\n *\n * The pool owns the lifetime of both textures and can destroy them without this\n * store hearing about it — a size-epoch sweep, a device-loss `clear()`. The\n * recorded handles then name destroyed textures, and binding one is a WebGPU\n * validation error that takes the whole plane's encoder down with it. Two\n * identity compares turn that into \"there is no backdrop this frame\", which the\n * optics pass already has a placeholder for: unrefracted glass for a frame,\n * rather than a dropped one.\n */\n const liveResources = (sourceId: string): PyramidResources | undefined => {\n const target = resources.get(sourceId);\n if (target === undefined) return undefined;\n if (pool.peek(poolKey.backdropChain(sourceId)) !== target.chain) return undefined;\n if (pool.peek(poolKey.backdropBody(sourceId)) !== target.body) return undefined;\n if (target.heavy !== undefined && pool.peek(poolKey.backdropHeavy(sourceId)) !== target.heavy) {\n return undefined;\n }\n if (\n target.heavy2 !== undefined &&\n pool.peek(poolKey.backdropHeavy2(sourceId)) !== target.heavy2\n ) {\n return undefined;\n }\n return target;\n };\n\n const mipView = (texture: GPUTexture, level: number): GPUTextureView =>\n texture.createView({ baseMipLevel: level, mipLevelCount: 1, dimension: \"2d\" });\n\n function allocate(\n sourceId: string,\n plan: PyramidPlan,\n bodyLevel: number,\n sizeEpoch: number,\n builtEpoch: number,\n bodySigmaTexels: number,\n density: { readonly texelsPerCss: number; readonly sourceWidth: number; readonly sourceHeight: number },\n bodySigmaCss: number,\n heavyLevel: number | undefined,\n heavySigmaCss: number,\n heavy2Level: number | undefined,\n heavy2SigmaCss: number,\n ): PyramidResources {\n const existing = resources.get(sourceId);\n const levelSize = (level: number): { width: number; height: number } =>\n plan.levels[level] ?? (plan.levels[0] as { width: number; height: number });\n const bodyWidth = levelSize(bodyLevel).width;\n const bodyHeight = levelSize(bodyLevel).height;\n\n const chain = pool.acquire(poolKey.backdropChain(sourceId), {\n width: plan.width,\n height: plan.height,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n mipLevelCount: plan.levelCount,\n label: `vitrea:pyramid:${sourceId}:chain`,\n });\n const body = pool.acquire(poolKey.backdropBody(sourceId), {\n width: bodyWidth,\n height: bodyHeight,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n label: `vitrea:pyramid:${sourceId}:body`,\n });\n\n /*\n * The heavy blur's texture (W26), acquired only where the profile named a\n * width. `undefined` is the landed material's answer, and it is what makes\n * the mechanism cost nothing there: no allocation, no two passes, and the\n * optics pass takes the single `textureSampleLevel` it has always taken.\n */\n let heavy: GPUTexture | undefined;\n if (heavyLevel === undefined) {\n // And RELEASED where it is not, rather than merely dropped from the record.\n // A material that sets the width back to 0 leaves a source whose pool still\n // holds the heavy texture and its scratch — two more full-level allocations\n // that nothing will ever bind and that only `forget` would reclaim, so they\n // would be held until the source is unregistered. The pool tolerates a\n // release of a key it does not hold, so this is also the path a source that\n // never had a heavy blur takes.\n pool.release(poolKey.backdropHeavy(sourceId));\n pool.release(poolKey.backdropHeavyScratch(sourceId));\n } else {\n heavy = pool.acquire(poolKey.backdropHeavy(sourceId), {\n width: levelSize(heavyLevel).width,\n height: levelSize(heavyLevel).height,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n label: `vitrea:pyramid:${sourceId}:heavy`,\n });\n }\n\n /* The second heavy blur (W30 G2), on the identical rule and for the\n * identical reason: acquired only where the material named a share, and\n * RELEASED where it did not, so a material that sets the share back to 0\n * does not strand two full-level allocations nothing will ever bind. */\n let heavy2: GPUTexture | undefined;\n if (heavy2Level === undefined) {\n pool.release(poolKey.backdropHeavy2(sourceId));\n pool.release(poolKey.backdropHeavy2Scratch(sourceId));\n } else {\n heavy2 = pool.acquire(poolKey.backdropHeavy2(sourceId), {\n width: levelSize(heavy2Level).width,\n height: levelSize(heavy2Level).height,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n label: `vitrea:pyramid:${sourceId}:heavy2`,\n });\n }\n\n let stats = existing?.stats;\n if (stats === undefined) {\n stats = device.createBuffer({\n label: `vitrea:pyramid:${sourceId}:stats`,\n size: ANALYSIS_STATS_FLOATS * 4,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\n });\n }\n\n if (\n existing === undefined ||\n existing.chain !== chain ||\n existing.body !== body ||\n existing.heavy !== heavy ||\n existing.heavy2 !== heavy2\n ) {\n reallocations += 1;\n }\n\n const next: PyramidResources = {\n sourceId,\n plan,\n chain,\n body,\n heavy,\n heavy2,\n stats,\n sizeEpoch,\n builtEpoch,\n bodySigmaTexels,\n texelsPerCss: density.texelsPerCss,\n sourceWidth: density.sourceWidth,\n sourceHeight: density.sourceHeight,\n bodySigmaCss,\n heavySigmaCss,\n heavy2SigmaCss,\n };\n resources.set(sourceId, next);\n return next;\n }\n\n function runImport(\n encoder: GPUCommandEncoder,\n sourceId: string,\n frame: BackdropFrame,\n chain: GPUTexture,\n ): void {\n const kind = frame.binding.kind;\n const pipeline = importPipeline(kind);\n const slot = uniformSlot(`import:${sourceId}`, 16);\n const matrix = importColorMatrix(frame.colorSpace);\n\n slot.data[0] = matrix[0] as number;\n slot.data[1] = matrix[1] as number;\n slot.data[2] = matrix[2] as number;\n slot.data[3] = frame.encoded ? 1 : 0;\n slot.data[4] = matrix[3] as number;\n slot.data[5] = matrix[4] as number;\n slot.data[6] = matrix[5] as number;\n slot.data[7] = alphaNormalisationMode(frame.alphaMode);\n slot.data[8] = matrix[6] as number;\n slot.data[9] = matrix[7] as number;\n slot.data[10] = matrix[8] as number;\n slot.data[11] = 0;\n // Stretch fit: level 0 IS the source, resampled to the planned extent, so the\n // uv transform is the identity. A group's own framing of the backdrop happens\n // in the optics pass, where the viewport is known.\n slot.data[12] = 1;\n slot.data[13] = 1;\n slot.data[14] = 0;\n slot.data[15] = 0;\n slot.write();\n\n const entries: GPUBindGroupEntry[] = [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: context.flatSampler },\n {\n binding: 2,\n resource:\n frame.binding.kind === \"external\" ? frame.binding.texture : frame.binding.view,\n },\n ];\n\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:import:${sourceId}`,\n ...timedRender(PASS_LABEL.import),\n colorAttachments: [\n { view: mipView(chain, 0), loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } },\n ],\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, device.createBindGroup({ layout: pipeline.getBindGroupLayout(0), entries }));\n pass.draw(3);\n pass.end();\n }\n\n function runChain(\n encoder: GPUCommandEncoder,\n sourceId: string,\n plan: PyramidPlan,\n chain: GPUTexture,\n ): void {\n const pipeline = chainPipeline(\"fs_downsample\");\n for (let level = 1; level < plan.levelCount; level += 1) {\n const source = plan.levels[level - 1] as { width: number; height: number };\n const slot = uniformSlot(`chain:${sourceId}:${level}`, 8);\n slot.data[0] = 1 / source.width;\n slot.data[1] = 1 / source.height;\n slot.data[2] = 0;\n slot.data[3] = 0;\n slot.data[4] = 0;\n slot.data[5] = 0;\n slot.data[6] = 0;\n slot.data[7] = 0;\n slot.write();\n\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:downsample:${sourceId}:${level}`,\n ...timedRender(PASS_LABEL.chain),\n colorAttachments: [\n { view: mipView(chain, level), loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } },\n ],\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: context.flatSampler },\n { binding: 2, resource: mipView(chain, level - 1) },\n ],\n }),\n );\n pass.draw(3);\n pass.end();\n }\n }\n\n /**\n * The separable blur that takes one chain level up to an exact σ — two passes,\n * horizontal into a scratch of the level's own extent and vertical out of it.\n *\n * Parameterised by `kind` because W26 gave the pyramid a second one: the body\n * (`bodyBlurPlan`) and the heavy blur (`heavyTapPlan`) differ only in which\n * level they start from, which σ they finish at and which texture they land in,\n * so one function draws both and the pool keys, the uniform slots and the pass\n * labels are keyed by the kind rather than duplicated.\n */\n function runSeparableBlur(\n encoder: GPUCommandEncoder,\n sourceId: string,\n kind: \"body\" | \"heavy\" | \"heavy2\",\n plan: PyramidPlan,\n chain: GPUTexture,\n target: GPUTexture,\n level: number,\n residualSigmaTexels: number,\n ): void {\n const pipeline = chainPipeline(\"fs_blur\");\n const size = plan.levels[level] ?? (plan.levels[0] as { width: number; height: number });\n const scratchKey =\n kind === \"body\"\n ? poolKey.backdropBodyScratch(sourceId)\n : kind === \"heavy\"\n ? poolKey.backdropHeavyScratch(sourceId)\n : poolKey.backdropHeavy2Scratch(sourceId);\n const scratch = pool.acquire(scratchKey, {\n width: size.width,\n height: size.height,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n label: `vitrea:pyramid:${sourceId}:${kind}-scratch`,\n });\n\n const stages: { target: GPUTexture; source: GPUTextureView; dir: [number, number]; tag: string }[] = [\n { target: scratch, source: mipView(chain, level), dir: [1, 0], tag: \"h\" },\n { target, source: scratch.createView(), dir: [0, 1], tag: \"v\" },\n ];\n\n for (const stage of stages) {\n const slot = uniformSlot(`${kind}:${sourceId}:${stage.tag}`, 8);\n slot.data[0] = 1 / size.width;\n slot.data[1] = 1 / size.height;\n slot.data[2] = 0;\n slot.data[3] = 0;\n slot.data[4] = residualSigmaTexels;\n slot.data[5] = stage.dir[0];\n slot.data[6] = stage.dir[1];\n slot.data[7] = 0;\n slot.write();\n\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:${kind}-blur-${stage.tag}:${sourceId}`,\n ...timedRender(PASS_LABEL.bodyBlur),\n colorAttachments: [\n { view: stage.target.createView(), loadOp: \"clear\", storeOp: \"store\", clearValue: { r: 0, g: 0, b: 0, a: 0 } },\n ],\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: context.flatSampler },\n { binding: 2, resource: stage.source },\n ],\n }),\n );\n pass.draw(3);\n pass.end();\n }\n }\n\n function runAnalysis(\n encoder: GPUCommandEncoder,\n sourceId: string,\n plan: PyramidPlan,\n chain: GPUTexture,\n stats: GPUBuffer,\n ): void {\n const pipeline = analysisPipeline();\n const level = plan.levels[plan.analysisLevel] ?? (plan.levels[0] as { width: number; height: number });\n const slot = uniformSlot(`analysis:${sourceId}`, 8);\n slot.data[0] = ANALYSIS_GRID;\n slot.data[1] = ANALYSIS_GRID;\n slot.data[2] = plan.analysisLevel;\n slot.data[3] = 1 / (ANALYSIS_GRID - 1);\n slot.data[4] = 1 / level.width;\n slot.data[5] = 1 / level.height;\n slot.data[6] = 0;\n slot.data[7] = 0;\n slot.write();\n\n const pass = encoder.beginComputePass({\n label: `vitrea:pass:analysis:${sourceId}`,\n ...timedCompute(PASS_LABEL.analysis),\n });\n pass.setPipeline(pipeline);\n pass.setBindGroup(\n 0,\n device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0),\n entries: [\n { binding: 0, resource: { buffer: slot.buffer } },\n { binding: 1, resource: context.flatSampler },\n { binding: 2, resource: chain.createView() },\n { binding: 3, resource: { buffer: stats } },\n ],\n }),\n );\n // One workgroup: the reduction reads a fixed grid, so its cost does not\n // follow the backdrop's resolution. See wgsl/analysis.ts.\n pass.dispatchWorkgroups(1);\n pass.end();\n }\n\n return {\n instrumentation: {\n get rebuilds() {\n return ledger.rebuilds;\n },\n get refusedDuplicates() {\n return ledger.refusedDuplicates;\n },\n get skippedClean() {\n return ledger.skippedClean;\n },\n get reallocations() {\n return reallocations;\n },\n rebuildsInFrame(sourceId) {\n return ledger.countInFrame(sourceId);\n },\n get peakRebuildsPerSourcePerFrame() {\n return ledger.peakPerSourcePerFrame;\n },\n },\n\n /** The ledger the invariant is asserted against. See `rebuild-ledger.ts`. */\n ledger,\n\n beginFrame(next) {\n frameId = next;\n ledger.beginFrame(next);\n },\n\n setTimeline(next) {\n timeline = next;\n },\n\n build(request, provider, encoder) {\n // The LIVE resources, not merely the recorded ones: a clean-skip against a\n // handle the pool has already destroyed would leave the source with no\n // usable pyramid and no way back — the skip is exactly what stops the\n // reallocation that would heal it.\n const existing = liveResources(request.sourceId);\n if (\n existing !== undefined &&\n existing.builtEpoch >= request.epoch &&\n !provider.isDirty() &&\n sameBody(existing, request)\n ) {\n ledger.recordClean();\n return { status: \"clean\", resources: existing };\n }\n\n // Claimed BEFORE any pass is encoded: the ledger is the guard, not a\n // counter kept alongside one.\n if (!ledger.claim(request.sourceId)) {\n return { status: \"duplicate\" };\n }\n\n let frame: BackdropFrame;\n try {\n frame = provider.acquire({ id: frameId, timeMs: 0 });\n } catch (error) {\n return {\n status: \"unavailable\",\n reason: error instanceof Error ? error.message : String(error),\n };\n }\n pendingRelease.push(provider);\n\n const plan = planPyramid(frame.width, frame.height, request.resolution);\n // Source texels per CSS px — the placed density where the host measured a\n // placement, the cover ratio the optics pass samples with where it did not\n // (`backdrop-fit.ts`) — times the downscale the plan actually applied\n // (which includes `maxDimension`, not just the policy's `scale`).\n const texelsPerCss = densityOf(frame, request);\n const planScale = frame.width > 0 ? plan.width / frame.width : 1;\n const bodySigmaTexels = request.bodySigmaCss * texelsPerCss * planScale;\n const bodyPlan = bodyBlurPlan(bodySigmaTexels, plan);\n // The heavy blur (W26), through the identical conversion — the same density\n // and the same plan downscale, because it is the same chain read one or two\n // levels deeper. At σ 0 there is no plan, no texture and no pass.\n const heavyPlan =\n request.heavySigmaCss > 0\n ? heavyTapPlan(request.heavySigmaCss * texelsPerCss * planScale, plan)\n : undefined;\n // The second heavy blur (W30 G2), through the same conversion and the same\n // plan. At σ 0 — the landed material, where the share that gates it is 0 —\n // there is no plan, no texture and no pass.\n const heavy2Plan =\n request.heavy2SigmaCss > 0\n ? heavyTapPlan(request.heavy2SigmaCss * texelsPerCss * planScale, plan)\n : undefined;\n const target = allocate(\n request.sourceId,\n plan,\n bodyPlan.level,\n frame.sizeEpoch,\n request.epoch,\n bodySigmaTexels,\n { texelsPerCss, sourceWidth: frame.width, sourceHeight: frame.height },\n request.bodySigmaCss,\n heavyPlan?.level,\n request.heavySigmaCss,\n heavy2Plan?.level,\n request.heavy2SigmaCss,\n );\n\n runImport(encoder, request.sourceId, frame, target.chain);\n runChain(encoder, request.sourceId, plan, target.chain);\n runSeparableBlur(\n encoder,\n request.sourceId,\n \"body\",\n plan,\n target.chain,\n target.body,\n bodyPlan.level,\n bodyPlan.residualSigmaTexels,\n );\n if (heavyPlan !== undefined && target.heavy !== undefined) {\n runSeparableBlur(\n encoder,\n request.sourceId,\n \"heavy\",\n plan,\n target.chain,\n target.heavy,\n heavyPlan.level,\n heavyPlan.residualSigmaTexels,\n );\n }\n if (heavy2Plan !== undefined && target.heavy2 !== undefined) {\n runSeparableBlur(\n encoder,\n request.sourceId,\n \"heavy2\",\n plan,\n target.chain,\n target.heavy2,\n heavy2Plan.level,\n heavy2Plan.residualSigmaTexels,\n );\n }\n runAnalysis(encoder, request.sourceId, plan, target.chain, target.stats);\n\n provider.markImported();\n return { status: \"built\", resources: target };\n },\n\n releaseAcquired() {\n // In acquisition order. A provider that throws on release must not strand\n // the others — a leaked VideoFrame stalls decoding.\n while (pendingRelease.length > 0) {\n const provider = pendingRelease.shift();\n try {\n provider?.release();\n } catch {\n // Deliberately swallowed; see above.\n }\n }\n },\n\n afterSubmit() {\n // The readback maps, now that the copies they read are in the queue.\n while (pendingMaps.length > 0) {\n const sourceId = pendingMaps.shift();\n if (sourceId === undefined) continue;\n const slot = readbacks.get(sourceId);\n if (slot === undefined) continue;\n const staging = slot.staging;\n pendingStats.set(\n sourceId,\n (async () => {\n try {\n await staging.mapAsync(GPUMapMode.READ);\n const values = new Float32Array(staging.getMappedRange().slice(0));\n staging.unmap();\n return statsFromBuffer(values);\n } catch {\n return undefined;\n } finally {\n slot.inFlight = false;\n }\n })(),\n );\n }\n },\n\n resources(sourceId) {\n return liveResources(sourceId);\n },\n\n requestStats(sourceId, encoder) {\n const target = liveResources(sourceId);\n if (target === undefined) return false;\n\n let readback = readbacks.get(sourceId);\n if (readback === undefined) {\n readback = {\n staging: device.createBuffer({\n label: `vitrea:pyramid:${sourceId}:stats-staging`,\n size: ANALYSIS_STATS_FLOATS * 4,\n usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,\n }),\n inFlight: false,\n };\n readbacks.set(sourceId, readback);\n }\n // Single slot, no queue: if the previous map has not resolved, this frame's\n // readback is simply skipped. Queueing them is how a renderer under pressure\n // accumulates stale buffers, and two answers from the same frame are no more\n // useful than one.\n if (readback.inFlight) return false;\n\n encoder.copyBufferToBuffer(target.stats, 0, readback.staging, 0, ANALYSIS_STATS_FLOATS * 4);\n readback.inFlight = true;\n // The map is NOT started here. `mapAsync` makes a buffer unavailable to\n // submits from the moment it is called, and the copy just encoded has not\n // been submitted yet — starting the map now makes this frame's own submit\n // invalid with \"used in submit while mapped\". So the map is deferred to\n // `afterSubmit`.\n pendingMaps.push(sourceId);\n return true;\n },\n\n async collectStats() {\n const out = new Map<string, BackdropStats>();\n const entries = [...pendingStats];\n pendingStats.clear();\n for (const [sourceId, promise] of entries) {\n const stats = await promise;\n if (stats !== undefined) out.set(sourceId, stats);\n }\n return out;\n },\n\n forget(sourceId) {\n pool.release(poolKey.backdropChain(sourceId));\n pool.release(poolKey.backdropBody(sourceId));\n pool.release(poolKey.backdropBodyScratch(sourceId));\n pool.release(poolKey.backdropHeavy(sourceId));\n pool.release(poolKey.backdropHeavyScratch(sourceId));\n resources.get(sourceId)?.stats.destroy();\n resources.delete(sourceId);\n readbacks.get(sourceId)?.staging.destroy();\n readbacks.delete(sourceId);\n pendingStats.delete(sourceId);\n const queued = pendingMaps.indexOf(sourceId);\n if (queued >= 0) pendingMaps.splice(queued, 1);\n },\n\n destroy() {\n for (const sourceId of [...resources.keys()]) this.forget(sourceId);\n for (const slot of uniforms.values()) slot.buffer.destroy();\n uniforms.clear();\n pendingRelease.length = 0;\n pendingMaps.length = 0;\n },\n };\n}\n\n/** Exposed so a test can assert the workgroup size the reduction was written for. */\nexport const ANALYSIS_DISPATCH = { workgroupSize: ANALYSIS_WORKGROUP, workgroups: 1 } as const;\n","import { readbackDue } from \"./analysis\";\nimport { linearToSrgbChannel, relativeLuminance } from \"./color\";\nimport { createStorageSlot, createUniformSlot, type GpuContext } from \"./gpu-context\";\nimport type { ResolvedSurface } from \"./instances\";\nimport type { FieldPassArgs, FieldTargets } from \"./passes\";\nimport type { PyramidResources } from \"./pyramid\";\nimport { silhouetteFieldModule, silhouetteReductionModule } from \"./wgsl/silhouette-tone\";\n\n/** Structural twin of core's readout: the renderer cannot import its parent package. */\nexport interface SurfaceBackdropToneAbscissa {\n readonly surfaceId: string;\n readonly kind: \"source\" | \"silhouette\" | \"hint\";\n readonly encodedLuminance: number;\n readonly luminance: number;\n readonly linearLuminance: number;\n readonly color: readonly [number, number, number];\n readonly sampleCount: number;\n readonly level: number;\n readonly sourceWidth: number;\n readonly sourceHeight: number;\n readonly sampledWidth: number;\n readonly sampledHeight: number;\n}\n\n/** The mask follows the resolved surface's own bounds, including a concentric inset\n * or press compression, but retains G0's circular corner convention. */\nexport function packToneShapes(surfaces: readonly ResolvedSurface[], dpr: number): Float32Array {\n const data = new Float32Array(surfaces.length * 8);\n surfaces.forEach((surface, i) => {\n const [w, h] = surface.shape.channels.size;\n data.set([\n (surface.centre[0] - w / 2) * dpr, (surface.centre[1] - h / 2) * dpr,\n w * dpr, h * dpr, surface.shape.corner.radius * dpr, 0, 0, 0,\n ], i * 8);\n });\n return data;\n}\n\ninterface DrawArgs {\n readonly groupId: string;\n readonly field: FieldPassArgs;\n readonly fields: FieldTargets;\n readonly surfaces: readonly ResolvedSurface[];\n readonly pyramid: PyramidResources;\n readonly viewportDevice: readonly [number, number];\n readonly fit: readonly [number, number, number, number];\n readonly fallbackTone: readonly [number, number, number, number];\n readonly timeMs: number;\n readonly cadenceHz: number;\n readonly liveSource: boolean;\n}\n\ntype SourceFallback = DrawArgs[\"fallbackTone\"];\n\ninterface Reduction {\n readonly chain: GPUTexture;\n readonly geometryKey: string;\n readonly builtEpoch: number;\n readonly timeMs: number;\n readonly metadata: readonly ReadingMetadata[];\n}\n\ntype ReadingMetadata = Pick<SurfaceBackdropToneAbscissa,\n \"surfaceId\" | \"sourceWidth\" | \"sourceHeight\" | \"sampledWidth\" | \"sampledHeight\">;\n\nexport function toneReadingsFromBuffer(\n values: ArrayLike<number>, metadata: readonly ReadingMetadata[], fallback?: SourceFallback,\n): readonly SurfaceBackdropToneAbscissa[] {\n return metadata.flatMap((meta, i): SurfaceBackdropToneAbscissa[] => {\n if (values[i * 8 + 7]! > 0) return [{\n ...meta, kind: \"silhouette\", level: 0,\n color: [values[i * 8]!, values[i * 8 + 1]!, values[i * 8 + 2]!],\n luminance: values[i * 8 + 3]!, encodedLuminance: values[i * 8 + 4]!,\n linearLuminance: values[i * 8 + 5]!, sampleCount: values[i * 8 + 6]!,\n }];\n if (fallback === undefined || fallback[3] < 0) return [];\n const [r, g, b, luminance] = fallback;\n // The caller supplies the source reference, not its sampling provenance. Do\n // not attribute the empty silhouette's dimensions or count to that reference.\n return [{\n surfaceId: meta.surfaceId, kind: \"source\", color: [r, g, b], luminance,\n encodedLuminance: linearToSrgbChannel(luminance),\n // The local optics field derives this channel from RGB, including fallback.\n linearLuminance: relativeLuminance([r, g, b]), sampleCount: 0, level: 0,\n sourceWidth: 0, sourceHeight: 0, sampledWidth: 0, sampledHeight: 0,\n }];\n });\n}\n\nexport function createSilhouetteTonePass(context: GpuContext) {\n const { device, cache, pool } = context;\n const createEntry = (count: number, groupId: string) => ({\n groupId, count,\n shapes: createStorageSlot(device, count * 32, \"vitrea:tone-shapes\"),\n instances: createStorageSlot(device, count * 72, \"vitrea:tone-instances\"),\n uniform: createUniformSlot(device, 8, \"vitrea:tone-uniform\"),\n fieldUniform: createUniformSlot(device, 16, \"vitrea:tone-field-uniform\"),\n tones: device.createBuffer({ size: count * 32,\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC }),\n readback: device.createBuffer({ size: count * 32,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ }),\n reduced: undefined as Reduction | undefined,\n encodedReduction: false,\n observation: undefined as { reduction: Reduction; values: Float32Array } | undefined,\n fallback: undefined as SourceFallback | undefined,\n encodedFallback: undefined as SourceFallback | undefined,\n queued: undefined as Reduction | undefined,\n pending: undefined as Promise<void> | undefined,\n });\n const entries = new Map<string, ReturnType<typeof createEntry>>();\n const destroyEntry = (entry: ReturnType<typeof createEntry>) => {\n entry.shapes.destroy();\n entry.instances.destroy();\n entry.uniform.buffer.destroy();\n entry.fieldUniform.buffer.destroy();\n entry.tones.destroy();\n entry.readback.destroy();\n };\n const forget = (resourceId: string) => {\n const entry = entries.get(resourceId);\n if (entry !== undefined) destroyEntry(entry);\n entries.delete(resourceId);\n pool.release(`tone-field:${resourceId}`);\n };\n\n return {\n draw(encoder: GPUCommandEncoder, args: DrawArgs): GPUTextureView {\n const { field, pyramid, fields } = args;\n let entry = entries.get(field.resourceId);\n if (entry !== undefined && entry.count !== field.instanceCount) {\n forget(field.resourceId);\n entry = undefined;\n }\n if (entry === undefined) {\n entry = createEntry(field.instanceCount, args.groupId);\n entries.set(field.resourceId, entry);\n }\n const shapeData = packToneShapes(args.surfaces, 1 / field.cssPerDevice);\n const geometryKey = JSON.stringify([\n pyramid.sourceId, pyramid.sizeEpoch, pyramid.sourceWidth, pyramid.sourceHeight,\n pyramid.plan.width, pyramid.plan.height, ...shapeData, ...args.viewportDevice,\n ...args.fit, ...args.surfaces.map((surface) => surface.nodeId),\n ]);\n const previous = entry.reduced;\n // Pixel changes on a live source share the existing adaptation cadence;\n // replacement pixels from a static image or gradient take effect immediately.\n // A changed footprint, fit or resource cannot reuse the old surface's mean,\n // even when that cadence is disabled. Static frames do neither GPU reduction\n // nor readback; the tone field below still follows the current optical union.\n if (previous === undefined || previous.chain !== pyramid.chain ||\n previous.geometryKey !== geometryKey ||\n (previous.builtEpoch !== pyramid.builtEpoch &&\n (!args.liveSource || readbackDue(previous.timeMs, args.timeMs, args.cadenceHz)))) {\n entry.reduced = {\n chain: pyramid.chain, geometryKey, builtEpoch: pyramid.builtEpoch, timeMs: args.timeMs,\n metadata: args.surfaces.map((surface) => ({\n surfaceId: surface.nodeId,\n sourceWidth: pyramid.sourceWidth, sourceHeight: pyramid.sourceHeight,\n sampledWidth: pyramid.plan.width, sampledHeight: pyramid.plan.height,\n })),\n };\n entry.encodedReduction = true;\n entry.shapes.write(shapeData, shapeData.length);\n entry.uniform.data.set([...args.viewportDevice, 0, 0, ...args.fit]);\n entry.uniform.write();\n const pipeline = cache.computePipeline(\"silhouette-reduction\", () => ({\n layout: \"auto\",\n compute: { module: cache.module(\"silhouette-reduction\", silhouetteReductionModule),\n entryPoint: \"reduce_tone\" },\n }));\n const pass = encoder.beginComputePass({ label: \"vitrea:silhouette-reduction\" });\n pass.setPipeline(pipeline);\n pass.setBindGroup(0, device.createBindGroup({\n layout: pipeline.getBindGroupLayout(0), entries: [\n { binding: 0, resource: { buffer: entry.uniform.buffer } },\n { binding: 1, resource: pyramid.chain.createView({ baseMipLevel: 0, mipLevelCount: 1 }) },\n { binding: 3, resource: { buffer: entry.shapes.buffer } },\n { binding: 4, resource: { buffer: entry.tones } },\n ],\n }));\n pass.dispatchWorkgroups(field.instanceCount);\n pass.end();\n }\n entry.instances.write(field.instances, field.instanceCount * 18);\n entry.encodedFallback = args.fallbackTone;\n\n // A busy readback may miss a reduction. Copy the latest cached buffer once\n // it is idle, but never publish an old observation as the newer geometry.\n if (entry.queued === undefined && entry.pending === undefined &&\n entry.observation?.reduction !== entry.reduced) {\n encoder.copyBufferToBuffer(entry.tones, 0, entry.readback, 0, entry.count * 32);\n entry.queued = entry.reduced;\n }\n\n const texture = pool.acquire(`tone-field:${field.resourceId}`, {\n width: fields.width, height: fields.height, format: \"rgba16float\",\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,\n });\n const u = entry.fieldUniform;\n u.data.set([field.rectDevice.width, field.rectDevice.height, field.cssPerDevice, 0,\n field.union.neckWidth, field.union.maxBulge, field.union.separationThreshold, 0]);\n new Uint32Array(u.data.buffer)[8] = field.instanceCount;\n u.data.set(args.fallbackTone, 12);\n u.write();\n const fieldPipeline = cache.renderPipeline(`silhouette-field:${field.family}`, () => ({\n layout: \"auto\",\n vertex: { module: cache.module(`silhouette-field:${field.family}`,\n () => silhouetteFieldModule(field.family)), entryPoint: \"vs_fullscreen\" },\n fragment: { module: cache.module(`silhouette-field:${field.family}`,\n () => silhouetteFieldModule(field.family)), entryPoint: \"fs_tone\",\n targets: [{ format: \"rgba16float\" }] },\n primitive: { topology: \"triangle-list\" },\n }));\n const view = texture.createView();\n const fieldPass = encoder.beginRenderPass({ label: \"vitrea:silhouette-field\",\n colorAttachments: [{ view, loadOp: \"clear\", storeOp: \"store\" }] });\n fieldPass.setPipeline(fieldPipeline);\n fieldPass.setBindGroup(0, device.createBindGroup({\n layout: fieldPipeline.getBindGroupLayout(0), entries: [\n { binding: 0, resource: { buffer: u.buffer } },\n { binding: 1, resource: { buffer: entry.instances.buffer } },\n { binding: 2, resource: { buffer: entry.tones } },\n ],\n }));\n fieldPass.draw(3);\n fieldPass.end();\n return view;\n },\n afterSubmit() {\n for (const entry of entries.values()) {\n entry.encodedReduction = false;\n if (entry.encodedFallback !== undefined) entry.fallback = entry.encodedFallback;\n entry.encodedFallback = undefined;\n const reduction = entry.queued;\n if (reduction === undefined) continue;\n entry.queued = undefined;\n entry.pending = entry.readback.mapAsync(GPUMapMode.READ).then(() => {\n entry.observation = {\n reduction, values: new Float32Array(entry.readback.getMappedRange()).slice(),\n };\n entry.readback.unmap();\n }).catch(() => {\n // Removal or device loss invalidates the observation, not the next draw.\n entry.observation = undefined;\n }).finally(() => { entry.pending = undefined; });\n }\n },\n cancelQueued() {\n for (const entry of entries.values()) {\n // An unsubmitted reduction never initialized the cached GPU buffer.\n if (entry.encodedReduction) entry.reduced = undefined;\n entry.encodedReduction = false;\n entry.encodedFallback = undefined;\n entry.queued = undefined;\n }\n },\n async collect() {\n await Promise.all([...entries.values()].map((entry) => entry.pending));\n },\n readings(groupId: string): readonly SurfaceBackdropToneAbscissa[] {\n return [...entries.values()].filter((entry) => entry.groupId === groupId)\n .flatMap((entry) => entry.observation === undefined ||\n entry.observation.reduction !== entry.reduced ? [] : toneReadingsFromBuffer(\n entry.observation.values, entry.observation.reduction.metadata, entry.fallback,\n ));\n },\n forget,\n destroy() {\n for (const resourceId of entries.keys()) forget(resourceId);\n },\n };\n}\n","/**\n * The renderer: device, resources, and the frame.\n *\n * Two entry points, deliberately:\n *\n * - **`drawFrame`** — draw one frame into two texture views. No scene, no\n * scheduler, no DOM. This is what the golden suite and the benchmark drive, and\n * what makes the optical maths testable without standing up the whole runtime.\n * - **`frameParticipant`** — the same work split across core's `write` and\n * `render` phases, so `vitrea`'s scheduler drives it alongside\n * platform-web's DOM participant. Pyramid rebuilds land in `write` because that\n * is the phase core hands them out in; drawing lands in `render`, with the graph\n * frozen.\n *\n * The participant reads the frame's `resolution` when core supplies one, and\n * prefers it over the group input's own `refraction`/`analysis` — core is the\n * authority on resolved state (X2), and it is the frame's resolution that has been\n * through the whole transition table. The group input's copies are the fallback for\n * `drawFrame`, where there is no core.\n *\n * ## Device generations\n *\n * Everything GPU-shaped hangs off a `GpuContext` tagged with the device generation\n * that made it. On loss the context is dropped whole, and the first frame on the\n * replacement re-points every registered provider at the new device and marks it\n * for re-import — so recovery flows through the ordinary\n * one-rebuild-per-dirty-source-per-frame path instead of a special case, which\n * means the recovery path is exercised by the same tests as the steady state.\n *\n * `ensureContext` is where that happens rather than the loss teardown, and the\n * reason is timing: the teardown runs while there is no device to adopt, and this\n * is the one place that knows both that a generation was superseded and what\n * replaced it. It also runs before anything acquires on the new device, which the\n * teardown cannot promise.\n *\n * The one provider that cannot be re-pointed is a backdrop over the *app's* own\n * texture: WebGPU has no cross-device sharing and the renderer does not own the\n * texture, so that provider refuses instead, and the refused rebuild is reported\n * through `unbuiltSources` for the host to act on.\n */\n\nimport { DEFAULT_GROUP_UNION, type GroupUnionParams } from \"@vitrea/geometry\";\n\nimport { createAdaptationState, readbackDue, type AdaptationState } from \"./analysis\";\nimport type { BackdropProvider } from \"./backdrop\";\nimport {\n coverFit,\n isUsablePlacement,\n placementFit,\n samePlacement,\n texelsPerCssPx,\n type BackdropFit,\n type BackdropPlacement,\n} from \"./backdrop-fit\";\nimport { OUTPUT_TEXTURE_FORMAT, relativeLuminance, linearToSrgbChannel } from \"./color\";\nimport {\n createDeviceHost,\n type DeviceCapabilityInput,\n type DeviceHost,\n type DeviceOwnership,\n type RendererDeviceStatus,\n} from \"./device\";\nimport { rendererError } from \"./errors\";\nimport { createGpuContext, type GpuContext } from \"./gpu-context\";\nimport { createGovernor, type Governor } from \"./governor\";\nimport {\n clipFieldRectToCanvas,\n drawsMaterial,\n groupFieldRect,\n packInstances,\n resolveSurfaces,\n snapRectToDevicePixels,\n type ResolvedSurface,\n} from \"./instances\";\nimport {\n accessibilityRefractionCap,\n adaptationStrength,\n backdropToneSizeBiasUnderPolicy,\n backdropToneUnderPolicy,\n bodyChromaRetentionUnderPolicy,\n collapsedRimUnderPolicy,\n collapseTransmissionAtScale,\n DEFAULT_MATERIAL_PROFILE,\n effectiveRefraction,\n NOMINAL_MATERIAL_POLICY,\n opticsUnderPolicy,\n outerShadowOcclusionAt,\n outerShadowReachPx,\n outerShadowThinOcclusion,\n outerShadowUnderPolicy,\n rimWidthAtScale,\n scatterFloorAtScale,\n scatterGainAtScale,\n scatterGainFarAtScale,\n heavySecondTapSigmaAtScale,\n heavyTapSigmaAtScale,\n scatterHeavyShareThickAtScale,\n scatterRampReachDevicePx,\n scatterRampStart,\n scatterSpanMaxAtScale,\n tintToneAdaptation,\n withMaterialOverrides,\n type MaterialPolicyView,\n type MaterialProfile,\n type MaterialProfilePatch,\n type MaterialVariant,\n} from \"./material\";\nimport { createSilhouetteTonePass, type SurfaceBackdropToneAbscissa } from \"./silhouette-tone\";\nimport { createPassRunner, groupResourceId, type DeviceRect, type PassRunner } from \"./passes\";\nimport {\n createPyramidStore,\n sameHeavySigma,\n type PyramidResources,\n type PyramidStore,\n} from \"./pyramid\";\nimport { chainLodForSigma, type ResolutionPolicyView } from \"./pyramid-plan\";\nimport type {\n FrameContextView,\n FrameParticipantView,\n GroupRenderInput,\n RebuildRequestView,\n SceneResolutionView,\n} from \"./render-model\";\nimport type { TimingCollector } from \"./timing\";\nimport { allShaderSource } from \"./wgsl\";\n\nexport const OPTICS_PASS_ID = \"vitrea.optics\";\nexport const HIGHLIGHT_PASS_ID = \"vitrea.highlight\";\nexport const FIELD_PASS_ID = \"vitrea.field\";\nexport const BACKDROP_PASS_ID = \"vitrea.backdrop\";\nexport const ANALYSIS_PASS_ID = \"vitrea.analysis\";\n\nexport const RENDERER_PASS_IDS = [\n BACKDROP_PASS_ID,\n ANALYSIS_PASS_ID,\n FIELD_PASS_ID,\n OPTICS_PASS_ID,\n HIGHLIGHT_PASS_ID,\n] as const;\n\n/*\n * `NOMINAL_MATERIAL_POLICY` now lives in `material.ts` and is re-exported here so\n * every existing importer is unaffected. It moved because `instances.ts` needs it\n * as a default — the size law folds under the policy, so surface resolution takes\n * one — and instances sits below this module in the graph, so importing it from\n * here would have closed a cycle. It was always a material constant that happened\n * to be declared beside the renderer that first used it.\n */\nexport { NOMINAL_MATERIAL_POLICY } from \"./material\";\n\nexport interface ViewportState {\n /** Viewport size in CSS px. */\n readonly widthCss: number;\n readonly heightCss: number;\n readonly devicePixelRatio: number;\n}\n\nexport interface RendererInstrumentation {\n readonly pyramid: PyramidStore[\"instrumentation\"];\n readonly texturePool: { readonly live: number; readonly created: number; readonly destroyed: number };\n readonly pipelines: { readonly renderPipelines: number; readonly computePipelines: number };\n readonly framesDrawn: number;\n readonly deviceGenerations: number;\n}\n\nexport interface DrawFrameArgs {\n readonly frame: { readonly id: number; readonly timeMs: number };\n /** The optics canvas' current texture view. */\n readonly optics: GPUTextureView;\n /** The highlight canvas' view. Omit to skip the highlight pass entirely. */\n readonly highlight?: GPUTextureView;\n readonly format?: GPUTextureFormat;\n /**\n * The rebuild requests core handed out. Omitted means \"ask every registered\n * provider whether it is dirty\", which is what `drawFrame` does standalone.\n */\n readonly rebuild?: readonly RebuildRequestView[];\n /** Core's resolved state for this frame. Overrides the group inputs' copies. */\n readonly resolution?: SceneResolutionView;\n readonly timing?: TimingCollector;\n /** Clear the targets first. Default true. */\n readonly clear?: boolean;\n /**\n * Which plane these targets are, for a host that draws more than one.\n *\n * The renderer treats it as an opaque namespace: it qualifies each group's\n * pooled resources (`groupResourceId`) so that one group id drawn on two\n * planes owns two independent sets rather than reallocating one set twice a\n * frame, and it appears in the resource labels. It names no logical group and\n * no state. Omitted is the single-plane namespace, which is what a standalone\n * renderer, the goldens and the calibration harness all draw in.\n */\n readonly plane?: string;\n}\n\nexport interface DrawFrameResult {\n readonly groupsDrawn: number;\n readonly rebuilds: number;\n readonly skipped: readonly { readonly groupId: string; readonly reason: string }[];\n /**\n * Source ids core handed out a rebuild for that this frame did **not** build.\n * The same list as `GlassRenderer.unbuiltSources` — see it for what a caller\n * owes.\n */\n readonly unbuilt: readonly string[];\n}\n\nexport interface WebGPURendererOptions {\n /** An app-owned device. Given one, the renderer never requests its own. */\n readonly device?: GPUDevice;\n readonly ownership?: DeviceOwnership;\n /** Re-request a vitrea-owned device after loss. */\n readonly reacquire?: () => Promise<GPUDevice | undefined>;\n readonly onReplacementNeeded?: () => void;\n readonly onDeviceStatusChange?: (status: RendererDeviceStatus) => void;\n /** Whether family C's f32 cross-check has passed (Decision Log #20). */\n readonly familyCVerified?: boolean;\n readonly viewport?: ViewportState;\n /**\n * Optical tunables to override, on top of `DEFAULT_MATERIAL_PROFILE`. This is\n * where a calibrated set lands (C7): a patch, not a whole profile, so a host\n * naming one tint alpha inherits every number it did not measure.\n */\n readonly materialProfile?: MaterialProfilePatch;\n}\n\nexport interface GlassRenderer {\n readonly backend: \"webgpu\";\n /** True only with a live, unlost device attached. */\n readonly ready: boolean;\n readonly passes: readonly string[];\n readonly shaderSource: string;\n readonly deviceStatus: RendererDeviceStatus;\n /** The facts a host folds into core's `PlatformProbe`. */\n readonly capabilityInput: DeviceCapabilityInput;\n readonly governor: Governor;\n readonly instrumentation: RendererInstrumentation;\n /**\n * The source ids the most recent frame was handed a rebuild for and did not\n * build — because no provider is registered under the id, or because the\n * provider could not serve a frame.\n *\n * This exists because core commits `builtEpoch` when it *hands out* the\n * request, not when the renderer finishes: a request dropped here is a claim\n * spent on nothing, and the source would sit clean at an epoch whose pixels\n * were never imported. Core has no view of this side of the wire, so the\n * renderer names the losses and the platform layer re-dirties them — one frame\n * of latency, and no new core surface.\n *\n * Accumulated across the frame's planes, not per `drawFrame` call: a host draws\n * one plane per call with the same frame id and hands the dirty set to the\n * first of them only, so a later plane's empty answer must not erase what the\n * first one found. Read after the frame's last plane, or after the\n * participant's `render` phase. Empty on every ordinary frame.\n */\n readonly unbuiltSources: readonly string[];\n\n attachDevice(device: GPUDevice, ownership?: DeviceOwnership): void;\n replaceDevice(device: GPUDevice): void;\n markWebGPUUnavailable(reason: \"no-adapter\" | \"device-request-failed\"): void;\n\n registerBackdrop(provider: BackdropProvider): void;\n unregisterBackdrop(sourceId: string): void;\n backdrop(sourceId: string): BackdropProvider | undefined;\n /**\n * Where a source's pixels sit on the plane, in CSS px relative to the viewport\n * (`backdrop-fit.ts`). Set every read phase by a host that measured the source\n * element's box; `undefined` (or never set) is the cover fit, the rule every\n * golden and calibration capture was taken under. Accepted before the provider\n * is registered and kept across device generations; cleared by\n * `unregisterBackdrop`.\n */\n setBackdropPlacement(sourceId: string, placement: BackdropPlacement | undefined): void;\n backdropPlacement(sourceId: string): BackdropPlacement | undefined;\n\n setViewport(viewport: ViewportState): void;\n readonly viewport: ViewportState;\n\n setGroup(input: GroupRenderInput): void;\n removeGroup(groupId: string): void;\n setAccessibility(policy: MaterialPolicyView): void;\n /**\n * Replace the optical tunables. The patch is applied to\n * `DEFAULT_MATERIAL_PROFILE`, never to the profile currently in force, so two\n * calls do not compound — a profile is a set of measurements, and half of one\n * measurement set over half of another describes no material.\n */\n setMaterialProfile(patch: MaterialProfilePatch): void;\n /** The tunables in force. Read-only; `setMaterialProfile` is the way in. */\n readonly materialProfile: MaterialProfile;\n\n drawFrame(args: DrawFrameArgs): DrawFrameResult;\n /**\n * Targets for the participant path, where core drives the phases. `plane` is\n * `DrawFrameArgs.plane` — see it.\n */\n setTargets(targets: { readonly optics: GPUTextureView; readonly highlight?: GPUTextureView; readonly format?: GPUTextureFormat; readonly plane?: string }): void;\n frameParticipant(): FrameParticipantView;\n\n /** Resolve any completed analysis readbacks into the adaptation drivers. */\n collectAdaptation(): Promise<number>;\n /** Actual GPU reduction, resolved asynchronously after the submitted draw. */\n backdropToneAbscissae(groupId: string): readonly SurfaceBackdropToneAbscissa[];\n destroy(): void;\n}\n\ninterface GroupEntry {\n readonly input: GroupRenderInput;\n}\n\n/** The resolution policy a renderer driven without a host applies to every source. */\nconst STANDALONE_RESOLUTION: ResolutionPolicyView = { scale: 1, maxDimension: 2048 };\n\nexport function createWebGPURenderer(options: WebGPURendererOptions = {}): GlassRenderer {\n const providers = new Map<string, BackdropProvider>();\n /** Where each source sits on the plane, where the host has said (`backdrop-fit.ts`). */\n const placements = new Map<string, BackdropPlacement>();\n /** The resolution policy each source was last built under, for a rebuild this side names. */\n const lastResolution = new Map<string, ResolutionPolicyView>();\n const groups = new Map<string, GroupEntry>();\n const adaptation = new Map<string, AdaptationState>();\n const lastReadbackAt = new Map<string, number>();\n const hintedTones = new Map<string, {\n groupId: string; readings: readonly SurfaceBackdropToneAbscissa[];\n }>();\n\n let accessibility: MaterialPolicyView = NOMINAL_MATERIAL_POLICY;\n let material: MaterialProfile = withMaterialOverrides(\n DEFAULT_MATERIAL_PROFILE,\n options.materialProfile ?? {},\n );\n let viewport: ViewportState = options.viewport ?? {\n widthCss: 0,\n heightCss: 0,\n devicePixelRatio: 1,\n };\n let context: GpuContext | undefined;\n /**\n * The last device generation a context was built for. Kept apart from\n * `context` because it has to survive `dropContext()` — the loss teardown runs\n * long before the replacement arrives, and \"which generation did the providers\n * build against\" is the question the replacement has to answer.\n */\n let builtGeneration: number | undefined;\n let store: PyramidStore | undefined;\n let runner: PassRunner | undefined;\n let silhouetteTone: ReturnType<typeof createSilhouetteTonePass> | undefined;\n let framesDrawn = 0;\n let generations = 0;\n let lastFrameTimeMs: number | undefined;\n let targets:\n | {\n optics: GPUTextureView;\n highlight?: GPUTextureView;\n format: GPUTextureFormat;\n plane: string;\n }\n | undefined;\n /**\n * Every plane this renderer has drawn a group on, so `removeGroup` can reach\n * each namespace the group may have allocated in (`groupResourceId`).\n *\n * Recorded where the groups are drawn rather than where the targets are set,\n * because `setTargets` can name a plane no draw ever reaches and a plane\n * nothing was drawn on holds nothing to forget.\n */\n const planesDrawn = new Set<string>();\n let pendingEncoder: GPUCommandEncoder | undefined;\n let pendingRebuilds = 0;\n let pendingUnbuilt: string[] = [];\n let unbuiltFrameId: number | undefined;\n\n /**\n * Accumulate the frame's unbuilt sources, across planes.\n *\n * A host draws one plane per `drawFrame` with the same frame id and hands the\n * dirty set to the first of them only, so the later planes' empty lists must\n * not erase what the first one found. Same rule as the rebuild ledger's, for\n * the same reason: a repeated frame id is one frame.\n */\n const recordUnbuilt = (frameId: number, ids: readonly string[]): void => {\n if (unbuiltFrameId !== frameId) {\n unbuiltFrameId = frameId;\n pendingUnbuilt = [];\n }\n for (const id of ids) if (!pendingUnbuilt.includes(id)) pendingUnbuilt.push(id);\n };\n\n const governor = createGovernor({\n ...(options.familyCVerified === undefined ? {} : { familyCVerified: options.familyCVerified }),\n });\n\n const dropContext = (): void => {\n store?.destroy();\n silhouetteTone?.destroy();\n silhouetteTone = undefined;\n hintedTones.clear();\n runner?.destroy();\n context?.destroy();\n store = undefined;\n runner = undefined;\n context = undefined;\n pendingEncoder = undefined;\n };\n\n const host: DeviceHost = createDeviceHost({\n ...(options.reacquire === undefined ? {} : { reacquire: options.reacquire }),\n ...(options.onReplacementNeeded === undefined\n ? {}\n : { onReplacementNeeded: options.onReplacementNeeded }),\n onStatusChange: (status) => {\n if (status.generation !== generations) generations = status.generation;\n options.onDeviceStatusChange?.(status);\n },\n });\n\n // Loss teardown: drop every resource, and mark every backdrop for re-import so\n // recovery uses the ordinary dirty path. Registered once — the hook survives\n // every generation, because the host outlives the contexts.\n host.addTeardownHook(() => {\n dropContext();\n adaptation.clear();\n lastReadbackAt.clear();\n });\n\n const ensureContext = (): { context: GpuContext; store: PyramidStore; runner: PassRunner } => {\n const device = host.requireDevice();\n const generation = host.status.generation;\n if (context === undefined || context.generation !== generation) {\n const superseded = builtGeneration;\n dropContext();\n context = createGpuContext(device, generation);\n builtGeneration = generation;\n store = createPyramidStore(context);\n runner = createPassRunner(context);\n silhouetteTone = createSilhouetteTonePass(context);\n // The providers outlive the context, and every one of them closes over the\n // device it was built with. Re-pointing them here — rather than in the loss\n // teardown — is what makes the timing right: this is the one place that\n // knows both that a device generation was superseded and what replaced it,\n // and it runs before any provider is acquired on the new device.\n //\n // Only a real transition invalidates. A provider registered before any\n // device existed has built nothing to throw away, and one already tagged\n // with this generation was built for this device.\n if (superseded !== undefined && superseded !== generation) {\n for (const provider of providers.values()) {\n if (provider.generation !== generation) provider.invalidate(generation, device);\n }\n }\n }\n return {\n context,\n store: store as PyramidStore,\n runner: runner as PassRunner,\n };\n };\n\n const adaptationFor = (sourceId: string): AdaptationState => {\n let state = adaptation.get(sourceId);\n if (state === undefined) {\n state = createAdaptationState(undefined, material);\n adaptation.set(sourceId, state);\n }\n return state;\n };\n\n /**\n * The uv transform the optics pass samples a source through: the placed fit\n * where the host measured where the source sits on the plane, the cover fit\n * where it did not (`backdrop-fit.ts`). Cover is computed from the PLAN's\n * extent, as it always was — the plan may have downscaled the source, and the\n * rounding of that downscale is part of every golden's bytes.\n */\n const fitFor = (sourceId: string, pyramid: PyramidResources): BackdropFit => {\n const placement = placements.get(sourceId);\n return isUsablePlacement(placement)\n ? placementFit(placement, viewport.widthCss, viewport.heightCss)\n : coverFit(pyramid.plan.width, pyramid.plan.height, viewport.widthCss, viewport.heightCss);\n };\n\n /**\n * The chain level the outer shadow's lift copies the backdrop from (W14 G1) —\n * the continuous level whose blur is `liftBlurSigmaCss` in CSS px, clamped to\n * what the chain actually has.\n *\n * The conversion is only knowable here, for the same reason `bodyChainLod`'s\n * is: it needs the source's texels per CSS px and the downscale the plan\n * applied, which is the pyramid's own record of how it was built. Clamped\n * rather than extrapolated — a chain too short to reach σ 40 CSS px copies the\n * backdrop at the widest blur it has, which is the closest thing to the\n * measured term that exists on that source, and the sweep's amplitude absorbs\n * the difference.\n */\n const liftChainLod = (sigmaCss: number, pyramid: PyramidResources | undefined): number => {\n if (pyramid === undefined || !(sigmaCss > 0)) return 0;\n const planScale = pyramid.sourceWidth > 0 ? pyramid.plan.width / pyramid.sourceWidth : 1;\n const sigmaTexels = sigmaCss * pyramid.texelsPerCss * planScale;\n return Math.min(chainLodForSigma(sigmaTexels), pyramid.plan.maxLod);\n };\n\n /**\n * A source whose body would come out differently from the one on its chain,\n * for a reason that never re-dirties it: a placement that changed SIZE moves\n * the texels-per-CSS-px the σ is converted with, and a window moved between a\n * 1x and a 2x display moves the σ itself, because the body's widths are\n * device-pixel quantities on this tier and the CSS-px σ the pyramid converts\n * is `blurSigma / dpr` (W12 G3, claims §5.56; restored by W15 G1, claims\n * §5.69 §1, after W13 Decision Log 8 had withdrawn it). A policy or profile\n * change moves it too (W13 G1, review finding). A static image fixes none of\n * these on its own. Named here as its own rebuild request, at\n * the epoch the chain already holds so the store's clean check falls through\n * to `sameBody` rather than to the epoch.\n */\n const staleBodyRebuilds = (\n explicit: readonly RebuildRequestView[],\n pyramids: PyramidStore,\n ): readonly RebuildRequestView[] => {\n const requests: RebuildRequestView[] = [];\n const named = new Set(explicit.map((request) => request.sourceId));\n // Every registered source, not only the placed ones: a placement WITHDRAWN\n // moves the density back to the cover ratio, and that is a change too.\n for (const sourceId of providers.keys()) {\n if (named.has(sourceId)) continue;\n const existing = pyramids.resources(sourceId);\n if (existing === undefined) continue;\n const next = texelsPerCssPx(\n existing.sourceWidth,\n existing.sourceHeight,\n placements.get(sourceId),\n viewport.widthCss,\n viewport.heightCss,\n );\n const sameDensity =\n Math.abs(next - existing.texelsPerCss) <= 1e-6 * Math.max(1, existing.texelsPerCss);\n const sigmaCss = bodySigmaCssFor(sourceId);\n const sameSigma =\n Math.abs(sigmaCss - existing.bodySigmaCss) <= 1e-6 * Math.max(1, existing.bodySigmaCss);\n // The heavy blur rides the same staleness rule (W26): it is built from the\n // same chain at the same density, so a ratio change that moved the body's\n // σ moved its σ too, and a clean source would otherwise keep the previous\n // display's heavy width. Through `sameHeavySigma` rather than the tolerance\n // above it, because the width's ON/OFF state is not a small difference in a\n // number: a tolerance around zero calls σ 1e-7 and σ 0 equal, and those two\n // are a heavy texture the pass binds and no heavy texture at all.\n const sameHeavy = sameHeavySigma(heavySigmaCssFor(sourceId), existing.heavySigmaCss);\n // The second heavy blur rides the identical rule (W30 G2).\n const sameHeavy2 = sameHeavySigma(\n heavySecondSigmaCssFor(sourceId),\n existing.heavy2SigmaCss,\n );\n if (sameDensity && sameSigma && sameHeavy && sameHeavy2) continue;\n requests.push({\n sourceId,\n epoch: existing.builtEpoch,\n resolution: lastResolution.get(sourceId) ?? STANDALONE_RESOLUTION,\n groupIds: [...groups.values()]\n .filter((entry) => entry.input.backdropSourceId === sourceId)\n .map((entry) => entry.input.groupId),\n });\n }\n return requests;\n };\n\n const unionOf = (input: GroupRenderInput): GroupUnionParams =>\n input.union ?? DEFAULT_GROUP_UNION;\n\n const variantOf = (input: GroupRenderInput): MaterialVariant => input.variant ?? \"regular\";\n\n /** The variant of whichever group samples this source, \"regular\" if none does. */\n const sourceVariant = (sourceId: string): MaterialVariant => {\n const input = [...groups.values()].find(\n (entry) => entry.input.backdropSourceId === sourceId,\n )?.input;\n return input === undefined ? \"regular\" : variantOf(input);\n };\n\n /**\n * The body σ in CSS px a build for this source would ask for.\n *\n * `blurSigma` is a DEVICE-pixel quantity on this tier (W12 G3, claims §5.56\n * §1; the reference's body is one kernel in device pixels at both scales,\n * §5.55 §1, and reading it so puts the 2x interior's structure on the\n * reference at every span, §5.58 §2). So the CSS-px σ the pyramid converts to\n * source texels with is `blurSigma / dpr`: it moves when the window moves\n * between displays even though nothing about the source changed.\n *\n * W13 Decision Log 8 withdrew this division as a LANDING — at the 1x deep\n * value the narrower 2x widths took the four large checkerboard rows down\n * 0.006–0.017 — and W15 restores it as a term of the 2x form, beside the deep\n * value that makes it right (claims §5.69 §1–§2; W15 Decision Log 2). It is\n * the GPU tier's alone: the shared projection `sizeScatterSigmaAt` takes no\n * ratio, and the CSS tier holds W13 Decision Log 5 until G1's prediction.\n *\n * `buildPyramids` passes this and `staleBodyRebuilds` compares it against the\n * σ the chain was built with, so the two cannot drift apart.\n */\n const bodySigmaCssFor = (sourceId: string): number => {\n const optics = opticsUnderPolicy(\n material.optics[sourceVariant(sourceId)],\n accessibility,\n material,\n );\n return optics.blurSigma / Math.max(viewport.devicePixelRatio, 1e-3);\n };\n\n /**\n * The heavy blur's σ in CSS px a build for this source would ask for (W26;\n * `MaterialProfile.sizeHeavyTapSigma`), 0 where the profile declines it.\n *\n * `bodySigmaCssFor`'s rule exactly, for the same measured reason: the heavy\n * width is a device-px quantity (claims §5.113 §2), so the CSS-px σ the pyramid\n * converts to source texels with is the device σ over the ratio. It is a\n * property of the SOURCE and not of the group, because the texture is built\n * once per source per frame before any group is drawn — which is the trade\n * W26 Decision Log 2 (b) took and `PyramidResources.heavy` records.\n *\n * It reads the material rather than the variant's optics for the WIDTH: the\n * heavy width is one number for the material, and no variant restates it.\n *\n * **But a source with no body has no heavy component either** (W26 G2's review;\n * Decision Log 7 (d)). The heavy sample is one component of the BODY — the two\n * are mixed by `kScatter` and nothing else consumes it — so a material whose\n * resolved `blurSigma` is 0 asks for no blur at all and must get none. That was\n * free while the heavy width was a multiple of the sharp one, on this tier\n * through `scatterLod`'s dependence on `bodyChainLod` and on the CSS tier\n * through `blurSigma × gain`; a width named in device px inherits nothing, so\n * both tiers state it. `cssTierHeavySigmaCssPx` carries the same rule.\n *\n * On the shipped accessibility path this is unreachable rather than merely\n * unused: core couples `frost: \"none\"` to `glass: \"none\"` and the renderer then\n * disconnects backdrop sampling entirely. What it covers is a MATERIAL that\n * names `optics.regular.blurSigma` 0 — a supported override — which would\n * otherwise have drawn an unblurred body with a 9 device px deep sample mixed\n * into it here and nothing at all on the mirror.\n */\n const heavySigmaCssFor = (sourceId: string): number => {\n if (bodySigmaCssFor(sourceId) <= 0) return 0;\n return (\n heavyTapSigmaAtScale(material, viewport.devicePixelRatio) /\n Math.max(viewport.devicePixelRatio, 1e-3)\n );\n };\n\n /**\n * The SECOND heavy blur's σ in CSS px a build for this source would ask for\n * (W30 G2), 0 wherever the material leaves `sizeHeavySecondShare` at 0.\n *\n * `heavySigmaCssFor`'s rule exactly, including the \"a source with no body has\n * no heavy component either\" clause, because the second heavy sample is a\n * component of the same body and is mixed into the same `kScatter`. The width\n * is already in CSS px in the profile — the fit has not yet said whether its\n * two scale readings halve into each other the way `sizeHeavyTapSigma`'s do —\n * so this applies `rampAtScale` and nothing else, and\n * `heavySecondTapSigmaAtScale` is where the share's gate lives.\n */\n const heavySecondSigmaCssFor = (sourceId: string): number => {\n if (bodySigmaCssFor(sourceId) <= 0) return 0;\n return heavySecondTapSigmaAtScale(material, viewport.devicePixelRatio);\n };\n\n /**\n * The one tint seed this group's optics pass draws with.\n *\n * A group is one pass and one uniform, so the seed is per group while the\n * strength is per pixel — enough for the composition Apple's guidance actually\n * describes (one emphasised control among plain ones) and not enough for two\n * hues in one container, which core reports as `tint-mixing`. The first tinted\n * drawn member wins, deterministically, rather than an average nobody chose.\n *\n * DRAWN is `drawsMaterial`'s definition and not a weaker one, which matters\n * since W27d gave it a second member: a surface at `materialization: 0` is not\n * in this group's field pass at all, so a group whose emphasised control has\n * dematerialized has to paint with the colour of a control that is still there.\n * Reading the first tinted member regardless would hand the pass the absent\n * one's hue and paint the surviving control with it.\n */\n const groupTintSeed = (input: GroupRenderInput): readonly [number, number, number] | undefined =>\n input.surfaces.find(\n (surface) => drawsMaterial(surface) && (surface.tint?.strength ?? 0) > 0,\n )?.tint?.color;\n\n const stateOf = (\n input: GroupRenderInput,\n resolution: SceneResolutionView | undefined,\n ): { refraction: GroupRenderInput[\"refraction\"]; analysisExact: boolean } => {\n const resolved = resolution?.groups.find((group) => group.groupId === input.groupId);\n if (resolved === undefined) {\n return { refraction: input.refraction, analysisExact: input.analysisExact };\n }\n return {\n refraction: resolved.state.refraction,\n analysisExact: resolved.state.analysis === \"exact\",\n };\n };\n\n function rebuildRequests(explicit: readonly RebuildRequestView[] | undefined): readonly RebuildRequestView[] {\n const base = explicit ?? standaloneRequests();\n const { store: pyramids } = ensureContext();\n const stale = staleBodyRebuilds(base, pyramids);\n return stale.length === 0 ? base : [...base, ...stale];\n }\n\n function standaloneRequests(): readonly RebuildRequestView[] {\n // Standalone path: ask each provider a group actually samples.\n const sampled = new Set<string>();\n for (const entry of groups.values()) {\n const id = entry.input.backdropSourceId;\n if (id !== undefined) sampled.add(id);\n }\n const requests: RebuildRequestView[] = [];\n for (const sourceId of sampled) {\n const provider = providers.get(sourceId);\n if (provider === undefined || !provider.isDirty()) continue;\n requests.push({\n sourceId,\n // Standalone, every dirty acquire is its own epoch: there is no core\n // keeping the books, so a monotonically rising number is the honest\n // stand-in and it keeps `build`'s clean-skip from firing spuriously.\n epoch: framesDrawn + 1,\n resolution: STANDALONE_RESOLUTION,\n groupIds: [...groups.values()]\n .filter((entry) => entry.input.backdropSourceId === sourceId)\n .map((entry) => entry.input.groupId),\n });\n }\n return requests;\n }\n\n function runRebuilds(\n encoder: GPUCommandEncoder,\n requests: readonly RebuildRequestView[],\n frameTimeMs: number,\n ): { built: number; unbuilt: readonly string[] } {\n const { store: pyramids } = ensureContext();\n let built = 0;\n const unbuilt: string[] = [];\n\n for (const request of requests) {\n const provider = providers.get(request.sourceId);\n if (provider === undefined) {\n // Core spent the claim on a source this renderer has never heard of — a\n // group registered ahead of its backdrop, or a source unregistered\n // between the hand-out and here.\n unbuilt.push(request.sourceId);\n continue;\n }\n\n lastResolution.set(request.sourceId, request.resolution);\n\n const placement = placements.get(request.sourceId);\n const outcome = pyramids.build(\n {\n sourceId: request.sourceId,\n epoch: request.epoch,\n resolution: request.resolution,\n // The body's sharp width is a DEVICE-pixel quantity (W12 G3, claims\n // §5.56; restored by W15 G1): `blurSigma` device px, so\n // `blurSigma / dpr` in the CSS px the pyramid converts to source\n // texels with. The heavy component rides the same conversion — its\n // level is this one plus log2(the gain at this ratio) octaves — so it\n // is the gain's own multiple of the sharp width in device px at every\n // scale. At dpr 1 this is `optics.blurSigma` unchanged, which is what\n // leaves the 1x law exactly as landed.\n bodySigmaCss: bodySigmaCssFor(request.sourceId),\n // The heavy blur's own σ, through the same conversion (W26). At 0 the\n // pyramid allocates nothing and encodes nothing.\n heavySigmaCss: heavySigmaCssFor(request.sourceId),\n // The second heavy blur's σ (W30 G2). At 0 — the landed material —\n // the pyramid allocates nothing and encodes nothing, exactly as for\n // the first one.\n heavy2SigmaCss: heavySecondSigmaCssFor(request.sourceId),\n viewportCss: [viewport.widthCss, viewport.heightCss],\n ...(isUsablePlacement(placement) ? { placement } : {}),\n },\n provider,\n encoder,\n );\n if (outcome.status === \"built\") built += 1;\n // \"clean\" and \"duplicate\" are both honest answers — the source already has\n // the pixels this epoch asked for. \"unavailable\" is not: the claim is spent\n // and nothing was imported.\n else if (outcome.status === \"unavailable\") unbuilt.push(request.sourceId);\n }\n\n // Analysis readback, cadence-gated by the governor. Every source with a\n // pyramid is eligible, whether or not it rebuilt this frame — a static\n // backdrop still needs its stats read once.\n const cadence = governor.knobs.adaptationCadenceHz;\n for (const sourceId of providers.keys()) {\n if (pyramids.resources(sourceId) === undefined) continue;\n if (!readbackDue(lastReadbackAt.get(sourceId), frameTimeMs, cadence)) continue;\n if (pyramids.requestStats(sourceId, encoder)) lastReadbackAt.set(sourceId, frameTimeMs);\n }\n\n return { built, unbuilt };\n }\n\n function drawGroups(\n encoder: GPUCommandEncoder,\n resolution: SceneResolutionView | undefined,\n timeMs: number,\n ): DrawFrameResult {\n const { store: pyramids, runner: passes } = ensureContext();\n const active = targets;\n if (active === undefined) {\n throw rendererError(\n \"pass-input\",\n \"No render targets are set. Call setTargets() (or pass views to drawFrame) before drawing.\",\n );\n }\n\n const dpr = Math.max(viewport.devicePixelRatio, 1e-3);\n const cssPerDevice = 1 / dpr;\n const viewportDevice: readonly [number, number] = [\n Math.max(1, Math.round(viewport.widthCss * dpr)),\n Math.max(1, Math.round(viewport.heightCss * dpr)),\n ];\n\n const skipped: { groupId: string; reason: string }[] = [];\n let drawn = 0;\n planesDrawn.add(active.plane);\n const resourceOf = (groupId: string): string => groupResourceId(active.plane, groupId);\n\n /*\n * A group that draws nothing on this plane this frame holds nothing for it.\n *\n * The group stays REGISTERED — the author has not unregistered it, its\n * `setGroup` input is still live, and the frame its presence rises again\n * allocates a fresh set through the ordinary `acquire`. What goes is the\n * pooled state, which is a group field texture, its aux, aux2 and presence\n * targets, the instance storage buffer and three uniform buffers: enough to\n * be worth returning for a surface an author has PARKED (`present={false}`,\n * claims §5.132 §1), which is an intended steady state and not a transient,\n * and which under W27d resolves to an empty drawing set that the loop below\n * bails out of on every subsequent frame.\n *\n * `passes.forget` is idempotent, which is what lets one rule cover every way\n * a group can draw nothing rather than one release site per reason.\n */\n const releaseIdle = (groupId: string): void => {\n passes.forget(resourceOf(groupId));\n silhouetteTone?.forget(resourceOf(groupId));\n hintedTones.delete(resourceOf(groupId));\n };\n\n for (const entry of groups.values()) {\n const input = entry.input;\n /*\n * No surfaces on THIS plane, which is the same case as the ones below and\n * not a special one — but only because the resources are plane-qualified.\n *\n * A host hands every group to every plane's draw and lets the plane's own\n * node list decide which of them have members there, so this is the\n * ordinary answer for a base-plane group during the overlay plane's draw.\n * Keyed on the group id alone, releasing here would have destroyed the\n * resources the other plane allocated moments earlier; keyed on the plane\n * too, it releases the namespace of a plane the group is not on, which is\n * exactly what a cross-plane promotion leaves behind.\n */\n if (input.surfaces.length === 0) {\n releaseIdle(input.groupId);\n continue;\n }\n\n // The frame's resolved material policy, read before the surfaces rather\n // than after: the size law folds under it (W2), so surface resolution needs\n // it to decide how thick each member reads.\n const policy = resolution?.accessibility.material ?? accessibility;\n\n let surfaces: readonly ResolvedSurface[];\n try {\n surfaces = resolveSurfaces(input, governor.knobs.fieldFamily, material, policy);\n } catch (error) {\n skipped.push({\n groupId: input.groupId,\n reason: error instanceof Error ? error.message : String(error),\n });\n releaseIdle(input.groupId);\n continue;\n }\n\n const union = unionOf(input);\n /*\n * Clipped to the plane canvas, and clipped once, so that three things go on\n * describing the same rectangle.\n *\n * `groupFieldRect` grows the surface union by the rim and bulge margin, so a\n * surface within a few CSS px of the viewport's top or left edge produces a\n * rect with a negative origin. `opticsPass` and `highlightPass` scissor to\n * this rect on the plane canvas and `setScissorRect` takes unsigned values,\n * so an unclipped rect is a hard `RangeError` out of the WebGPU binding\n * rather than a clipped draw. A toolbar pinned to the left edge is enough to\n * hit it.\n *\n * The clip has to reach the instance frame too. The field texture is\n * allocated at this rect's size and `fs_optics` reads it by `uv` over the\n * *viewport*, so moving the viewport without moving the texture and the\n * instance origin with it would stretch the glass instead of clipping it.\n * That is why the origin handed to `packInstances` is derived from the\n * clipped device rect rather than from the CSS rect it came from. What is\n * lost is the part of the field that lies outside the canvas, which is the\n * part nothing can see.\n *\n * A group entirely on screen is unaffected: `snapRectToDevicePixels` has\n * already put both edges on device-pixel boundaries, so the arithmetic below\n * reproduces the previous origin and extent exactly.\n */\n /*\n * The outer shadow (W8) is resolved before the rect, because it is what\n * sizes the rect: the optics pass scissors to this rectangle, so the pad has\n * to reach as far as the shadow draws or the facet is sliced off at the\n * contour. Both folds land here on the CPU — the accessibility regime and\n * the linear-to-compositing-space conversion — so the shader carries the\n * curve and not the regime, as every other axis does.\n */\n const shadow = outerShadowUnderPolicy(policy, material);\n /*\n * The backdrop luminance the shadow's thin regime keys on (W14 G1) — and\n * it is the SAME statistic W9's face response keys on, which is the\n * charter's third binding rule: the backdrop's ENCODED-space mean,\n * decoded, one number per group, measured by the host. `undefined` where\n * the host measured none, which the law reads as its mid plateau rather\n * than as black.\n *\n * Resolved here rather than beside the pass because the rect's pad below\n * depends on it: over `light-solid` the shadow is a third of what it is\n * over the checkerboard, and a pad taken from the wrong amplitude is\n * either a slice or a waste.\n */\n const shadowBackdropLuminance =\n input.backdropTone === undefined\n ? undefined\n : (input.backdropToneLevel ?? relativeLuminance(input.backdropTone));\n /*\n * The pad covers the DEEPEST shadow any member of this group can emit,\n * which is not the group's base amplitude. The size law amplifies the\n * amplitude per surface and the shader reads the CASTING surface's own\n * thickness, so a rect padded from the base while a thick platter emitted\n * more would slice that surface's shadow off at the scissor — and the CSS\n * tier, having no scissor, would go on drawing it, which is a cross-tier\n * divergence rather than a cost. The gain ships at the identity, so this is\n * inert today and correct for whatever the cascade fits.\n *\n * A maximum over the members rather than the thickest member's value,\n * because a profile is entitled to a negative gain and then the THINNEST\n * surface is the one that reaches furthest.\n */\n let reachOcclusion = outerShadowThinOcclusion(shadowBackdropLuminance, shadow);\n /*\n * And the widest σ, for the same reason one step along (W30 G2). Since\n * macOS 27 the blur is graded by the CASTING span (`outerShadowSigmaPx`),\n * so a rect padded at one member's σ while a wider member emitted a wider\n * one slices that member's shadow off at the scissor. The pad is a bound,\n * not a value: it is taken at the deepest amplitude and the largest span\n * ANY member carries, even where those are two different members, because\n * one rectangle has to contain every member's shadow and the reach is\n * monotone in both arguments on the law the material ships.\n */\n let reachSpanPx = 0;\n for (const surface of surfaces) {\n reachOcclusion = Math.max(\n reachOcclusion,\n outerShadowOcclusionAt(\n shadow,\n shadowBackdropLuminance,\n surface.spanPx,\n surface.sizeThickness,\n material,\n ),\n );\n reachSpanPx = Math.max(reachSpanPx, surface.spanPx);\n }\n const shadowReachPx = outerShadowReachPx(shadow, reachOcclusion, reachSpanPx);\n\n const snapped = snapRectToDevicePixels(\n groupFieldRect(surfaces, union, undefined, shadowReachPx),\n dpr,\n );\n /*\n * Nothing left to draw: every member resolved away — the whole group at\n * `materialization: 0`, or a group of nothing but reference shapes — or\n * what survived lies entirely off the canvas. `groupFieldRect` over an\n * empty list yields nothing and `clipFieldRectToCanvas` clips it to\n * `undefined`, which is the one condition both reach.\n */\n const rectDevice: DeviceRect | undefined = clipFieldRectToCanvas(snapped, dpr, viewportDevice);\n if (rectDevice === undefined) {\n releaseIdle(input.groupId);\n continue;\n }\n\n /*\n * The surface's OWN rect — the rect every pass used before W8, and the one\n * the highlight pass still uses.\n *\n * The shadow made the field rect several times larger on a small control,\n * and the highlight draws nothing out there: `fs_highlight` returns on\n * `coverage <= 0`, so those fragments were rasterised, read twice and\n * thrown away. On the benchmark's mobile scene that was 1.0 ms of a 3.1 ms\n * frame, interleaved against the same scene with the shadow declined. The\n * optics pass cannot be scoped this way — it is what draws the shadow.\n */\n const surfaceRectDevice: DeviceRect =\n shadowReachPx === 0\n ? rectDevice\n : (clipFieldRectToCanvas(\n snapRectToDevicePixels(groupFieldRect(surfaces, union), dpr),\n dpr,\n viewportDevice,\n ) ?? rectDevice);\n\n const packed = packInstances(surfaces, [\n rectDevice.x * cssPerDevice,\n rectDevice.y * cssPerDevice,\n ]);\n const fieldArgs = {\n resourceId: resourceOf(input.groupId),\n family: governor.knobs.fieldFamily,\n rectDevice,\n cssPerDevice,\n coverageRampCss: cssPerDevice,\n // Ladder rungs 2 and 3 turn this down; rung 0 and 1 leave it at 1, which\n // is the extent the group's rect already had.\n renderScale: governor.knobs.refractionResolutionScale,\n instances: packed.data,\n instanceCount: packed.count,\n union,\n };\n const fields = passes.fieldPass(encoder, fieldArgs);\n\n const state = stateOf(input, resolution);\n const variant = variantOf(input);\n const sourceId = input.backdropSourceId;\n const pyramid = sourceId === undefined ? undefined : pyramids.resources(sourceId);\n const adapt =\n sourceId === undefined ? undefined : adaptationFor(sourceId).values;\n const localTone = typeof material.backdropToneAbscissa === \"object\" &&\n input.backdropToneHint !== true && pyramid !== undefined && sourceId !== undefined &&\n surfaces.length > 0\n ? silhouetteTone?.draw(encoder, {\n groupId: input.groupId, field: fieldArgs, fields, surfaces, pyramid,\n viewportDevice, fit: fitFor(sourceId, pyramid),\n timeMs, cadenceHz: governor.knobs.adaptationCadenceHz,\n liveSource: providers.get(sourceId)?.kind !== \"image\" &&\n providers.get(sourceId)?.kind !== \"gradient\",\n fallbackTone: [\n input.backdropTone?.[0] ?? 0, input.backdropTone?.[1] ?? 0,\n input.backdropTone?.[2] ?? 0,\n input.backdropTone === undefined ? -1 :\n input.backdropToneLevel ?? relativeLuminance(input.backdropTone),\n ],\n })\n : undefined;\n if (localTone === undefined) silhouetteTone?.forget(resourceOf(input.groupId));\n const hintLevel = input.backdropToneLevel ??\n (input.backdropTone === undefined ? undefined : relativeLuminance(input.backdropTone));\n if (typeof material.backdropToneAbscissa === \"object\" &&\n input.backdropToneHint === true && hintLevel !== undefined &&\n input.backdropTone !== undefined) {\n const color = input.backdropTone;\n hintedTones.set(resourceOf(input.groupId), {\n groupId: input.groupId,\n readings: surfaces.map((surface) => ({\n surfaceId: surface.nodeId, kind: \"hint\", color,\n encodedLuminance: linearToSrgbChannel(hintLevel), luminance: hintLevel,\n linearLuminance: input.backdropToneLinearLuminance ?? hintLevel,\n sampleCount: 0, level: 0,\n sourceWidth: 0, sourceHeight: 0, sampledWidth: 0, sampledHeight: 0,\n })),\n });\n } else hintedTones.delete(resourceOf(input.groupId));\n /*\n * The response and size laws always read the LINEAR profile (W27f G1).\n * DOM groups convert only their final layer, after evaluating the material\n * at the measured tone; feeding an encoded alpha into the response solve\n * made the thick dark pane 0.089 OKLab L too dark (claims §5.129).\n */\n const nominalOptics = material.optics[variant];\n const optics = opticsUnderPolicy(nominalOptics, policy, material);\n\n /*\n * Backdrop tone adaptation (W7). Both policy folds resolve here, on the\n * CPU, so the shaders carry the curve and not the regime — and the optics\n * and highlight passes are handed the same four numbers, because a\n * highlight that outlived the surface it belongs to is exactly what two\n * copies of one curve produce.\n *\n * The strength is zero unless the host measured a backdrop tone for this\n * group. That is not a defensive default: this axis moves the material onto\n * a colour, and the only colour it may move onto is one somebody measured.\n */\n const backdropTone: readonly [number, number, number, number] = [\n material.backdropToneLow,\n material.backdropToneHigh,\n backdropToneSizeBiasUnderPolicy(policy, material),\n input.backdropTone === undefined && localTone === undefined\n ? 0\n : backdropToneUnderPolicy(policy, material) * material.backdropToneMax,\n ];\n // The tone LEVEL is the encoded-space reading (W9); the tone COLOUR stays\n // the physical linear mean the collapse converges onto. Hosts that predate\n // the split fall back to the colour's own luminance.\n // The same reading the shadow's thin regime resolved against above, with\n // \"no backdrop\" spelled as 0 for the tone axis, whose strength is already\n // stood down there.\n const backdropToneLevel = shadowBackdropLuminance ?? 0;\n // Decision Log #19's dual cap, resolved once, on the CPU.\n const refraction = effectiveRefraction(\n accessibilityRefractionCap(policy),\n state.refraction,\n );\n const refractionScale = material.refractionScale[refraction];\n\n passes.opticsPass(encoder, {\n resourceId: resourceOf(input.groupId),\n target: active.optics,\n targetFormat: active.format,\n rectDevice,\n fields,\n ...(localTone === undefined ? {} : { localTone }),\n viewportDevice,\n cssPerDevice,\n coverageRampCss: cssPerDevice,\n fit:\n pyramid === undefined || sourceId === undefined\n ? [1, 1, 0, 0]\n : fitFor(sourceId, pyramid),\n refractionScale,\n lensRefractionGain: material.lensRefractionGain,\n // The lens law (W12 G2) and the inner shadow's own depth gain, both\n // evaluated per pixel in the shader from the thickness and the span.\n lensHeightPerSpan: material.lensHeightPerSpan,\n lensHeightMax: material.lensHeightMax,\n lensAmountPerSpan: material.lensAmountPerSpan,\n lensAmountMax: material.lensAmountMax,\n lensThicknessReference: material.lensThicknessReference,\n lensExtentGain: material.lensExtentGain,\n lensProfileExponent: material.lensProfileExponent,\n lensOvalization: material.lensOvalization,\n lensOvalizationSpanMin: material.lensOvalizationSpanMin,\n lensOvalizationSpanMax: material.lensOvalizationSpanMax,\n shadowDepthSizeGainMax: material.lensSizeGainMax,\n chainMaxLod: pyramid?.plan.maxLod ?? 0,\n tint: optics.tint,\n tintAlpha: optics.tintAlpha,\n adaptTint: adapt?.tint ?? optics.tint,\n adaptStrength:\n adapt?.observed === true\n ? adaptationStrength(policy, state.analysisExact, material)\n : 0,\n /*\n * `glass: \"none\"` is forced colours, and it takes the author's tint with\n * the rest of the material.\n *\n * The pass keeps running — it is what paints the surface at all on this\n * tier — but with no backdrop and an opaque occlusion, so whatever colour\n * sits here IS the surface. An author tint arriving into that lands as a\n * flat fill of the author's colour where the platform's palette is\n * required, which is the one composition forced colours exists to\n * prevent. Falling back to the material's own tint reproduces exactly\n * what an untinted surface draws.\n */\n tintSeed: (policy.glass === \"none\" ? undefined : groupTintSeed(input)) ?? optics.tint,\n tintToneAdaptation: tintToneAdaptation(policy, material),\n tintShade: [material.tintShadeDark, material.tintShadeLight, material.tintShadeStrength],\n tintChromaScale: material.tintChromaScale ?? 1,\n tintShadeCollapseRetention: material.tintShadeCollapseRetention ?? 0,\n // The band's half-width is a per-scale reading since W23: the reference's\n // rim narrows between the scales where vitrea's widened (claims §5.100\n // §5). At dpr 1, and on any variant whose two anchors are equal, this is\n // `optics.rimWidth` exactly.\n rimWidth: rimWidthAtScale(optics, dpr),\n rimAlpha: optics.rimAlpha,\n specularPower: optics.specularPower,\n specularGain: optics.specularGain,\n // The rim's amplitude law (W23). The level gain is per variant, because\n // a variant with a different `rimAlpha` has a different rim; the two\n // collapsed rims are the profile's, because the collapsed appearance is\n // one appearance and the reference's fixtures carry it identically in\n // both schemes, painted or bare (X4).\n rimLevelGain: optics.rimLevelGain,\n // Both ends of the collapsed rim's tint lerp, under the accessibility\n // regime: `collapsedRimUnderPolicy` returns the two absolute constants\n // unless a preference has asked for a border, in which case both ends are\n // the border's own alpha and the shader's `mix` is that constant at every\n // tint strength (W23 G1's review fix).\n rimCollapsed: collapsedRimUnderPolicy(policy, 0, material),\n rimCollapsedTinted: collapsedRimUnderPolicy(policy, 1, material),\n // The rim's light in the author's own colour (W23 G3). Under a strong\n // border the rim is the preference's mark and not the material's, so it\n // stays white: an accessibility border that took the paint's hue would\n // be the paint again, which is what it exists not to be.\n rimTintChroma: policy.border === \"strong\" ? 0 : material.rimTintChroma,\n lightDirection: material.lightDirection,\n // The lit edge (W24): the rim's own axis, kept apart from\n // `lightDirection` because the shadow reads that one and the two are\n // measured 22 degrees apart. The exponent comes from the variant's\n // optics under the accessibility fold, so a strong border's rim is one\n // brightness the whole way round.\n rimLitAxis: material.rimLitAxis,\n rimLitExponent: optics.rimLitExponent,\n // W25's three mechanisms (claims §5.113; W25 Decision Log 3), each of\n // them 0 on the landed material. The along-side field's slope is the\n // variant's under the same accessibility fold as the exponent it grades;\n // the heavy share's thick lift is resolved at the ratio this group draws\n // at, on the pattern every second-scale constant already has; the level\n // term's gain is the profile's, and the span curve it rides is the\n // shader's own `farS`.\n rimAlongSideSlope: optics.rimAlongSideSlope,\n sizeScatterHeavyShareThick: scatterHeavyShareThickAtScale(material, dpr),\n sizeToneLevelFar: material.sizeToneLevelFar,\n // The heavy blur (W26): whether this group's source carries one. The width\n // itself is already in the texture, so this pass only chooses which of\n // two textures the deep sample comes from.\n heavyTapEnabled: pyramid?.heavy !== undefined,\n /*\n * W30's two operators (claims §5.156 §2 and §3; §5.158), every word of\n * them 0 on the landed material.\n *\n * The shadow's σ law crosses as three leaves rather than one width,\n * because the shader reads it per pixel from the casting surface's own\n * span. The scatter's scale conditioning crosses as the material's gain\n * and reference plus the SOURCE's own statistic — the analysis pass's\n * edge density, which arrives by readback and is therefore resolved\n * here, like `bodyChainLod`. `adapt` is the filtered reading, so the\n * statistic the shader sees is the one the drivers have settled on\n * rather than a raw frame's.\n *\n * Where nothing has been observed the statistic is the material's own\n * REFERENCE rather than 0 — the same gate `adaptStrength` takes two\n * fields above, and for the same reason. The shader evaluates\n * `gain · (statistic − reference)`, so a reference is the value at which\n * the operator contributes nothing; passing 0 instead is that identity\n * only while the reference happens to be 0, and the moment §5.159 fits\n * one every unobserved frame would evaluate `gain · (0 − ref)` at full\n * magnitude — a group whose backdrop readback has not landed yet would\n * draw at the operator's full excursion and then step to its resting\n * value. The reference says \"no evidence\", which is what an unobserved\n * source has (W30 G2 review closure, claims §5.158 §8, finding 3).\n */\n outerShadowSigmaLaw: [\n shadow.sigmaSlopePerSpan,\n shadow.sigmaSpanRefPx,\n shadow.sigmaThinOffsetPx,\n ],\n sizeScatterScaleGain: material.sizeScatterScaleGain,\n sizeScatterScaleRef: material.sizeScatterScaleRef,\n backdropScaleStatistic:\n adapt?.observed === true ? adapt.edgeDensity : material.sizeScatterScaleRef,\n sizeHeavySecondShare: material.sizeHeavySecondShare,\n heavySecondEnabled: pyramid?.heavy2 !== undefined,\n // W31's body chroma retention (claims §5.164): a material constant, per\n // group, with no source-side half — the chromaticity it restores toward\n // is the blurred backdrop the optics pass already sampled per pixel.\n //\n // Under the accessibility fold it stands down (W31 Decision Log 3 (d);\n // claims §5.164 §8 (b) and §13): an occlusion lift covers more of the\n // backdrop, so restoring the nominal fraction of its chromaticity gives\n // back what the preference asked to have covered — measured at `R` 3.05\n // and 3.17 against a reference of 1. `bodyChromaRetentionUnderPolicy` is\n // exactly `material.bodyChromaRetention` where no preference is set,\n // which is why every standard row is bit-identical across this fold.\n bodyChromaRetention: bodyChromaRetentionUnderPolicy(material.bodyChromaRetention, policy),\n ...(pyramid === undefined && input.unsampledMaterial !== undefined\n ? { domMaterial: {\n ...input.unsampledMaterial,\n mode: input.backdropTone === undefined ? 1 : 2,\n } }\n : {}),\n shadowDepth: optics.shadowDepth,\n shadowAlpha: optics.shadowAlpha,\n // The size law's gains, per group (W2); the per-pixel factor they\n // multiply rides the field pass's aux channel, so one uniform serves a\n // group whose members are not one size. `bodyChainLod` is where the body\n // blur already sits on the chain — only the pyramid that built it knows\n // the CSS-px-to-texel conversion, so it publishes the σ and this converts.\n // The gain at the ratio this group draws at (W15 G1, claims §5.69 §1):\n // the shader's scatter level is `bodyChainLod + log2(gain)`, so this is\n // where the heavy width's second scale acts. `sizeScatterGainMax2x`\n // defaults to the 1x gain, so this is `material.sizeScatterGainMax`\n // until the sweep fits it.\n sizeScatterGainMax: scatterGainAtScale(material, dpr),\n // The gain's far end at the same ratio (W15 G1's re-form, claims §5.70\n // §4 and §7): the shader grades the gain from the near end at\n // `sizeSpanMax` to this at `sizeScatterSpanMax`, because the reference's\n // heavy kernel grows with the span and one gain left the largest span's\n // deep interior too structured. `sizeScatterGainFar2x` defaults to the\n // 2x gain's own default and interpolates from the 1x gain, so this is\n // `sizeScatterGainMax` at dpr 1 whatever the profile says.\n sizeScatterGainFar: scatterGainFarAtScale(material, dpr),\n sizeOcclusionGain: material.sizeOcclusionGain,\n sizeShadowGainMax: material.sizeShadowGainMax,\n bodyChainLod: chainLodForSigma(pyramid?.bodySigmaTexels ?? 0),\n // The size law's curves (W11c): the shader evaluates the thickness and\n // the scatter mix per pixel from the span the field carries, under the\n // same fold `sizeThicknessUnderPolicy` applies on the CPU.\n sizeSpanMin: material.sizeSpanMin,\n sizeSpanMax: material.sizeSpanMax,\n // The deep value's floor and span top at this ratio (W15 G1, claims\n // §5.69 §2). Same two uniform slots the shader has always read for\n // `kDeep` and for the fold; only the value is resolved from the\n // viewport now, as the ramp's anchors already were.\n sizeScatterFloor: scatterFloorAtScale(material, dpr),\n sizeScatterSpanMax: scatterSpanMaxAtScale(material, dpr),\n // The body's depth ramp (W13 G1, claims §5.61 §2, §5.64 §5), resolved\n // from the viewport's own ratio: the profile anchors the start's thin\n // and thick ends and the reach at dpr 1 and dpr 2, and the CPU\n // interpolates all three in dpr. The start's SPAN grading stays in the\n // shader, because a group's members are not one size and the span\n // arrives per pixel on the field's own channel — so the two anchors go\n // over and `sizeThickness` is evaluated there. The reach is handed over\n // in CSS px because the field's depth is in CSS px.\n sizeScatterRampStartThin: scatterRampStart(dpr, material, 0),\n sizeScatterRampStartThick: scatterRampStart(dpr, material, material.sizeSpanMax),\n // The fourth form's far end, at the scatter span curve's top; the shader\n // declines from the thick end to it along that curve.\n sizeScatterRampStartFar: scatterRampStart(\n dpr,\n material,\n scatterSpanMaxAtScale(material, dpr),\n ),\n sizeScatterRampReachCssPx: scatterRampReachDevicePx(dpr, material) / dpr,\n sizeFold: material.refractionScale[accessibilityRefractionCap(policy)],\n backdropTone,\n backdropToneColour: [\n input.backdropTone?.[0] ?? 0,\n input.backdropTone?.[1] ?? 0,\n input.backdropTone?.[2] ?? 0,\n backdropToneLevel,\n ],\n // The response law's anchors (W9) and the linear backdrop mean its\n // solve composites against. The shader re-derives the encoded input\n // from `backdropToneLevel`, so the fourth slot carries the linear\n // mean — the one quantity the solve needs that the tone colour does\n // not already hold.\n backdropToneAnchorX: material.backdropToneAnchorX,\n backdropToneResponseThin: material.backdropToneResponseThin,\n backdropToneResponseThick: material.backdropToneResponseThick,\n // The response law rides only the UN-DEGRADED regime, for the same\n // provenance reason the dark profiles set its strength to 0: the\n // anchors are standard-light-reference measurements, and the\n // accessibility references behave differently (nearly opaque, flat in\n // span — W2). Measured before this gate existed: reduced-transparency\n // photo ΔE p95 0.007 → 0.048 and cross-tier ratio 0.99 → 0.86. Where\n // any policy fold touches the tone axis, the solve stands down and the\n // collapse alone runs, exactly the pre-W9 behaviour those profiles\n // were fitted on.\n backdropToneResponseStrength:\n backdropToneUnderPolicy(policy, material) >= 0.999\n ? material.backdropToneResponseStrength\n : 0,\n backdropToneLinearMean:\n input.backdropToneLinearLuminance ?? backdropToneLevel,\n /*\n * The collapse's transmission (W24 G1) rides the UN-DEGRADED regime, on\n * the same gate and for the same reason as the response law above: it is\n * fitted on the standard reference, and the accessibility references are\n * a nearly opaque material whose collapsed appearance was never read\n * over a textured backdrop. Where any policy fold touches the tone axis\n * the collapse's target is the group's mean, which is W7's behaviour and\n * what those profiles were fitted on.\n */\n collapseTransmission:\n backdropToneUnderPolicy(policy, material) >= 0.999\n ? collapseTransmissionAtScale(material, dpr)\n : 0,\n outerShadow: [\n // The thin regime's LINEAR occlusion at this group's backdrop (W14\n // G1). The conversion to the compositing space moved into the shader\n // with the regimes: it is not linear, so converting one regime here\n // and blending in the shader would not be the same law.\n outerShadowThinOcclusion(shadowBackdropLuminance, shadow),\n shadow.sigmaPx,\n shadow.spreadPx,\n // The offset in field-texture UV. The field spans exactly this rect, so\n // one CSS px is one over the rect's CSS height however the governor\n // scaled the rasterisation.\n shadow.offsetPx / Math.max(rectDevice.height * cssPerDevice, 1e-6),\n ],\n outerShadowThick: [\n shadow.thickOcclusionAt96,\n shadow.thickOcclusionAt128,\n shadow.thickOcclusionAt160,\n ],\n outerShadowLift: [\n // A DOM layer can evaluate the lift at its stated tone, but not at\n // unknown exterior pixels. No tone still means no light to add.\n policy.glass === \"none\" ||\n (pyramid === undefined &&\n (input.unsampledMaterial === undefined || input.backdropTone === undefined))\n ? 0 : shadow.liftAmplitude,\n shadow.liftSpanMin,\n shadow.liftSpanFull,\n liftChainLod(shadow.liftBlurSigmaCss, pyramid),\n ],\n outerShadowSizeGain: shadow.sizeGain,\n outerShadowRectCssHeight: rectDevice.height * cssPerDevice,\n backdrop:\n pyramid === undefined || policy.glass === \"none\"\n ? undefined\n : {\n chain: pyramid.chain.createView(),\n body: pyramid.body.createView(),\n heavy: pyramid.heavy?.createView(),\n heavy2: pyramid.heavy2?.createView(),\n },\n });\n\n if (active.highlight !== undefined) {\n // One sweep phase and one press point per group: there is one pointer, and\n // a sweep travelling the container's unioned contour is what a\n // GlassEffectContainer is for. The per-pixel glow comes off the aux target.\n const lead = surfaces.reduce(\n (best, surface) => (surface.channels.glow > best.channels.glow ? surface : best),\n surfaces[0] as ResolvedSurface,\n );\n passes.highlightPass(encoder, {\n resourceId: resourceOf(input.groupId),\n target: active.highlight,\n targetFormat: active.format,\n // The surface's own rect, not the shadow's — see `surfaceRectDevice`.\n rectDevice: surfaceRectDevice,\n fieldRectDevice: rectDevice,\n fields,\n ...(localTone === undefined ? {} : { localTone }),\n viewportDevice,\n cssPerDevice,\n sweep: lead.channels.sweep,\n sweepBandRadians: material.sweepBandRadians,\n /*\n * The band's amplitude, from the same lead surface that supplies its\n * phase. `shimmer` is 0 on a resting surface and nothing in v1 drives\n * it, so a surface nobody is animating contributes exactly no sweep\n * term and the pass writes nothing on its rim — the contract the\n * pass's own comment states, which the profile's `sweepGain` alone\n * could not keep, because 0 radians of the band's angular coordinate\n * is the left edge rather than nowhere (W22's Design; the defect\n * claims §5.90 §4 isolated).\n *\n * Reduced Motion removes shimmer travel outright rather than freezing\n * it, on this same product, and that zeroing is unchanged.\n */\n sweepGain: policy.glass === \"none\" ? 0 : material.sweepGain * lead.channels.shimmer,\n // `rimWidth`, NOT the scale-graded band the optics pass takes (W23).\n // The second anchor was fitted on the ambient rim read at the contour\n // on a resting surface, and this band carries the specular sweep,\n // which is gated to nothing at rest (W22) and has no row on any bed.\n // A constant whose rows do not separate it is not applied here either.\n rimWidth: optics.rimWidth,\n pressPointCss: lead.channels.pressPoint ?? lead.centre,\n glowRadiusCss: material.glowRadiusCss,\n glowGain: material.glowGain,\n colour: optics.highlight,\n // The same four numbers the optics pass took, so the two passes fade\n // the surface on one curve rather than on two copies of it — and the\n // same band and fold, since the curve is evaluated off the span.\n backdropTone,\n backdropToneLevel,\n sizeSpanMin: material.sizeSpanMin,\n sizeSpanMax: material.sizeSpanMax,\n sizeFold: material.refractionScale[accessibilityRefractionCap(policy)],\n });\n }\n\n drawn += 1;\n }\n\n return { groupsDrawn: drawn, rebuilds: pendingRebuilds, skipped, unbuilt: [...pendingUnbuilt] };\n }\n\n return {\n backend: \"webgpu\",\n\n get ready() {\n return host.status.device !== undefined && host.status.deviceHealth === \"ok\";\n },\n\n passes: RENDERER_PASS_IDS,\n shaderSource: allShaderSource(),\n\n get deviceStatus() {\n return host.status;\n },\n\n get capabilityInput() {\n return host.capabilityInput;\n },\n\n governor,\n\n get unbuiltSources() {\n return pendingUnbuilt;\n },\n\n get instrumentation() {\n const pool = context?.pool.stats;\n const cache = context?.cache.stats;\n return {\n pyramid:\n store?.instrumentation ?? {\n rebuilds: 0,\n refusedDuplicates: 0,\n skippedClean: 0,\n reallocations: 0,\n rebuildsInFrame: () => 0,\n peakRebuildsPerSourcePerFrame: 0,\n },\n texturePool: {\n live: pool?.live ?? 0,\n created: pool?.created ?? 0,\n destroyed: pool?.destroyed ?? 0,\n },\n pipelines: {\n renderPipelines: cache?.renderPipelines ?? 0,\n computePipelines: cache?.computePipelines ?? 0,\n },\n framesDrawn,\n deviceGenerations: generations,\n };\n },\n\n attachDevice(device, ownership) {\n host.attach(device, ownership ?? options.ownership ?? (options.device === device ? \"app\" : \"vitrea\"));\n },\n\n replaceDevice(device) {\n host.replaceDevice(device);\n },\n\n markWebGPUUnavailable(reason) {\n host.markUnavailable(reason);\n },\n\n registerBackdrop(provider) {\n if (providers.has(provider.id)) {\n throw rendererError(\n \"source-identity\",\n `Backdrop source \"${provider.id}\" is already registered. Unregister it first, or register the replacement under a new id.`,\n provider.id,\n );\n }\n providers.set(provider.id, provider);\n },\n\n unregisterBackdrop(sourceId) {\n placements.delete(sourceId);\n lastResolution.delete(sourceId);\n const provider = providers.get(sourceId);\n if (provider === undefined) return;\n provider.destroy();\n providers.delete(sourceId);\n store?.forget(sourceId);\n adaptation.delete(sourceId);\n lastReadbackAt.delete(sourceId);\n },\n\n backdrop(sourceId) {\n return providers.get(sourceId);\n },\n\n setBackdropPlacement(sourceId, placement) {\n if (samePlacement(placements.get(sourceId), placement)) return;\n if (placement === undefined) placements.delete(sourceId);\n else placements.set(sourceId, { ...placement });\n },\n\n backdropPlacement(sourceId) {\n return placements.get(sourceId);\n },\n\n setViewport(next) {\n const changed =\n next.widthCss !== viewport.widthCss ||\n next.heightCss !== viewport.heightCss ||\n next.devicePixelRatio !== viewport.devicePixelRatio;\n viewport = next;\n if (!changed) return;\n // A resize bumps the size epoch, which is what invalidates every dependent\n // allocation (§GPU device ownership) — group field textures included, since\n // their device extent is a function of the DPR.\n //\n // The bump alone, deliberately: `pool.acquire` destroys and reallocates a\n // stale-epoch entry on next use, so every allocation is replaced exactly\n // when it is next needed. Sweeping here instead destroyed the backdrop\n // chain and body textures *immediately*, and a static source rebuilds\n // nothing — so the very next frame bound two destroyed textures and lost\n // the whole plane's encoder to a validation error. Deferring costs one\n // frame's worth of superseded textures and nothing else.\n context?.pool.bumpSizeEpoch();\n },\n\n get viewport() {\n return viewport;\n },\n\n setGroup(input) {\n groups.set(input.groupId, { input });\n },\n\n removeGroup(groupId) {\n groups.delete(groupId);\n // Every plane, because a group's resources are per plane and one group can\n // have drawn on more than one (`groupResourceId`). Forgetting only the\n // plane drawn most recently would strand the other plane's set for the\n // life of the renderer.\n for (const plane of planesDrawn) {\n runner?.forget(groupResourceId(plane, groupId));\n silhouetteTone?.forget(groupResourceId(plane, groupId));\n hintedTones.delete(groupResourceId(plane, groupId));\n }\n },\n\n setAccessibility(policy) {\n accessibility = policy;\n },\n\n setMaterialProfile(patch) {\n material = withMaterialOverrides(DEFAULT_MATERIAL_PROFILE, patch);\n // The adaptation filters carry the old profile's tint ends, so they are\n // dropped rather than left to interpolate between two materials. Everything\n // else on the draw path reads the profile per frame, so the next frame\n // redraws with the new numbers on its own.\n adaptation.clear();\n },\n\n get materialProfile() {\n return material;\n },\n\n setTargets(next) {\n targets = {\n optics: next.optics,\n ...(next.highlight === undefined ? {} : { highlight: next.highlight }),\n format: next.format ?? OUTPUT_TEXTURE_FORMAT,\n plane: next.plane ?? \"\",\n };\n },\n\n drawFrame(args) {\n const { context: gpu, store: pyramids, runner: passes } = ensureContext();\n targets = {\n optics: args.optics,\n ...(args.highlight === undefined ? {} : { highlight: args.highlight }),\n format: args.format ?? OUTPUT_TEXTURE_FORMAT,\n plane: args.plane ?? \"\",\n };\n\n pyramids.beginFrame(args.frame.id);\n pyramids.setTimeline(args.timing);\n passes.setTimeline(args.timing);\n\n const encoder = gpu.device.createCommandEncoder({\n label: `vitrea:frame:${args.frame.id}`,\n });\n\n let result: DrawFrameResult;\n try {\n const rebuilt = runRebuilds(encoder, rebuildRequests(args.rebuild), args.frame.timeMs);\n pendingRebuilds = rebuilt.built;\n recordUnbuilt(args.frame.id, rebuilt.unbuilt);\n\n if (args.clear !== false) {\n passes.clearPass(encoder, args.optics);\n if (args.highlight !== undefined) passes.clearPass(encoder, args.highlight);\n }\n\n result = drawGroups(encoder, args.resolution, args.frame.timeMs);\n\n args.timing?.resolve(encoder);\n gpu.device.queue.submit([encoder.finish()]);\n // Success path only: starting a readback map for a copy that never\n // reached the queue is its own bug (see `requestStats`).\n pyramids.afterSubmit();\n silhouetteTone?.afterSubmit();\n } finally {\n // Owed whether or not the frame reached the queue. A throw anywhere above\n // leaves an acquired video held across the frame, and the next acquire\n // then fails the frame-protocol check — self-healing, but only after a\n // wasted frame and a decoder buffer nobody released.\n pyramids.releaseAcquired();\n silhouetteTone?.cancelQueued();\n }\n\n // Advance the adaptation filters by the real frame delta. The drivers are\n // frame-rate invariant by construction (§Motion), so a dropped frame and two\n // short ones produce the same value.\n const delta = lastFrameTimeMs === undefined ? 0 : args.frame.timeMs - lastFrameTimeMs;\n lastFrameTimeMs = args.frame.timeMs;\n if (delta > 0) {\n for (const state of adaptation.values()) state.advance(delta);\n }\n\n framesDrawn += 1;\n pyramids.setTimeline(undefined);\n passes.setTimeline(undefined);\n return result;\n },\n\n frameParticipant() {\n return {\n id: \"vitrea.renderer-webgpu\",\n\n write: (frameContext: FrameContextView) => {\n if (host.status.device === undefined || host.status.deviceHealth !== \"ok\") return;\n const { context: gpu, store: pyramids, runner: passes } = ensureContext();\n\n pyramids.beginFrame(frameContext.frame.id);\n pyramids.setTimeline(undefined);\n passes.setTimeline(undefined);\n\n pendingEncoder = gpu.device.createCommandEncoder({\n label: `vitrea:frame:${frameContext.frame.id}`,\n });\n // Core hands out the frame's rebuilds here and only here: one pass over\n // the dirty set per frame id, which is the §Core model invariant's other\n // half. This renderer's own ledger is what proves it kept its side.\n try {\n const rebuilt = runRebuilds(\n pendingEncoder,\n frameContext.consumeDirtyBackdropSources(),\n frameContext.frame.timeMs,\n );\n pendingRebuilds = rebuilt.built;\n recordUnbuilt(frameContext.frame.id, rebuilt.unbuilt);\n } catch (error) {\n // Nothing will submit this encoder, so the releases owed for what was\n // already acquired have to happen here rather than in `render`.\n pendingEncoder = undefined;\n pyramids.releaseAcquired();\n silhouetteTone?.cancelQueued();\n throw error;\n }\n },\n\n render: (frameContext: FrameContextView) => {\n const encoder = pendingEncoder;\n pendingEncoder = undefined;\n if (encoder === undefined || context === undefined) return;\n const passes = runner as PassRunner;\n const pyramids = store as PyramidStore;\n\n try {\n if (targets !== undefined) {\n passes.clearPass(encoder, targets.optics);\n if (targets.highlight !== undefined) passes.clearPass(encoder, targets.highlight);\n drawGroups(encoder, frameContext.resolution, frameContext.frame.timeMs);\n }\n\n context.device.queue.submit([encoder.finish()]);\n pyramids.afterSubmit();\n silhouetteTone?.afterSubmit();\n } finally {\n pyramids.releaseAcquired();\n silhouetteTone?.cancelQueued();\n }\n\n const delta =\n lastFrameTimeMs === undefined ? 0 : frameContext.frame.timeMs - lastFrameTimeMs;\n lastFrameTimeMs = frameContext.frame.timeMs;\n if (delta > 0) {\n for (const state of adaptation.values()) state.advance(delta);\n }\n framesDrawn += 1;\n },\n };\n },\n\n backdropToneAbscissae(groupId) {\n return [\n ...(silhouetteTone?.readings(groupId) ?? []),\n ...[...hintedTones.values()].filter((entry) => entry.groupId === groupId)\n .flatMap((entry) => entry.readings),\n ];\n },\n\n async collectAdaptation() {\n await silhouetteTone?.collect();\n if (store === undefined) return 0;\n const stats = await store.collectStats();\n for (const [sourceId, value] of stats) {\n const state = adaptationFor(sourceId);\n // The first observation jumps rather than filters: a 500 ms low-pass\n // starting from zero would fade the material in from black over half a\n // second on every page load.\n if (state.values.observed) state.observe(value);\n else state.reset(value);\n }\n return stats.size;\n },\n\n destroy() {\n for (const provider of providers.values()) provider.destroy();\n providers.clear();\n groups.clear();\n adaptation.clear();\n lastReadbackAt.clear();\n pendingUnbuilt = [];\n unbuiltFrameId = undefined;\n builtGeneration = undefined;\n dropContext();\n host.destroy();\n },\n };\n}\n"]}