@vitreajs/vitrea 0.5.0 → 0.7.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.
|
@@ -0,0 +1 @@
|
|
|
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/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/renderer.ts"],"names":["t","smoothstep","shape","outerShadowReachPx","level"],"mappings":"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","file":"dist-PY6GF4HA.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 /** Specular exponent and gain on the rim. */\n readonly specularPower: number;\n readonly specularGain: 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 /** Gaussian σ the silhouette is blurred by, CSS px. A `box-shadow` blur is 2σ. */\n readonly sigmaPx: 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 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 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 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 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 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 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 * **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 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 readonly backdropToneAnchorX: readonly [number, number, number];\n readonly backdropToneResponseThin: readonly [number, number, number];\n readonly backdropToneResponseThick: readonly [number, number, number];\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 /** 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 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 rimAlpha: 0.18,\n specularPower: 6,\n specularGain: 0.55,\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 specularPower: 8,\n specularGain: 0.45,\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 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 * 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 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 sweepBandRadians: 0.55,\n glowRadiusCss: 44,\n glowGain: 0.6,\n sweepGain: 0.85,\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 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 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 strongBorderRim?: Readonly<Partial<MaterialRim>>;\n readonly reducedTintAdaptation?: number;\n readonly tintShadeDark?: number;\n readonly tintShadeLight?: number;\n readonly tintShadeStrength?: number;\n readonly backdropToneMax?: number;\n readonly backdropToneLow?: number;\n readonly backdropToneHigh?: number;\n readonly backdropToneSizeBias?: number;\n readonly backdropToneAnchorX?: readonly [number, number, number];\n readonly backdropToneResponseThin?: readonly [number, number, number];\n readonly backdropToneResponseThick?: readonly [number, number, number];\n readonly backdropToneResponseStrength?: number;\n readonly outerShadow?: Readonly<Partial<MaterialOuterShadow>>;\n readonly lightDirection?: 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 * 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\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 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 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 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 backdropToneMax: patch.backdropToneMax ?? base.backdropToneMax,\n backdropToneLow: patch.backdropToneLow ?? base.backdropToneLow,\n backdropToneHigh: patch.backdropToneHigh ?? base.backdropToneHigh,\n backdropToneSizeBias: patch.backdropToneSizeBias ?? base.backdropToneSizeBias,\n backdropToneAnchorX: patch.backdropToneAnchorX ?? base.backdropToneAnchorX,\n backdropToneResponseThin: patch.backdropToneResponseThin ?? base.backdropToneResponseThin,\n backdropToneResponseThick: patch.backdropToneResponseThick ?? base.backdropToneResponseThick,\n backdropToneResponseStrength:\n patch.backdropToneResponseStrength ?? base.backdropToneResponseStrength,\n outerShadow: { ...base.outerShadow, ...patch.outerShadow },\n lightDirection: patch.lightDirection ?? base.lightDirection,\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 profile.increasedOcclusionLift,\n ),\n };\n\n if (policy.border === \"strong\") next = { ...next, ...profile.strongBorderRim };\n\n return next;\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 return [seed[0] * shade, seed[1] * shade, seed[2] * shade];\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): 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 const 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 // Interior slope: the Fritsch–Carlson harmonic mean, 0 across a sign change,\n // which is what keeps the curve monotone between monotone anchors.\n const m1 = d0 * d1 <= 0 ? 0 : (2 * d0 * d1) / (d0 + d1);\n const seg = x <= xs[1] ? 0 : 1;\n const h = seg === 0 ? h0 : h1;\n const t = (x - (seg === 0 ? xs[0] : xs[1])) / h;\n const y0 = seg === 0 ? ys[0] : ys[1];\n const y1 = seg === 0 ? ys[1] : ys[2];\n const s0 = seg === 0 ? d0 : m1;\n const s1 = seg === 0 ? m1 : d1;\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 );\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 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 */\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 return (\n floor\n + (1 - floor)\n * smoothstep(profile.sizeSpanMin, scatterSpanMaxAtScale(profile, devicePixelRatio), spanPx)\n );\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 return 0.5 * (1 + Math.tanh(0.7978845608028654 * (x + 0.044715 * x * x * x)));\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 */\nexport function outerShadowReachPx(shadow: MaterialOuterShadow, occlusion: number): 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(shadow.sigmaPx, 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 backdropUpload: (sourceId: string): string => `backdrop:${sourceId}:upload`,\n groupField: (groupId: string): string => `group:${groupId}:field`,\n groupAux: (groupId: string): string => `group:${groupId}:aux`,\n groupAux2: (groupId: string): string => `group:${groupId}:aux2`,\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 /** `lensStrength`, 0..1. Multiplies the resolved refraction scale. */\n readonly lensStrength: 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 lensStrength: 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 /**\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 * The material's tint and alpha for a group that samples NOTHING (W11a) — a\n * `css-backdrop` group whose blurred backdrop is a DOM proxy beneath the\n * canvas, or a `none` group over the page itself. Such a group's body is\n * not composited in the shader: the optics pass writes the material as a\n * premultiplied layer and the browser composites it over the DOM, in\n * encoded sRGB. A linear-light alpha written into that composite lands the\n * surface darker than the same material sampled on the GPU — the gap\n * `cssTintAlpha` closes for the CSS tier, at a declared reference level —\n * so the host, which owns that mapping, resolves the pair once and hands\n * the same numbers to both tiers. Linear light; the renderer folds the\n * accessibility policy over it exactly as over the profile's own. Ignored\n * wherever the group samples a backdrop; absent, the profile's pair is\n * written as it is (the golden harness, which has no host).\n */\n readonly unsampledMaterial?: { readonly tint: Rgb; readonly tintAlpha: number };\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 is that padding, written\n * as zero rather than left to whatever the buffer held.\n */\nexport const INSTANCE_FLOATS = 18;\nexport const INSTANCE_BYTES = INSTANCE_FLOATS * 4;\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\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 // Reference shapes are resolved (a child needs its parent's field) and then\n // dropped: they contribute no instance, no bounds, and no coverage.\n return group.surfaces\n .filter((surface) => surface.fieldReferenceOnly !== true)\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 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 data[o + 14] = Math.max(s.shape.channels.thickness, 0) * Math.min(1, Math.max(0, 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 data[o + 17] = 0;\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 _pad : f32, // 68 stride padding: vec2f aligns the struct to 8, so 72 is the next legal size\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@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};\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 return m;\n}\n\nstruct FieldOut {\n @location(0) field : vec4f,\n @location(1) aux : vec4f,\n @location(2) aux2 : 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 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 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 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. Reduced Motion sets `shimmer: \"none\"`, which the CPU turns\n * into a zero gain — the band is not drawn stationary, it is not drawn.\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), unused (w)\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\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.\nfn angle_delta(a : f32, b : f32) -> f32 {\n let raw = abs(a - b);\n return min(raw, TAU - raw);\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 if (hu.flags.z > 0.5) {\n field = textureSampleLevel(fieldTexture, fieldSampler, fieldUv, 0.0);\n aux = textureSampleLevel(auxTexture, 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 }\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 (hu.toneAdapt.w > 0.0) {\n let toneX = hu.toneLevel.x + 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(hu.toneAdapt.w, 0.0, 1.0) * (1.0 - toneT * toneT * (3.0 - 2.0 * toneT));\n }\n\n let intensity = clamp(sweep + press, 0.0, 1.0) * coverage * (1.0 - toneAdapt);\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, specularPower, specularGain\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), same layout\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};\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/// 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) -> 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 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 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}\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.\nfn outer_shadow_falloff(signedDistance : f32, sigma : f32) -> f32 {\n let x = -signedDistance / max(sigma, 1e-4);\n return 0.5 * (1.0 + tanh(0.7978845608028654 * (x + 0.044715 * x * x * x)));\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};\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 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 if (upsampled > 0.5) {\n shadowField = textureSampleLevel(fieldTexture, fieldSampler, shadowUv, 0.0);\n shadowAux = textureSampleLevel(auxTexture, 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 }\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 out.alpha = 1.0 - pow(1.0 - occ, 1.0 / 2.4);\n out.falloff = outer_shadow_falloff(shadowField.x + clampedOffCss - ou.shadow.z, ou.shadow.y);\n out.castSpanCss = shadowAux.z;\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.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 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 return v * (ou.shadowLift.x * rise * shadow.falloff);\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 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 } 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 }\n\n let d = field.x;\n let normal = field.yz;\n let coverage = field.w;\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 let lensThick = max(aux.x, 0.0);\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 let kDeep = scatterFloor + (1.0 - scatterFloor) * deepT * deepT * (3.0 - 2.0 * deepT);\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 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 kScatter = clamp(scatterFloor + ((1.0 - sharpShare) - scatterFloor) * fold, 0.0, 1.0);\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 let scatterLod = clamp(ou.size.w + log2(max(gainEff, 1e-4)), 0.0, ou.lens.w);\n\n var backdrop = vec3f(0.0);\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 let scatterSample = textureSampleLevel(backdropChain, backdropSampler, refractedUv, scatterLod);\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 let scatterColour = scatterSample.rgb / max(scatterSample.a, 1e-6);\n backdrop = mix(bodySample.rgb / max(bodySample.a, 1e-6), scatterColour, kScatter);\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 the whole axis stands\n * down where there is no backdrop at all rather than reading the zero vector as\n * a black backdrop and dissolving the surface into nothing.\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.flags.x > 0.5 && ou.toneAdapt.w > 0.0) {\n let toneX = ou.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(ou.toneAdapt.w, 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 * 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 (ou.flags.x > 0.5 && ou.toneAdapt.w > 0.0 && ou.toneRowThin.w > 0.0 &&\n sizedAlpha > 1e-3 && toneAdapt < 0.995) {\n let encodedInput = srgb_encode(ou.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);\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 * ou.toneAnchor.w) / (1.0 - toneAdapt);\n let neutralLuma = dot(neutral, vec3f(0.2126, 0.7152, 0.0722));\n let nominal = (1.0 - sizedAlpha) * ou.toneAnchor.w + sizedAlpha * neutralLuma;\n let shift = (preCollapse - nominal) / sizedAlpha * authority * ou.toneAdapt.w;\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) * ou.toneAnchor.w + sizedAlpha * solvedLuma;\n if (preCollapse > achieved + 1e-4 && solvedLuma > ou.toneAnchor.w + 1e-3) {\n let alphaTarget = clamp(\n (preCollapse - ou.toneAnchor.w) / (solvedLuma - ou.toneAnchor.w),\n sizedAlpha,\n 1.0,\n );\n solvedAlpha = mix(sizedAlpha, alphaTarget, authority * ou.toneAdapt.w);\n }\n }\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) + ou.toneColour.rgb * 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 var colour = mix(backdrop, adapted, adaptedAlpha);\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 if (ou.flags.x <= 0.5) {\n colour = adapted;\n bodyAlpha = adaptedAlpha;\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 if (aux.w > 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) * ou.toneColour.w;\n let grip = clamp(ou.seed.w, 0.0, 1.0) * clamp(ou.tone.z, 0.0, 1.0) * (1.0 - toneAdapt);\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 let layer = ou.seed.rgb * shade;\n let s = clamp(aux.w, 0.0, 1.0);\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 let shadowKeep = 1.0 - shadowProfile * shadowDepth * ou.light.w * present;\n let shadowedAlpha = 1.0 - shadowKeep * (1.0 - bodyAlpha);\n colour = colour * (shadowKeep * bodyAlpha / max(shadowedAlpha, 1e-6));\n bodyAlpha = shadowedAlpha;\n\n // Rim and specular from the gradient. The rim is unlit ambient edge brightness;\n // the specular term is the same edge lit from 'light.xy'.\n let rw = rim_weight(d, ou.rim.x);\n let facing = dot(normal, ou.light.xy);\n let spec = pow(clamp(facing, 0.0, 1.0), max(ou.rim.z, 1e-3)) * ou.rim.w;\n let rim = rw * (ou.rim.y + spec) * present;\n if (ou.flags.x > 0.5) {\n colour = colour + vec3f(rim);\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 let carried = clamp(bodyAlpha + rim, 0.0, 1.0);\n colour = min((colour * bodyAlpha + vec3f(rim)) / 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 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 let hi = pow((c + vec3f(0.055)) / 1.055, 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","/**\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\";\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 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/** 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 readonly groupId: 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 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\nexport interface OpticsPassArgs {\n readonly groupId: string;\n readonly target: GPUTextureView;\n readonly targetFormat: GPUTextureFormat;\n readonly rectDevice: DeviceRect;\n readonly fields: FieldTargets;\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 rimWidth: number;\n readonly rimAlpha: number;\n readonly specularPower: number;\n readonly specularGain: 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: readonly [number, number, number];\n readonly backdropToneResponseThin: readonly [number, number, number];\n readonly backdropToneResponseThick: readonly [number, number, number];\n /** The response law's per-profile authority (0 on dark profiles) — see\n * `MaterialProfile.backdropToneResponseStrength`. */\n readonly backdropToneResponseStrength: 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: { readonly chain: GPUTextureView; readonly body: GPUTextureView } | undefined;\n}\n\nexport interface HighlightPassArgs {\n readonly groupId: string;\n readonly target: GPUTextureView;\n readonly targetFormat: GPUTextureFormat;\n readonly rectDevice: DeviceRect;\n readonly fields: FieldTargets;\n readonly viewportDevice: readonly [number, number];\n readonly cssPerDevice: number;\n readonly sweep: number;\n readonly sweepBandRadians: number;\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 forget(groupId: string): void;\n destroy(): void;\n}\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 ],\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.groupId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.groupId}:field`,\n });\n const aux = pool.acquire(poolKey.groupAux(args.groupId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.groupId}:aux`,\n });\n const aux2 = pool.acquire(poolKey.groupAux2(args.groupId), {\n width,\n height,\n format: WORKING_TEXTURE_FORMAT,\n usage: fieldUsage(),\n label: `vitrea:group:${args.groupId}:aux2`,\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.groupId}`, 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.groupId);\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.groupId}`,\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 });\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 width,\n height,\n upsampled: width !== rectWidth || height !== rectHeight,\n };\n },\n\n opticsPass(encoder, args) {\n const slot = uniformSlot(`optics:${args.groupId}`, 96);\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 d[30] = args.specularPower;\n d[31] = args.specularGain;\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 d[71] = 0;\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 slot.write();\n\n const chain = args.backdrop?.chain ?? placeholderView;\n const body = args.backdrop?.body ?? placeholderView;\n\n const pipeline = opticsPipeline(args.targetFormat);\n const pass = encoder.beginRenderPass({\n label: `vitrea:pass:optics:${args.groupId}`,\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 ],\n }),\n );\n pass.draw(3);\n pass.end();\n },\n\n highlightPass(encoder, args) {\n const slot = uniformSlot(`highlight:${args.groupId}`, 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] = 0;\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.groupId}`,\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 ],\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(groupId) {\n pool.release(poolKey.groupField(groupId));\n pool.release(poolKey.groupAux(groupId));\n pool.release(poolKey.groupAux2(groupId));\n storages.get(groupId)?.destroy();\n storages.delete(groupId);\n for (const key of [`field:${groupId}`, `optics:${groupId}`, `highlight:${groupId}`]) {\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 * 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 * 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 { bodyBlurPlan, planPyramid, type PyramidPlan, type ResolutionPolicyView } 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 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\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 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 */\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\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 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 ): PyramidResources {\n const existing = resources.get(sourceId);\n const bodyWidth = (plan.levels[bodyLevel] ?? plan.levels[0] as { width: number; height: number }).width;\n const bodyHeight = (plan.levels[bodyLevel] ?? plan.levels[0] as { width: number; height: number }).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 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 (existing === undefined || existing.chain !== chain || existing.body !== body) {\n reallocations += 1;\n }\n\n const next: PyramidResources = {\n sourceId,\n plan,\n chain,\n body,\n stats,\n sizeEpoch,\n builtEpoch,\n bodySigmaTexels,\n texelsPerCss: density.texelsPerCss,\n sourceWidth: density.sourceWidth,\n sourceHeight: density.sourceHeight,\n bodySigmaCss,\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 function runBodyBlur(\n encoder: GPUCommandEncoder,\n sourceId: string,\n plan: PyramidPlan,\n chain: GPUTexture,\n body: 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 scratch = pool.acquire(poolKey.backdropBodyScratch(sourceId), {\n width: size.width,\n height: size.height,\n format: WORKING_TEXTURE_FORMAT,\n usage: chainUsage(),\n label: `vitrea:pyramid:${sourceId}:body-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: body, source: scratch.createView(), dir: [0, 1], tag: \"v\" },\n ];\n\n for (const stage of stages) {\n const slot = uniformSlot(`body:${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:body-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 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 );\n\n runImport(encoder, request.sourceId, frame, target.chain);\n runChain(encoder, request.sourceId, plan, target.chain);\n runBodyBlur(\n encoder,\n request.sourceId,\n plan,\n target.chain,\n target.body,\n bodyPlan.level,\n bodyPlan.residualSigmaTexels,\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 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","/**\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 } 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 groupFieldRect,\n packInstances,\n resolveSurfaces,\n snapRectToDevicePixels,\n type ResolvedSurface,\n} from \"./instances\";\nimport {\n accessibilityRefractionCap,\n adaptationStrength,\n backdropToneSizeBiasUnderPolicy,\n backdropToneUnderPolicy,\n DEFAULT_MATERIAL_PROFILE,\n effectiveRefraction,\n NOMINAL_MATERIAL_POLICY,\n opticsUnderPolicy,\n outerShadowOcclusionAt,\n outerShadowReachPx,\n outerShadowThinOcclusion,\n outerShadowUnderPolicy,\n scatterFloorAtScale,\n scatterGainAtScale,\n scatterGainFarAtScale,\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 { createPassRunner, type DeviceRect, type PassRunner } from \"./passes\";\nimport { createPyramidStore, type PyramidResources, type PyramidStore } 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\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 /** Targets for the participant path, where core drives the phases. */\n setTargets(targets: { readonly optics: GPUTextureView; readonly highlight?: GPUTextureView; readonly format?: GPUTextureFormat }): void;\n frameParticipant(): FrameParticipantView;\n\n /** Resolve any completed analysis readbacks into the adaptation drivers. */\n collectAdaptation(): Promise<number>;\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\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 framesDrawn = 0;\n let generations = 0;\n let lastFrameTimeMs: number | undefined;\n let targets:\n | { optics: GPUTextureView; highlight?: GPUTextureView; format: GPUTextureFormat }\n | undefined;\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 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 // 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 if (sameDensity && sameSigma) 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 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 const groupTintSeed = (input: GroupRenderInput): readonly [number, number, number] | undefined =>\n input.surfaces.find(\n (surface) => surface.fieldReferenceOnly !== true && (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 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 ): 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\n for (const entry of groups.values()) {\n const input = entry.input;\n if (input.surfaces.length === 0) continue;\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 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 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 }\n const shadowReachPx = outerShadowReachPx(shadow, reachOcclusion);\n\n const snapped = snapRectToDevicePixels(\n groupFieldRect(surfaces, union, undefined, shadowReachPx),\n dpr,\n );\n const rectDevice: DeviceRect | undefined = clipFieldRectToCanvas(snapped, dpr, viewportDevice);\n if (rectDevice === undefined) continue;\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 fields = passes.fieldPass(encoder, {\n groupId: 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\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 /*\n * A group with no pyramid to sample writes its material as a layer the\n * browser composites (W11a; see `GroupRenderInput.unsampledMaterial`), so\n * where the host resolved the compositing-space pair it replaces the\n * profile's — before the policy fold, which then lands on it exactly as\n * the CSS tier's fold lands on the same numbers.\n */\n const nominalOptics = material.optics[variant];\n const optics = opticsUnderPolicy(\n pyramid === undefined && input.unsampledMaterial !== undefined\n ? {\n ...nominalOptics,\n tint: input.unsampledMaterial.tint,\n tintAlpha: input.unsampledMaterial.tintAlpha,\n }\n : nominalOptics,\n policy,\n material,\n );\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\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 groupId: input.groupId,\n target: active.optics,\n targetFormat: active.format,\n rectDevice,\n fields,\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 rimWidth: optics.rimWidth,\n rimAlpha: optics.rimAlpha,\n specularPower: optics.specularPower,\n specularGain: optics.specularGain,\n lightDirection: material.lightDirection,\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 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 // The lift needs a chain to copy; without one there is nothing to add,\n // and `hasBackdrop` in the shader says the same thing a second time.\n pyramid === undefined || policy.glass === \"none\" ? 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 },\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 groupId: 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 viewportDevice,\n cssPerDevice,\n sweep: lead.channels.sweep,\n sweepBandRadians: material.sweepBandRadians,\n // Reduced Motion removes shimmer travel outright rather than freezing it.\n sweepGain: policy.glass === \"none\" ? 0 : material.sweepGain,\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 runner?.forget(groupId);\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 };\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 };\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);\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 } 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 }\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 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);\n }\n\n context.device.queue.submit([encoder.finish()]);\n pyramids.afterSubmit();\n } finally {\n pyramids.releaseAcquired();\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 async collectAdaptation() {\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"]}
|