vireglass 2.1.0 → 2.3.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.
Files changed (46) hide show
  1. package/README.md +41 -1
  2. package/dist/{chunk-3PGYF2NK.js → chunk-CTTZNZFV.js} +3 -3
  3. package/dist/{chunk-3PGYF2NK.js.map → chunk-CTTZNZFV.js.map} +1 -1
  4. package/dist/{chunk-FL5UZPY5.js → chunk-H5QTBF67.js} +4 -4
  5. package/dist/{chunk-FL5UZPY5.js.map → chunk-H5QTBF67.js.map} +1 -1
  6. package/dist/{chunk-TTOKBARR.js → chunk-MMPK6DCK.js} +10 -3
  7. package/dist/chunk-MMPK6DCK.js.map +1 -0
  8. package/dist/{chunk-BZC2WHCK.js → chunk-PM2SWCSF.js} +4 -4
  9. package/dist/{chunk-BZC2WHCK.js.map → chunk-PM2SWCSF.js.map} +1 -1
  10. package/dist/{chunk-P2ZOODXD.js → chunk-SLRPHDV7.js} +3 -3
  11. package/dist/{chunk-P2ZOODXD.js.map → chunk-SLRPHDV7.js.map} +1 -1
  12. package/dist/dom.cjs +48 -20
  13. package/dist/dom.cjs.map +1 -1
  14. package/dist/dom.d.cts +15 -3
  15. package/dist/dom.d.ts +15 -3
  16. package/dist/dom.js +44 -23
  17. package/dist/dom.js.map +1 -1
  18. package/dist/index.cjs +1 -2
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +4 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.js +5 -5
  23. package/dist/law.cjs +8 -1
  24. package/dist/law.cjs.map +1 -1
  25. package/dist/law.d.cts +7 -0
  26. package/dist/law.d.ts +7 -0
  27. package/dist/law.js +1 -1
  28. package/dist/reference.js +2 -2
  29. package/dist/web/index.cjs +262 -153
  30. package/dist/web/index.cjs.map +1 -1
  31. package/dist/web/index.d.cts +88 -2
  32. package/dist/web/index.d.ts +88 -2
  33. package/dist/web/index.js +257 -156
  34. package/dist/web/index.js.map +1 -1
  35. package/docs/law.md +2 -2
  36. package/package.json +13 -9
  37. package/src/dom/body.ts +24 -9
  38. package/src/dom/index.ts +44 -10
  39. package/src/dom/probe.ts +27 -3
  40. package/src/law.ts +7 -0
  41. package/src/targets/glsl.ts +4 -0
  42. package/src/web/gl.ts +57 -4
  43. package/src/web/gpu-timer.ts +111 -0
  44. package/src/web/index.ts +1 -0
  45. package/src/web/renderer.ts +305 -218
  46. package/dist/chunk-TTOKBARR.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/web/gl.ts","../../src/web/probe.ts","../../src/web/renderer.ts"],"names":["slot"],"mappings":"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","file":"index.js","sourcesContent":["// Low-level GL helpers for the pipeline: program compilation, textures, FBOs, the fullscreen\n// triangle. Knows nothing about VireGlass — a reusable layer on top of WebGL2.\n\n/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by\n * `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment\n * shader pulls its own coordinate from `gl_FragCoord`. */\nexport const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = `#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n`;\n\nexport function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error('vireglass/web: gl.createShader returned null');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) ?? '(no log)';\n gl.deleteShader(shader);\n throw new Error(`vireglass/web: shader failed to compile:\\n${log}`);\n }\n return shader;\n}\n\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram {\n const vertex = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragment = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n const program = gl.createProgram();\n if (!program) throw new Error('vireglass/web: gl.createProgram returned null');\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) ?? '(no log)';\n gl.deleteProgram(program);\n throw new Error(`vireglass/web: program failed to link:\\n${log}`);\n }\n return program;\n}\n\n/** Draws the fullscreen triangle with the current program. No attributes — the vertices are\n * baked into the shader, so even a VAO isn't needed. */\nexport function drawFullscreenTriangle(gl: WebGL2RenderingContext): void {\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nexport type TextureOptions = {\n width: number;\n height: number;\n /** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */\n internalFormat?: number;\n format?: number;\n type?: number;\n};\n\n/**\n * content/probe texture: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE. Skia's `.eval` is\n * bilinear by default — NEAREST would break the disc gather into pixel-stepped bands (spec §4).\n */\nexport function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture {\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web: gl.createTexture returned null');\n const internalFormat = options.internalFormat ?? gl.RGBA8;\n const format = options.format ?? gl.RGBA;\n const type = options.type ?? gl.UNSIGNED_BYTE;\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n options.width,\n options.height,\n 0,\n format,\n type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n return texture;\n}\n\nexport function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {\n const fbo = gl.createFramebuffer();\n if (!fbo) throw new Error('vireglass/web: gl.createFramebuffer returned null');\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new Error(`vireglass/web: FBO incomplete, status ${status}`);\n }\n return fbo;\n}\n\n/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */\nexport function bindTextureAt(\n gl: WebGL2RenderingContext,\n unit: number,\n texture: WebGLTexture,\n program: WebGLProgram,\n uniformName: string,\n): void {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n const loc = gl.getUniformLocation(program, uniformName);\n gl.uniform1i(loc, unit);\n}\n","// Backdrop lightness probe under the lens — the web counterpart to the native capture in\n// ImageReader (`GlassLensView.kt`); see the web-core design spec and its Phase 3 plan.\n//\n// Downsampling the scene into a 48×96 grid runs as a GL pass (sampling `content` in the\n// downsample program, see `renderer.ts`), while READING the result happens here, through a PBO\n// with `fenceSync`: a synchronous `readPixels` stalls the pipeline, and a naive port stutters\n// while dragging sliders.\n//\n// Lagging by a frame or two isn't a bug, it's part of the contract (per the Phase 3 plan): we\n// read whatever the GPU already finished by the previous frame, rather than waiting on the\n// current one.\n\nimport { bindTextureAt, createFramebuffer, createProgram, drawFullscreenTriangle } from './gl';\n\nexport const PROBE_GRID_WIDTH = 48;\nexport const PROBE_GRID_HEIGHT = 96;\n\n/** Stats for the lens rectangle from a single probe sample. `null` until the first ready frame\n * has come in — the shader falls back to `u_probeLuma = -1` in that case (see `lens-shader.ts`). */\nexport type ProbeStats = {\n luma: number;\n busy: number;\n lo: number;\n hi: number;\n slopeX: number;\n slopeY: number;\n r: number;\n g: number;\n b: number;\n};\n\nconst DOWNSAMPLE_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_contentSize;\nuniform vec2 u_gridSize;\n\n// Cell → content UV mapping. Does NOT correspond to the canvas's visible top/bottom — this is an\n// internal pass, its buffer is never displayed, only read back on the CPU with the same formula\n// (see rectStats below). It doesn't need to match the blit pass's orientation.\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_gridSize;\n vec3 sum = vec3(0.0);\n const int N = 5;\n vec2 block = u_contentSize / u_gridSize;\n vec2 origin = uv * u_contentSize;\n for (int y = 0; y < N; y++) {\n for (int x = 0; x < N; x++) {\n vec2 p = origin + (vec2(float(x), float(y)) + 0.5) * (block / float(N));\n sum += texture(u_content, p / u_contentSize).rgb;\n }\n }\n fragColor = vec4(sum / float(N * N), 1.0);\n}\n`;\n\ntype PboSlot = {\n buffer: WebGLBuffer;\n sync: WebGLSync | null;\n pending: boolean;\n};\n\nexport type ProbeRect = { centerX: number; centerY: number; halfWidth: number; halfHeight: number };\n\nexport type Probe = {\n /** Renders a downsample of the current `contentTexture` into its own FBO and advances the PBO\n * read pipeline. Returns stats for the lens rectangle — lagging by a frame or two, or `null`\n * until a reader is ready. */\n sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null;\n /** Stats for another rectangle from the ALREADY-captured grid — no new pass, no new read. */\n statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null;\n destroy(): void;\n};\n\n/** RGBA32F gives the probe sub-pixel averaging precision (spec §5: \"where the web has the edge\")\n * — without it, the sum of 25 eight-bit samples per cell gets requantized back to 8 bits, and a\n * near-black gradient slice bands right at this step. Without `EXT_color_buffer_float` we fall\n * back to RGBA8 — renders everywhere, just coarser. */\nfunction pickDownsampleFormat(\n gl: WebGL2RenderingContext,\n): { internalFormat: number; type: number; floatPrecision: boolean } {\n const hasFloat = gl.getExtension('EXT_color_buffer_float') !== null;\n return hasFloat\n ? { internalFormat: gl.RGBA32F, type: gl.FLOAT, floatPrecision: true }\n : { internalFormat: gl.RGBA8, type: gl.UNSIGNED_BYTE, floatPrecision: false };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Rectangle stats from the 48×96 buffer. Buffer row `r` is `(r+0.5)/H` by the same formula as in\n * `DOWNSAMPLE_FRAGMENT_SOURCE`; here that same formula is inverted, so the buffer's orientation\n * (up/down) doesn't matter — only symmetry between reading and writing does.\n */\ntype DownsampleBuffer = Float32Array | Uint8Array;\n\nfunction rectStats(\n buffer: DownsampleBuffer,\n floatPrecision: boolean,\n gridW: number,\n gridH: number,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n): ProbeStats | null {\n const x0 = rect.centerX - rect.halfWidth;\n const x1 = rect.centerX + rect.halfWidth;\n const y0 = rect.centerY - rect.halfHeight;\n const y1 = rect.centerY + rect.halfHeight;\n\n const lumas: number[] = [];\n const nx: number[] = [];\n const ny: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n\n const norm = floatPrecision ? 1 : 255;\n for (let row = 0; row < gridH; row++) {\n const cy = ((row + 0.5) / gridH) * contentHeight;\n if (cy < y0 || cy > y1) continue;\n for (let col = 0; col < gridW; col++) {\n const cx = ((col + 0.5) / gridW) * contentWidth;\n if (cx < x0 || cx > x1) continue;\n const i = (row * gridW + col) * 4;\n const r = buffer[i] / norm;\n const g = buffer[i + 1] / norm;\n const b = buffer[i + 2] / norm;\n lumas.push(luma(r, g, b));\n nx.push((cx - rect.centerX) / Math.max(rect.halfWidth, 1));\n ny.push((cy - rect.centerY) / Math.max(rect.halfHeight, 1));\n sr += r;\n sg += g;\n sb += b;\n }\n }\n const n = lumas.length;\n if (n === 0) return null;\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = (busy / n) * 2;\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n const slope = (xs: number[]) => {\n let mx = 0;\n for (const v of xs) mx += v;\n mx /= n;\n let sxx = 0;\n let sxl = 0;\n for (let i = 0; i < n; i++) {\n const dx = xs[i] - mx;\n sxx += dx * dx;\n sxl += dx * (lumas[i] - mean);\n }\n return sxx > 1e-6 ? sxl / sxx : 0;\n };\n\n return {\n luma: mean,\n busy: Math.min(busy, 1),\n lo: percentile(0.1),\n hi: percentile(0.9),\n slopeX: slope(nx),\n slopeY: slope(ny),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\nexport function createProbe(gl: WebGL2RenderingContext, vertexSource: string): Probe {\n const program = createProgram(gl, vertexSource, DOWNSAMPLE_FRAGMENT_SOURCE);\n const format = pickDownsampleFormat(gl);\n\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web/probe: gl.createTexture returned null');\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n format.internalFormat,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n 0,\n gl.RGBA,\n format.type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n const fbo = createFramebuffer(gl, texture);\n\n const byteSize = PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4 * (format.floatPrecision ? 4 : 1);\n const slots: PboSlot[] = [0, 1].map(() => {\n const buffer = gl.createBuffer();\n if (!buffer) throw new Error('vireglass/web/probe: gl.createBuffer returned null');\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);\n gl.bufferData(gl.PIXEL_PACK_BUFFER, byteSize, gl.STREAM_READ);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n return { buffer, sync: null, pending: false };\n });\n let cursor = 0;\n let latestRaw: DownsampleBuffer | null = null;\n\n const contentLoc = gl.getUniformLocation(program, 'u_content');\n const contentSizeLoc = gl.getUniformLocation(program, 'u_contentSize');\n const gridSizeLoc = gl.getUniformLocation(program, 'u_gridSize');\n\n function pollReady(slot: PboSlot): void {\n if (!slot.pending || !slot.sync) return;\n // The flag flushes the command queue, otherwise a fence placed after readPixels might never\n // fire at all. The wait itself is zero. WAIT_FAILED isn't \"ready\": without a separate branch\n // for it, execution fell through and read garbage out of the PBO.\n const status = gl.clientWaitSync(slot.sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0);\n if (status === gl.TIMEOUT_EXPIRED || status === gl.WAIT_FAILED) return;\n gl.deleteSync(slot.sync);\n slot.sync = null;\n slot.pending = false;\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n const out: DownsampleBuffer = format.floatPrecision\n ? new Float32Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4)\n : new Uint8Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4);\n gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, out);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n latestRaw = out;\n }\n\n function sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null {\n // Collect finished reads from PAST frames before requesting a new one.\n for (const slot of slots) pollReady(slot);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.useProgram(program);\n bindTextureAt(gl, 0, contentTexture, program, 'u_content');\n gl.uniform1i(contentLoc, 0);\n gl.uniform2f(contentSizeLoc, contentWidth, contentHeight);\n gl.uniform2f(gridSizeLoc, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.disable(gl.BLEND);\n drawFullscreenTriangle(gl);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n const slot = slots[cursor];\n cursor = (cursor + 1) % slots.length;\n if (!slot.pending) {\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n gl.readPixels(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT, gl.RGBA, format.type, 0);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n slot.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\n slot.pending = true;\n }\n\n return statsFor(contentWidth, contentHeight, rect);\n }\n\n // The downsample is one per frame, but a frame can have many elements: each needs stats for\n // ITS OWN rectangle out of the same grid, not its own pass and its own PBO read.\n function statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null {\n if (!latestRaw) return null;\n return rectStats(\n latestRaw,\n format.floatPrecision,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n contentWidth,\n contentHeight,\n rect,\n );\n }\n\n function destroy(): void {\n for (const slot of slots) {\n if (slot.sync) gl.deleteSync(slot.sync);\n gl.deleteBuffer(slot.buffer);\n }\n gl.deleteFramebuffer(fbo);\n gl.deleteTexture(texture);\n gl.deleteProgram(program);\n }\n\n return { sample, statsFor, destroy };\n}\n","// The web lab's WebGL2 pipeline (per the Phase 3 plan; web-core spec §5). Four passes, and the\n// ordering and layer split deliberately mirror Android — the lens and the surface are NOT\n// collapsed into one pass, otherwise the lab stops predicting the phone (there they're two\n// separate layers):\n//\n// 1. scene backdrop — rasterized into an offscreen 2D canvas (text and cover art are\n// easier there than in GL) and uploaded into the `content`\n// texture. This texture plays the role of the spec's FBO(scene):\n// later passes only SAMPLE it, never redraw it.\n// 2. blit backdrop to screen — `content` is drawn as the backing; without it the screen would\n// show only the element, and the material is compared against\n// exactly what's around it.\n// 3. downsample (`probe.ts`) — stats for the lens rectangle, see there.\n// 4. lens (`toGLSL(LENS_SHADER)`) — samples `content`, draws over the backdrop.\n// 5. surface (`toGLSL(SURFACE_SHADER)`) — bevel and highlight over the lens.\n//\n// UNITS. Everything is device-px, one coordinate space for the whole canvas (web-core spec\n// §4.2): `toLensProps` already multiplies by `density`; `toSurfaceUniforms` doesn't and\n// shouldn't (its contract is shared with Android), so its result gets run through\n// `toDeviceSurfaceUniforms`.\n//\n// SHARED CENTER. On Android the lens and the surface live in THEIR OWN local spaces (different\n// `lensPadDp`/`surfacePadDp` margins), and concentricity is a convention the component\n// maintains. Here both shaders get screen coordinates directly (`gl_FragCoord`), so the only way\n// to align them is to pass the exact SAME `u_center` in canvas pixels to both: the lens gets it\n// as-is (a native uniform), the surface gets it substituted in place of the adapter's own value\n// (which is only meaningful in its own local canvas, which doesn't exist here).\nimport {\n DYNAMIC_UNIFORMS,\n ICON_UNIFORMS,\n OVERLAY_UNIFORMS,\n toLensProps,\n toDeviceSurfaceUniforms,\n toSurfaceUniforms,\n type VireGlassAccent,\n type VireGlassMorph,\n type VireGlassTouch,\n} from '../adapters';\nimport { lensPadDp, shadowOpacity, surfacePadDp, type VireGlassGeometry } from '../geometry';\nimport { LENS_SHADER } from '../lens-shader';\nimport type { VireGlassDebugMode, VireGlassOptics } from '../material';\nimport { SURFACE_SHADER } from '../surface-shader';\nimport { toGLSL } from '../targets/glsl';\nimport {\n bindTextureAt,\n createProgram,\n createTexture,\n drawFullscreenTriangle,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n} from './gl';\nimport { createProbe, type ProbeStats } from './probe';\n\n/** The scene draws itself with an offset: the lenses in the frame stay put while the canvas\n * underneath them slides — only this way can you actually see what refraction does to whatever\n * passes under the element. Offset in device-px. */\nexport type VireGlassSceneDrawer = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n offsetX: number,\n offsetY: number,\n /** Pixels per dp — the same value used for elements. The canvas and the glass must live at the\n * same scale: as a fraction of canvas width, a cell on desktop came out five times larger than\n * on a phone, and an element of the same size looked completely different on the lab bench\n * than on a device. */\n density: number,\n) => void;\n\n/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */\nexport type VireGlassPiece = {\n optics: VireGlassOptics;\n geometry: VireGlassGeometry;\n /** Element center in CANVAS PIXELS (device-px). Shared between the lens and the surface. */\n centerX: number;\n centerY: number;\n morph?: VireGlassMorph;\n /** Third shape of the same body: breaking the element into pieces uses two bridges. */\n morph2?: VireGlassMorph;\n /** Local finger response: touch point, drag, press, wave. */\n touch?: VireGlassTouch;\n /** Press response, 0…1 — the highlight blooms, the body thickens slightly. */\n press?: number;\n /** Element under the finger, 0…1 — a stronger highlight and rim light. */\n active?: number;\n /** Played fraction, 0…1: an active state expressed as a field. Omitted means no progress. */\n progress?: number;\n /** Whether to draw the icon from the frame's shared mask on this element (see `iconMask` in the frame options). */\n icon?: boolean;\n /** Whether to draw the frame's colored layer on this element (see `colorLayer`). */\n overlay?: boolean;\n /** Icon color at rest and in the active state, RGBA 0…1. */\n inkIdle?: readonly number[];\n inkActive?: readonly number[];\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the element appearing as the lens builds up (M 2:55). */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n /** Tint for the primary action — colored glass, not a fill. */\n accent?: VireGlassAccent;\n};\n\nexport type VireGlassRenderOptions = {\n /** `devicePixelRatio` — passed as an argument rather than read globally, so the renderer stays\n * testable and isn't tied to a specific window. */\n density: number;\n debug: VireGlassDebugMode;\n pieces: readonly VireGlassPiece[];\n scene: VireGlassSceneDrawer;\n /** Canvas offset under stationary elements, device-px. */\n offsetX?: number;\n offsetY?: number;\n /**\n * Ink mask the size of the canvas, screen coordinates, read from the GREEN channel. White on\n * BLACK: antialiasing has to live in color, not alpha, otherwise green holds at one all the way\n * to the edge inside a stroke and the icon's edges tear.\n *\n * The mask does NOT carry and must not carry a calm backing under the ink: that's a property of\n * the material itself (`legibility`), the same across the whole element. While the app used to\n * supply that backing, one element had it and another didn't, with nothing to explain the\n * difference.\n */\n iconMask?: TexImageSource | null;\n /**\n * App-colored layer the size of the canvas, screen coordinates: cover art, a thumbnail —\n * anything the app puts ON the glass in color. Separate from the ink mask, because that one\n * carries a single channel colored by polarity, while this one has its own color.\n *\n * Drawn INSIDE the material, at the same coordinate as the ink: only this way does the\n * surface's deformation carry them together. As a separate layer on top of the glass, text used\n * to shake on press while the cover art stayed put.\n */\n colorLayer?: TexImageSource | null;\n};\n\nexport type VireGlassRenderResult = {\n /** One backdrop sample per element, in the same order as `pieces`. */\n probes: readonly (ProbeStats | null)[];\n};\n\nexport type VireGlassRenderer = {\n resize(widthPx: number, heightPx: number): void;\n render(options: VireGlassRenderOptions): VireGlassRenderResult;\n destroy(): void;\n};\n\nconst BLIT_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_resolution;\nvoid main() {\n // The same Y flip the transpiler does for the lens/surface (targets/glsl.ts): content is\n // uploaded from the 2D canvas WITHOUT flipping, so its V=0 is the scene's top row. This keeps\n // the same order here, otherwise the backdrop and what the lens refracts through it drift\n // apart vertically.\n vec2 uv = gl_FragCoord.xy / u_resolution;\n uv.y = 1.0 - uv.y;\n fragColor = texture(u_content, uv);\n}\n`;\n\ntype UniformValue = number | readonly number[];\n\nfunction locationCache(gl: WebGL2RenderingContext, program: WebGLProgram) {\n const cache = new Map<string, WebGLUniformLocation | null>();\n return (name: string): WebGLUniformLocation | null => {\n let loc = cache.get(name);\n if (loc === undefined) {\n loc = gl.getUniformLocation(program, name);\n cache.set(name, loc);\n }\n return loc;\n };\n}\n\nfunction setUniform(\n gl: WebGL2RenderingContext,\n loc: WebGLUniformLocation | null,\n value: UniformValue,\n): void {\n if (!loc) return;\n if (typeof value === 'number') {\n gl.uniform1f(loc, value);\n return;\n }\n switch (value.length) {\n case 1:\n gl.uniform1f(loc, value[0]);\n break;\n case 2:\n gl.uniform2f(loc, value[0], value[1]);\n break;\n case 3:\n gl.uniform3f(loc, value[0], value[1], value[2]);\n break;\n case 4:\n gl.uniform4f(loc, value[0], value[1], value[2], value[3]);\n break;\n default:\n throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);\n }\n}\n\n/** The material arrives as ONE channel (web-core spec §4, \"Uniform contract\"): name/size/value\n * as three parallel arrays — exactly the layout that used to get lost with Android Props. */\nfunction applyChannel(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n names: readonly string[],\n sizes: readonly number[],\n values: readonly number[],\n): void {\n let cursor = 0;\n for (let i = 0; i < names.length; i += 1) {\n const size = sizes[i];\n setUniform(gl, get(names[i]), values.slice(cursor, cursor + size));\n cursor += size;\n }\n}\n\nfunction applyObject(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n values: Record<string, UniformValue>,\n): void {\n for (const name of Object.keys(values)) setUniform(gl, get(name), values[name]);\n}\n\nexport function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer {\n const context = canvas.getContext('webgl2', {\n preserveDrawingBuffer: true,\n alpha: false,\n antialias: false,\n });\n if (!context) throw new Error('vireglass/web: WebGL2 unavailable');\n // Explicit non-nullable typing — otherwise the `!context` narrowing doesn't survive the\n // closures of the nested `function resize/render/destroy` below, and tsc goes back to treating\n // `gl` as `WebGL2RenderingContext | null`.\n const gl: WebGL2RenderingContext = context;\n\n const blitProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, BLIT_FRAGMENT_SOURCE);\n const lensProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, toGLSL(LENS_SHADER));\n const surfaceProgram = createProgram(\n gl,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n toGLSL(SURFACE_SHADER),\n );\n const probe = createProbe(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE);\n\n const blitLoc = locationCache(gl, blitProgram);\n const lensLoc = locationCache(gl, lensProgram);\n const surfaceLoc = locationCache(gl, surfaceProgram);\n\n let width = canvas.width;\n let height = canvas.height;\n\n let sceneCanvas = document.createElement('canvas');\n let sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n // Smoothed backdrop estimate per element: keyed by its position in the pieces list.\n const settled = new Map<number, ProbeStats>();\n /** Fraction of the new sample per frame. Same magnitude as SETTLE on Android. */\n const SETTLE = 0.12;\n\n function settleStats(index: number, fresh: ProbeStats): ProbeStats {\n const prev = settled.get(index);\n if (!prev) {\n settled.set(index, fresh);\n return fresh;\n }\n const mix = (a: number, b: number) => a + (b - a) * SETTLE;\n const next: ProbeStats = {\n luma: mix(prev.luma, fresh.luma),\n busy: mix(prev.busy, fresh.busy),\n lo: mix(prev.lo, fresh.lo),\n hi: mix(prev.hi, fresh.hi),\n slopeX: mix(prev.slopeX, fresh.slopeX),\n slopeY: mix(prev.slopeY, fresh.slopeY),\n r: mix(prev.r, fresh.r),\n g: mix(prev.g, fresh.g),\n b: mix(prev.b, fresh.b),\n };\n settled.set(index, next);\n return next;\n }\n\n let contentTexture = createTexture(gl, {\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n\n // The icon mask is ONE per frame, the size of the canvas. The shader samples it at the pixel's\n // screen coordinate (`u_center + p` is exactly `xy`), so each element's icon is simply drawn\n // into the mask at its own spot: no separate texture per button is needed here.\n const iconTexture = createTexture(gl, { width: 1, height: 1 });\n const colorTexture = createTexture(gl, { width: 1, height: 1 });\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n 1,\n 1,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n new Uint8Array([0, 0, 0, 0]),\n );\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n function resize(widthPx: number, heightPx: number): void {\n width = Math.max(1, Math.round(widthPx));\n height = Math.max(1, Math.round(heightPx));\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n\n sceneCanvas = document.createElement('canvas');\n sceneCanvas.width = width;\n sceneCanvas.height = height;\n sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n gl.deleteTexture(contentTexture);\n contentTexture = createTexture(gl, { width, height });\n }\n\n function render(options: VireGlassRenderOptions): VireGlassRenderResult {\n if (!sceneCtx) throw new Error('vireglass/web: renderer not initialized (resize was never called)');\n\n // 1. Scene backdrop: a 2D canvas is easier for text and \"cover art\" (task, item 3), and the\n // texture itself plays the role of the plan's FBO(scene) — everything after this only reads\n // it.\n sceneCtx.clearRect(0, 0, width, height);\n options.scene(sceneCtx, width, height, options.offsetX ?? 0, options.offsetY ?? 0, options.density);\n gl.bindTexture(gl.TEXTURE_2D, contentTexture);\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, sceneCanvas);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n if (options.colorLayer) {\n gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);\n }\n if (options.iconMask) {\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n // 2. Backdrop to screen — the backing the element is seen against.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.useProgram(blitProgram);\n bindTextureAt(gl, 0, contentTexture, blitProgram, 'u_content');\n setUniform(gl, blitLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n\n const probes: (ProbeStats | null)[] = [];\n\n for (let index = 0; index < options.pieces.length; index += 1) {\n const piece = options.pieces[index];\n\n // 3. Downsample + stats for the rectangle of VISIBLE glass (no lens/surface margins — the\n // same `glassWidth`/`glassHeight` that go into toLensProps). Only the first element\n // captures the grid: it's shared for the frame, the rest just need their own rectangle out\n // of it.\n const halfWidth = (piece.geometry.width * options.density) / 2;\n const halfHeight = (piece.geometry.height * options.density) / 2;\n const rect = {\n centerX: piece.centerX,\n centerY: piece.centerY,\n halfWidth,\n halfHeight,\n };\n const fresh =\n index === 0\n ? probe.sample(contentTexture, width, height, rect)\n : probe.statsFor(width, height, rect);\n // The backdrop estimate eases toward the new value instead of jumping to it. On Android\n // the native view does this (`GlassLensView.kt`, a per-frame SETTLE); nobody did it on the\n // web: under a moving canvas, body density used to jerk with the instantaneous sample, and\n // on screen that read as lighting artifacts.\n const stats = fresh ? settleStats(index, fresh) : null;\n probes.push(stats);\n // Restore the viewport and the content texture binding — the probe pass reuses TEXTURE0\n // and its own FBO, unbinds them itself, but does change the viewport.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n\n gl.enable(gl.BLEND);\n // Premultiplied-over: both the lens and the surface emit premultiplied alpha (see `return\n // half4(half3(...) * alpha, alpha)` in both shaders).\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n // Both passes draw a fullscreen triangle, but the element covers only a small part of the\n // frame: without scissoring, a row of samples multiplies cost by the number of elements (on\n // a headless software renderer this pushed a frame into seconds). Margin is added on both\n // sides — the shadow, bevel and light gathering all reach past the element's own bounds.\n // The morph drop travels past the element's bounds — its travel is part of the margin,\n // otherwise scissoring would cut off the tail right where it matters.\n const reachOf = (m?: VireGlassMorph) =>\n m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;\n const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));\n // Field deformation pushes the element's edge past its own bounds — drag, wave amplitude\n // and growth on press. Without this term, scissoring cuts off exactly the part being\n // dragged toward.\n const touchReach = piece.touch\n ? Math.hypot(piece.touch.pullX, piece.touch.pullY) +\n piece.touch.waveAmp * 2 +\n Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press\n : 0;\n const padPx =\n (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) *\n options.density;\n const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));\n const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));\n const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));\n const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));\n gl.enable(gl.SCISSOR_TEST);\n gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));\n\n // 4. Lens.\n gl.useProgram(lensProgram);\n bindTextureAt(gl, 0, contentTexture, lensProgram, 'content');\n setUniform(gl, lensLoc('u_contentSize'), [width, height]);\n setUniform(gl, lensLoc('u_resolution'), [width, height]);\n setUniform(gl, lensLoc('u_center'), [piece.centerX, piece.centerY]);\n // There's no local-view margin here (one shared coordinate space) — on Android `u_reach`\n // capped adaptive-blur gathering at the edge of the lens view's PADDING; there's no such\n // boundary here, so the value is chosen deliberately larger than any real gather radius, so\n // the `reach - length(p)` condition never triggers before `u_contentMin/Max` does.\n setUniform(gl, lensLoc('u_reach'), Math.max(width, height));\n setUniform(gl, lensLoc('u_contentMin'), [1, 1]);\n setUniform(gl, lensLoc('u_contentMax'), [width - 1, height - 1]);\n if (stats) {\n setUniform(gl, lensLoc('u_probeLuma'), stats.luma);\n setUniform(gl, lensLoc('u_probeBusy'), stats.busy);\n setUniform(gl, lensLoc('u_probeRange'), [stats.lo, stats.hi]);\n setUniform(gl, lensLoc('u_probeSlope'), [stats.slopeX, stats.slopeY]);\n setUniform(gl, lensLoc('u_probe'), [stats.r, stats.g, stats.b]);\n } else {\n // The probe hasn't reported yet (the first frame or two) — the -1 sentinel keeps the\n // shader on its own point samples (see the comment in `lens-shader.ts`).\n setUniform(gl, lensLoc('u_probeLuma'), -1);\n }\n const lens = toLensProps(piece.optics, piece.geometry, options.density, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n touch: piece.touch,\n progress: piece.progress,\n light: piece.light,\n appear: piece.appear,\n accent: piece.accent,\n });\n applyChannel(gl, lensLoc, lens.uniformNames, lens.uniformSizes, lens.uniformValues);\n drawFullscreenTriangle(gl);\n\n // 5. Surface — shares its center with the lens (see the comment at the top of this file).\n // `toSurfaceUniforms`'s contract is dp, shared with Android; the core converts it to pixels.\n gl.useProgram(surfaceProgram);\n const rawSurface = toSurfaceUniforms(piece.optics, piece.geometry, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n bodyInLens: true,\n touch: piece.touch,\n progress: piece.progress,\n // The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives\n // in the core: while it lived here, Android didn't have it at all.\n shadow: stats ? shadowOpacity(stats.busy) : 1,\n // The probe has already computed the ambient color — the shadow gets it for free. Taken\n // as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the\n // steps the smoothing was written to remove.\n ambient: stats ? ([stats.r, stats.g, stats.b] as const) : undefined,\n appear: piece.appear,\n lift: piece.lift,\n });\n // The dp → device pixel conversion lives in the core (`toDeviceSurfaceUniforms`): one list\n // of lengths for every field, so a new field can't be forgotten here by oversight.\n applyObject(gl, surfaceLoc, {\n ...toDeviceSurfaceUniforms(rawSurface, options.density),\n u_center: [piece.centerX, piece.centerY],\n });\n // What's worklet dynamics on Android (press, active, tilt) arrives here as fields on the element.\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);\n const hasIcon = Boolean(piece.icon && options.iconMask);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);\n // Scale 1: the coordinate is already in screen space, the sampler itself normalizes by size.\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);\n bindTextureAt(gl, 1, iconTexture, surfaceProgram, 'u_icon');\n setUniform(gl, surfaceLoc('u_iconSize'), hasIcon ? [width, height] : [1, 1]);\n const hasColor = Boolean(piece.overlay && options.colorLayer);\n setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);\n bindTextureAt(gl, 2, colorTexture, surfaceProgram, 'u_overlay');\n setUniform(gl, surfaceLoc('u_overlaySize'), hasColor ? [width, height] : [1, 1]);\n setUniform(gl, surfaceLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n }\n gl.disable(gl.SCISSOR_TEST);\n\n return { probes };\n }\n\n function destroy(): void {\n probe.destroy();\n gl.deleteProgram(blitProgram);\n gl.deleteProgram(lensProgram);\n gl.deleteProgram(surfaceProgram);\n gl.deleteTexture(contentTexture);\n gl.deleteTexture(iconTexture);\n gl.deleteTexture(colorTexture);\n }\n\n return { resize, render, destroy };\n}\n"]}
1
+ {"version":3,"sources":["../../src/web/gl.ts","../../src/web/gpu-timer.ts","../../src/web/probe.ts","../../src/web/renderer.ts"],"names":["slot"],"mappings":"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","file":"index.js","sourcesContent":["// Low-level GL helpers for the pipeline: program compilation, textures, FBOs, the fullscreen\n// triangle. Knows nothing about VireGlass — a reusable layer on top of WebGL2.\n\n/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by\n * `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment\n * shader pulls its own coordinate from `gl_FragCoord`. */\nexport const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = `#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n`;\n\nexport function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error('vireglass/web: gl.createShader returned null');\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader) ?? '(no log)';\n gl.deleteShader(shader);\n throw new Error(`vireglass/web: shader failed to compile:\\n${log}`);\n }\n return shader;\n}\n\nexport function createProgram(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n): WebGLProgram {\n const vertex = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragment = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n const program = gl.createProgram();\n if (!program) throw new Error('vireglass/web: gl.createProgram returned null');\n gl.attachShader(program, vertex);\n gl.attachShader(program, fragment);\n gl.linkProgram(program);\n gl.deleteShader(vertex);\n gl.deleteShader(fragment);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(program) ?? '(no log)';\n gl.deleteProgram(program);\n throw new Error(`vireglass/web: program failed to link:\\n${log}`);\n }\n return program;\n}\n\n/** Draws the fullscreen triangle with the current program. No attributes — the vertices are\n * baked into the shader, so even a VAO isn't needed. */\nexport function drawFullscreenTriangle(gl: WebGL2RenderingContext): void {\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n}\n\nexport type TextureOptions = {\n width: number;\n height: number;\n /** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */\n internalFormat?: number;\n format?: number;\n type?: number;\n /** CLAMP_TO_EDGE by default. A simulation with a periodic domain (a tiling pattern, a torus)\n * wants REPEAT on its own textures instead — applied to both S and T, there's no case here\n * that wants them to differ. */\n wrap?: number;\n};\n\n/**\n * General-purpose texture allocator: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE by default.\n * Used throughout `web/` for `contentTexture` and the probe's downsample buffer, and public so a\n * `VireGlassBackdropPass` can build its own textures the same way. LINEAR rather than NEAREST\n * because Skia's `.eval` is bilinear by default — NEAREST would break the disc gather into\n * pixel-stepped bands (spec §4); a pass with different needs overrides `internalFormat`/`format`/\n * `type`/`wrap` directly.\n */\nexport function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture {\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web: gl.createTexture returned null');\n const internalFormat = options.internalFormat ?? gl.RGBA8;\n const format = options.format ?? gl.RGBA;\n const type = options.type ?? gl.UNSIGNED_BYTE;\n const wrap = options.wrap ?? gl.CLAMP_TO_EDGE;\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n options.width,\n options.height,\n 0,\n format,\n type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);\n gl.bindTexture(gl.TEXTURE_2D, null);\n return texture;\n}\n\nexport type UniformValue = number | readonly number[];\n\n/** One cache per program: `getUniformLocation` is a name lookup, and every piece re-sets every\n * uniform every frame. */\nexport function locationCache(gl: WebGL2RenderingContext, program: WebGLProgram) {\n const cache = new Map<string, WebGLUniformLocation | null>();\n return (name: string): WebGLUniformLocation | null => {\n let loc = cache.get(name);\n if (loc === undefined) {\n loc = gl.getUniformLocation(program, name);\n cache.set(name, loc);\n }\n return loc;\n };\n}\n\nexport function setUniform(\n gl: WebGL2RenderingContext,\n loc: WebGLUniformLocation | null,\n value: UniformValue,\n): void {\n if (!loc) return;\n if (typeof value === 'number') {\n gl.uniform1f(loc, value);\n return;\n }\n switch (value.length) {\n case 1:\n gl.uniform1f(loc, value[0]);\n break;\n case 2:\n gl.uniform2f(loc, value[0], value[1]);\n break;\n case 3:\n gl.uniform3f(loc, value[0], value[1], value[2]);\n break;\n case 4:\n gl.uniform4f(loc, value[0], value[1], value[2], value[3]);\n break;\n default:\n throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);\n }\n}\n\nexport function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer {\n const fbo = gl.createFramebuffer();\n if (!fbo) throw new Error('vireglass/web: gl.createFramebuffer returned null');\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n if (status !== gl.FRAMEBUFFER_COMPLETE) {\n throw new Error(`vireglass/web: FBO incomplete, status ${status}`);\n }\n return fbo;\n}\n\n/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */\nexport function bindTextureAt(\n gl: WebGL2RenderingContext,\n unit: number,\n texture: WebGLTexture,\n program: WebGLProgram,\n uniformName: string,\n): void {\n gl.activeTexture(gl.TEXTURE0 + unit);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n const loc = gl.getUniformLocation(program, uniformName);\n gl.uniform1i(loc, unit);\n}\n","// GPU timing for `VireGlassRenderer.getLastGpuMs()`, isolated from the renderer so it can be\n// unit-tested against a fake: `EXT_disjoint_timer_query_webgl2` is unavailable in the headless\n// Chromium the shader gates run in, so nothing in this repository otherwise exercises the ring\n// logic at all.\n\n/** The two tokens the extension adds; everything else the timer needs is core WebGL2. */\nexport type GpuTimerExtension = {\n readonly TIME_ELAPSED_EXT: number;\n readonly GPU_DISJOINT_EXT: number;\n};\n\n/** The slice of WebGL2 this module needs, kept narrow so a test can fake it without a real GL\n * context. A `WebGL2RenderingContext` satisfies this structurally — no cast needed at the call\n * site in `renderer.ts`. */\nexport type GpuTimerContext = {\n readonly QUERY_RESULT_AVAILABLE: number;\n readonly QUERY_RESULT: number;\n getExtension(name: string): unknown;\n createQuery(): WebGLQuery | null;\n deleteQuery(query: WebGLQuery): void;\n beginQuery(target: number, query: WebGLQuery): void;\n endQuery(target: number): void;\n getQueryParameter(query: WebGLQuery, pname: number): unknown;\n getParameter(pname: number): unknown;\n};\n\n/** Queries in flight at once. `EXT_disjoint_timer_query_webgl2` results arrive asynchronously,\n * often a few frames late, so one query per frame would mean starting a new query before the\n * previous one's result is back — undefined by spec. */\nexport const GPU_TIMER_RING_SIZE = 3;\n\ntype TimerSlot = { query: WebGLQuery; pending: boolean };\n\nexport type GpuTimer = {\n /** Runs `fn` as one timed sample. Always calls the matching `endQuery` even if `fn` throws, so\n * a frame that fails partway through (a broken backdrop pass, a validation error) never leaves\n * a query open for the next call to trip over. */\n time<T>(fn: () => T): T;\n /** `null` without the extension or while the ring hasn't produced a non-disjoint result yet. */\n getLastMs(): number | null;\n destroy(): void;\n};\n\n/** Missing the extension (most headless/CI setups, and every browser but Chromium-family in\n * practice) degrades every method here to a no-op / `null` — never an error. */\nexport function createGpuTimer(gl: GpuTimerContext): GpuTimer {\n const ext = gl.getExtension('EXT_disjoint_timer_query_webgl2') as GpuTimerExtension | null;\n const slots: TimerSlot[] = ext\n ? Array.from({ length: GPU_TIMER_RING_SIZE }, () => ({\n query: gl.createQuery() as WebGLQuery,\n pending: false,\n }))\n : [];\n let cursor = 0;\n let active: TimerSlot | null = null;\n let lastMs: number | null = null;\n\n function poll(): void {\n if (!ext) return;\n for (const slot of slots) {\n if (!slot.pending) continue;\n if (!gl.getQueryParameter(slot.query, gl.QUERY_RESULT_AVAILABLE)) continue;\n slot.pending = false;\n // A disjoint event (e.g. the GPU clock changed) invalidates every query since the last\n // check — the sample is discarded, not reported as zero or stale.\n if (gl.getParameter(ext.GPU_DISJOINT_EXT)) continue;\n const ns = gl.getQueryParameter(slot.query, gl.QUERY_RESULT) as number;\n lastMs = ns / 1e6;\n }\n }\n\n function begin(): void {\n active = null;\n if (!ext || slots.length === 0) return;\n poll();\n const slot = slots[cursor];\n // The ring hasn't caught up (this slot's previous result isn't back yet) — skip timing this\n // frame rather than reuse a query that's still in flight.\n if (slot.pending) return;\n gl.beginQuery(ext.TIME_ELAPSED_EXT, slot.query);\n active = slot;\n }\n\n function end(): void {\n if (!ext || !active) return;\n gl.endQuery(ext.TIME_ELAPSED_EXT);\n active.pending = true;\n cursor = (cursor + 1) % slots.length;\n active = null;\n }\n\n function time<T>(fn: () => T): T {\n begin();\n try {\n return fn();\n } finally {\n end();\n }\n }\n\n function getLastMs(): number | null {\n poll();\n return lastMs;\n }\n\n function destroy(): void {\n for (const slot of slots) gl.deleteQuery(slot.query);\n }\n\n return { time, getLastMs, destroy };\n}\n","// Backdrop lightness probe under the lens — the web counterpart to the native capture in\n// ImageReader (`GlassLensView.kt`); see the web-core design spec and its Phase 3 plan.\n//\n// Downsampling the scene into a 48×96 grid runs as a GL pass (sampling `content` in the\n// downsample program, see `renderer.ts`), while READING the result happens here, through a PBO\n// with `fenceSync`: a synchronous `readPixels` stalls the pipeline, and a naive port stutters\n// while dragging sliders.\n//\n// Lagging by a frame or two isn't a bug, it's part of the contract (per the Phase 3 plan): we\n// read whatever the GPU already finished by the previous frame, rather than waiting on the\n// current one.\n\nimport { bindTextureAt, createFramebuffer, createProgram, drawFullscreenTriangle } from './gl';\n\nexport const PROBE_GRID_WIDTH = 48;\nexport const PROBE_GRID_HEIGHT = 96;\n\n/** Stats for the lens rectangle from a single probe sample. `null` until the first ready frame\n * has come in — the shader falls back to `u_probeLuma = -1` in that case (see `lens-shader.ts`). */\nexport type ProbeStats = {\n luma: number;\n busy: number;\n lo: number;\n hi: number;\n slopeX: number;\n slopeY: number;\n r: number;\n g: number;\n b: number;\n};\n\nconst DOWNSAMPLE_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_contentSize;\nuniform vec2 u_gridSize;\n\n// Cell → content UV mapping. Does NOT correspond to the canvas's visible top/bottom — this is an\n// internal pass, its buffer is never displayed, only read back on the CPU with the same formula\n// (see rectStats below). It doesn't need to match the blit pass's orientation.\nvoid main() {\n vec2 uv = gl_FragCoord.xy / u_gridSize;\n vec3 sum = vec3(0.0);\n const int N = 5;\n vec2 block = u_contentSize / u_gridSize;\n vec2 origin = uv * u_contentSize;\n for (int y = 0; y < N; y++) {\n for (int x = 0; x < N; x++) {\n vec2 p = origin + (vec2(float(x), float(y)) + 0.5) * (block / float(N));\n sum += texture(u_content, p / u_contentSize).rgb;\n }\n }\n fragColor = vec4(sum / float(N * N), 1.0);\n}\n`;\n\ntype PboSlot = {\n buffer: WebGLBuffer;\n sync: WebGLSync | null;\n pending: boolean;\n};\n\nexport type ProbeRect = { centerX: number; centerY: number; halfWidth: number; halfHeight: number };\n\nexport type Probe = {\n /** Renders a downsample of the current `contentTexture` into its own FBO and advances the PBO\n * read pipeline. Returns stats for the lens rectangle — lagging by a frame or two, or `null`\n * until a reader is ready. */\n sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null;\n /** Stats for another rectangle from the ALREADY-captured grid — no new pass, no new read. */\n statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null;\n destroy(): void;\n};\n\n/** RGBA32F gives the probe sub-pixel averaging precision (spec §5: \"where the web has the edge\")\n * — without it, the sum of 25 eight-bit samples per cell gets requantized back to 8 bits, and a\n * near-black gradient slice bands right at this step. Without `EXT_color_buffer_float` we fall\n * back to RGBA8 — renders everywhere, just coarser. */\nfunction pickDownsampleFormat(\n gl: WebGL2RenderingContext,\n): { internalFormat: number; type: number; floatPrecision: boolean } {\n const hasFloat = gl.getExtension('EXT_color_buffer_float') !== null;\n return hasFloat\n ? { internalFormat: gl.RGBA32F, type: gl.FLOAT, floatPrecision: true }\n : { internalFormat: gl.RGBA8, type: gl.UNSIGNED_BYTE, floatPrecision: false };\n}\n\nfunction luma(r: number, g: number, b: number): number {\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n}\n\n/**\n * Rectangle stats from the 48×96 buffer. Buffer row `r` is `(r+0.5)/H` by the same formula as in\n * `DOWNSAMPLE_FRAGMENT_SOURCE`; here that same formula is inverted, so the buffer's orientation\n * (up/down) doesn't matter — only symmetry between reading and writing does.\n */\ntype DownsampleBuffer = Float32Array | Uint8Array;\n\nfunction rectStats(\n buffer: DownsampleBuffer,\n floatPrecision: boolean,\n gridW: number,\n gridH: number,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n): ProbeStats | null {\n const x0 = rect.centerX - rect.halfWidth;\n const x1 = rect.centerX + rect.halfWidth;\n const y0 = rect.centerY - rect.halfHeight;\n const y1 = rect.centerY + rect.halfHeight;\n\n const lumas: number[] = [];\n const nx: number[] = [];\n const ny: number[] = [];\n let sr = 0;\n let sg = 0;\n let sb = 0;\n\n const norm = floatPrecision ? 1 : 255;\n for (let row = 0; row < gridH; row++) {\n const cy = ((row + 0.5) / gridH) * contentHeight;\n if (cy < y0 || cy > y1) continue;\n for (let col = 0; col < gridW; col++) {\n const cx = ((col + 0.5) / gridW) * contentWidth;\n if (cx < x0 || cx > x1) continue;\n const i = (row * gridW + col) * 4;\n const r = buffer[i] / norm;\n const g = buffer[i + 1] / norm;\n const b = buffer[i + 2] / norm;\n lumas.push(luma(r, g, b));\n nx.push((cx - rect.centerX) / Math.max(rect.halfWidth, 1));\n ny.push((cy - rect.centerY) / Math.max(rect.halfHeight, 1));\n sr += r;\n sg += g;\n sb += b;\n }\n }\n const n = lumas.length;\n if (n === 0) return null;\n\n let mean = 0;\n for (const v of lumas) mean += v;\n mean /= n;\n\n let busy = 0;\n for (const v of lumas) busy += Math.abs(v - mean);\n busy = (busy / n) * 2;\n\n const sorted = [...lumas].sort((a, b) => a - b);\n const percentile = (p: number) => {\n const idx = p * (n - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);\n };\n\n const slope = (xs: number[]) => {\n let mx = 0;\n for (const v of xs) mx += v;\n mx /= n;\n let sxx = 0;\n let sxl = 0;\n for (let i = 0; i < n; i++) {\n const dx = xs[i] - mx;\n sxx += dx * dx;\n sxl += dx * (lumas[i] - mean);\n }\n return sxx > 1e-6 ? sxl / sxx : 0;\n };\n\n return {\n luma: mean,\n busy: Math.min(busy, 1),\n lo: percentile(0.1),\n hi: percentile(0.9),\n slopeX: slope(nx),\n slopeY: slope(ny),\n r: sr / n,\n g: sg / n,\n b: sb / n,\n };\n}\n\nexport function createProbe(gl: WebGL2RenderingContext, vertexSource: string): Probe {\n const program = createProgram(gl, vertexSource, DOWNSAMPLE_FRAGMENT_SOURCE);\n const format = pickDownsampleFormat(gl);\n\n const texture = gl.createTexture();\n if (!texture) throw new Error('vireglass/web/probe: gl.createTexture returned null');\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n format.internalFormat,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n 0,\n gl.RGBA,\n format.type,\n null,\n );\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.bindTexture(gl.TEXTURE_2D, null);\n const fbo = createFramebuffer(gl, texture);\n\n const byteSize = PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4 * (format.floatPrecision ? 4 : 1);\n const slots: PboSlot[] = [0, 1].map(() => {\n const buffer = gl.createBuffer();\n if (!buffer) throw new Error('vireglass/web/probe: gl.createBuffer returned null');\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, buffer);\n gl.bufferData(gl.PIXEL_PACK_BUFFER, byteSize, gl.STREAM_READ);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n return { buffer, sync: null, pending: false };\n });\n let cursor = 0;\n let latestRaw: DownsampleBuffer | null = null;\n\n const contentLoc = gl.getUniformLocation(program, 'u_content');\n const contentSizeLoc = gl.getUniformLocation(program, 'u_contentSize');\n const gridSizeLoc = gl.getUniformLocation(program, 'u_gridSize');\n\n function pollReady(slot: PboSlot): void {\n if (!slot.pending || !slot.sync) return;\n // The flag flushes the command queue, otherwise a fence placed after readPixels might never\n // fire at all. The wait itself is zero. WAIT_FAILED isn't \"ready\": without a separate branch\n // for it, execution fell through and read garbage out of the PBO.\n const status = gl.clientWaitSync(slot.sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0);\n if (status === gl.TIMEOUT_EXPIRED || status === gl.WAIT_FAILED) return;\n gl.deleteSync(slot.sync);\n slot.sync = null;\n slot.pending = false;\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n const out: DownsampleBuffer = format.floatPrecision\n ? new Float32Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4)\n : new Uint8Array(PROBE_GRID_WIDTH * PROBE_GRID_HEIGHT * 4);\n gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, out);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n latestRaw = out;\n }\n\n function sample(\n contentTexture: WebGLTexture,\n contentWidth: number,\n contentHeight: number,\n rect: ProbeRect,\n ): ProbeStats | null {\n // Collect finished reads from PAST frames before requesting a new one.\n for (const slot of slots) pollReady(slot);\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.useProgram(program);\n bindTextureAt(gl, 0, contentTexture, program, 'u_content');\n gl.uniform1i(contentLoc, 0);\n gl.uniform2f(contentSizeLoc, contentWidth, contentHeight);\n gl.uniform2f(gridSizeLoc, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT);\n gl.disable(gl.BLEND);\n drawFullscreenTriangle(gl);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n const slot = slots[cursor];\n cursor = (cursor + 1) % slots.length;\n if (!slot.pending) {\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, slot.buffer);\n gl.readPixels(0, 0, PROBE_GRID_WIDTH, PROBE_GRID_HEIGHT, gl.RGBA, format.type, 0);\n gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);\n gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n slot.sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);\n slot.pending = true;\n }\n\n return statsFor(contentWidth, contentHeight, rect);\n }\n\n // The downsample is one per frame, but a frame can have many elements: each needs stats for\n // ITS OWN rectangle out of the same grid, not its own pass and its own PBO read.\n function statsFor(contentWidth: number, contentHeight: number, rect: ProbeRect): ProbeStats | null {\n if (!latestRaw) return null;\n return rectStats(\n latestRaw,\n format.floatPrecision,\n PROBE_GRID_WIDTH,\n PROBE_GRID_HEIGHT,\n contentWidth,\n contentHeight,\n rect,\n );\n }\n\n function destroy(): void {\n for (const slot of slots) {\n if (slot.sync) gl.deleteSync(slot.sync);\n gl.deleteBuffer(slot.buffer);\n }\n gl.deleteFramebuffer(fbo);\n gl.deleteTexture(texture);\n gl.deleteProgram(program);\n }\n\n return { sample, statsFor, destroy };\n}\n","// The web lab's WebGL2 pipeline (per the Phase 3 plan; web-core spec §5). Four passes, and the\n// ordering and layer split deliberately mirror Android — the lens and the surface are NOT\n// collapsed into one pass, otherwise the lab stops predicting the phone (there they're two\n// separate layers):\n//\n// 1. backdrop — fills the `content` texture one of two ways: `scene` rasterizes\n// into an offscreen 2D canvas (text and cover art are easier there\n// than in GL) and uploads it via `texSubImage2D`; `backdrop` draws\n// straight into `content` with its own GPU pass instead, no canvas,\n// no readback (see `VireGlassBackdropPass`). Either way the texture\n// plays the role of the spec's FBO(scene): later passes only SAMPLE\n// it, never redraw it.\n// 2. blit backdrop to screen — `content` is drawn as the backing; without it the screen would\n// show only the element, and the material is compared against\n// exactly what's around it.\n// 3. downsample (`probe.ts`) — stats for the lens rectangle, see there.\n// 4. lens (`toGLSL(LENS_SHADER)`) — samples `content`, draws over the backdrop.\n// 5. surface (`toGLSL(SURFACE_SHADER)`) — bevel and highlight over the lens.\n//\n// UNITS. Everything is device-px, one coordinate space for the whole canvas (web-core spec\n// §4.2): `toLensProps` already multiplies by `density`; `toSurfaceUniforms` doesn't and\n// shouldn't (its contract is shared with Android), so its result gets run through\n// `toDeviceSurfaceUniforms`.\n//\n// SHARED CENTER. On Android the lens and the surface live in THEIR OWN local spaces (different\n// `lensPadDp`/`surfacePadDp` margins), and concentricity is a convention the component\n// maintains. Here both shaders get screen coordinates directly (`gl_FragCoord`), so the only way\n// to align them is to pass the exact SAME `u_center` in canvas pixels to both: the lens gets it\n// as-is (a native uniform), the surface gets it substituted in place of the adapter's own value\n// (which is only meaningful in its own local canvas, which doesn't exist here).\nimport {\n DYNAMIC_UNIFORMS,\n ICON_UNIFORMS,\n OVERLAY_UNIFORMS,\n toLensProps,\n toDeviceSurfaceUniforms,\n toSurfaceUniforms,\n type VireGlassAccent,\n type VireGlassMorph,\n type VireGlassTouch,\n} from '../adapters';\nimport { lensPadDp, shadowOpacity, surfacePadDp, type VireGlassGeometry } from '../geometry';\nimport { LENS_SHADER } from '../lens-shader';\nimport type { VireGlassDebugMode, VireGlassOptics } from '../material';\nimport { SURFACE_SHADER } from '../surface-shader';\nimport { toGLSL } from '../targets/glsl';\nimport {\n bindTextureAt,\n createFramebuffer,\n createProgram,\n createTexture,\n drawFullscreenTriangle,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n locationCache,\n setUniform,\n type UniformValue,\n} from './gl';\nimport { createGpuTimer } from './gpu-timer';\nimport { createProbe, type ProbeStats } from './probe';\n\n/** The scene draws itself with an offset: the lenses in the frame stay put while the canvas\n * underneath them slides — only this way can you actually see what refraction does to whatever\n * passes under the element. Offset in device-px. */\nexport type VireGlassSceneDrawer = (\n ctx: CanvasRenderingContext2D,\n width: number,\n height: number,\n offsetX: number,\n offsetY: number,\n /** Pixels per dp — the same value used for elements. The canvas and the glass must live at the\n * same scale: as a fraction of canvas width, a cell on desktop came out five times larger than\n * on a phone, and an element of the same size looked completely different on the lab bench\n * than on a device. */\n density: number,\n) => void;\n\n/** The target a `VireGlassBackdropPass` must finish its frame in — the FBO wraps `contentTexture`\n * itself, so drawing into it needs no readback: the very texture the lens samples gets the pixels\n * directly. */\nexport type VireGlassBackdropTarget = {\n /** Owned by the renderer — the FBO wrapping `contentTexture` itself, recreated on `resize` and\n * freed in `destroy`. The pass must not delete it, and must not hold onto it past the call:\n * the object may be gone or pointing at a different texture by the next `render()`. */\n framebuffer: WebGLFramebuffer;\n width: number;\n height: number;\n};\n\n/**\n * Alternative to `scene`: draws the backdrop with a GPU pass, in this same WebGL2 context, straight\n * into the texture the lens samples — no offscreen 2D canvas, no `texSubImage2D` readback. The\n * renderer doesn't know or care what's drawn; a fluid sim, a video frame, anything that ends up as\n * pixels.\n *\n * ORIENTATION CONTRACT. `contentTexture` carries the same layout the `scene` path has always\n * produced: uploaded from a 2D canvas without a Y flip, so texel row 0 (`v≈0`) is the scene's TOP\n * row (see `BLIT_FRAGMENT_SOURCE` below) — and that row sits at `gl_FragCoord.y = 0` in this FBO,\n * the window-coordinate BOTTOM, not the top. A pass that copies an ordinary top-row-first image\n * (one loaded the normal way, via `texImage2D` from a canvas or an `<img>`) straight across with\n * `texture(src, gl_FragCoord.xy / vec2(target.width, target.height))` reproduces it correctly,\n * with no flip of its own. A pass that instead treats INCREASING y as its own \"up\" — the natural\n * convention for a physical simulation — must flip before this final write, or its top ends up\n * stored as the scene's bottom and appears upside down once the lens samples it.\n *\n * The pass may render through as many of its own FBOs first as it likes (a multi-step simulation)\n * and leave the GL context in whatever state suits it; it must finish by drawing into\n * `target.framebuffer` at `viewport(0, 0, target.width, target.height)`. The renderer puts back\n * every piece of state its own remaining steps depend on right after — framebuffer, viewport,\n * blend, scissor, depth/stencil/cull, the vertex array binding, the active texture unit, and the\n * `UNPACK_*` pixel-store flags used to upload `iconMask`/`colorLayer` — so the pass is free to\n * change any of it without arranging its own cleanup.\n */\nexport type VireGlassBackdropPass = (\n gl: WebGL2RenderingContext,\n target: VireGlassBackdropTarget,\n) => void;\n\n/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */\nexport type VireGlassPiece = {\n optics: VireGlassOptics;\n geometry: VireGlassGeometry;\n /** Element center in CANVAS PIXELS (device-px). Shared between the lens and the surface. */\n centerX: number;\n centerY: number;\n morph?: VireGlassMorph;\n /** Third shape of the same body: breaking the element into pieces uses two bridges. */\n morph2?: VireGlassMorph;\n /** Local finger response: touch point, drag, press, wave. */\n touch?: VireGlassTouch;\n /** Press response, 0…1 — the highlight blooms, the body thickens slightly. */\n press?: number;\n /** Element under the finger, 0…1 — a stronger highlight and rim light. */\n active?: number;\n /** Played fraction, 0…1: an active state expressed as a field. Omitted means no progress. */\n progress?: number;\n /** Whether to draw the icon from the frame's shared mask on this element (see `iconMask` in the frame options). */\n icon?: boolean;\n /** Whether to draw the frame's colored layer on this element (see `colorLayer`). */\n overlay?: boolean;\n /** Icon color at rest and in the active state, RGBA 0…1. */\n inkIdle?: readonly number[];\n inkActive?: readonly number[];\n /** Key light direction in screen space; defaults to the light at rest. */\n light?: readonly [number, number];\n /** 0…1: the element appearing as the lens builds up (M 2:55). */\n appear?: number;\n /** 0 — the element sinks in under the finger, 1 — it rises into glass (reference §5). */\n lift?: number;\n /** Tint for the primary action — colored glass, not a fill. */\n accent?: VireGlassAccent;\n};\n\nexport type VireGlassRenderOptions = {\n /** `devicePixelRatio` — passed as an argument rather than read globally, so the renderer stays\n * testable and isn't tied to a specific window. */\n density: number;\n debug: VireGlassDebugMode;\n pieces: readonly VireGlassPiece[];\n /** CPU-side backdrop: draws into an offscreen 2D canvas, uploaded via `texSubImage2D`. Exactly\n * one of `scene`/`backdrop` is required — `render()` throws if both or neither are given — see\n * `backdrop` for the GPU alternative. */\n scene?: VireGlassSceneDrawer;\n /** GPU-side backdrop: draws straight into the texture the lens samples, in this context, no\n * readback. Exactly one of `scene`/`backdrop` is required — see `VireGlassBackdropPass` for the\n * orientation contract it must honor. */\n backdrop?: VireGlassBackdropPass | null;\n /** Canvas offset under stationary elements, device-px. */\n offsetX?: number;\n offsetY?: number;\n /**\n * Ink mask the size of the canvas, screen coordinates, read from the GREEN channel. White on\n * BLACK: antialiasing has to live in color, not alpha, otherwise green holds at one all the way\n * to the edge inside a stroke and the icon's edges tear.\n *\n * The mask does NOT carry and must not carry a calm backing under the ink: that's a property of\n * the material itself (`legibility`), the same across the whole element. While the app used to\n * supply that backing, one element had it and another didn't, with nothing to explain the\n * difference.\n */\n iconMask?: TexImageSource | null;\n /**\n * App-colored layer the size of the canvas, screen coordinates: cover art, a thumbnail —\n * anything the app puts ON the glass in color. Separate from the ink mask, because that one\n * carries a single channel colored by polarity, while this one has its own color.\n *\n * Drawn INSIDE the material, at the same coordinate as the ink: only this way does the\n * surface's deformation carry them together. As a separate layer on top of the glass, text used\n * to shake on press while the cover art stayed put.\n */\n colorLayer?: TexImageSource | null;\n};\n\nexport type VireGlassRenderResult = {\n /** One backdrop sample per element, in the same order as `pieces`. */\n probes: readonly (ProbeStats | null)[];\n};\n\nexport type VireGlassRenderer = {\n resize(widthPx: number, heightPx: number): void;\n render(options: VireGlassRenderOptions): VireGlassRenderResult;\n /** GPU time of the last `render()` call, milliseconds, via\n * `EXT_disjoint_timer_query_webgl2`. `null` when the extension is unavailable or the sample\n * came back disjoint — never an error either way. */\n getLastGpuMs(): number | null;\n destroy(): void;\n};\n\nconst BLIT_FRAGMENT_SOURCE = `#version 300 es\nprecision highp float;\nout vec4 fragColor;\nuniform sampler2D u_content;\nuniform vec2 u_resolution;\nvoid main() {\n // The same Y flip the transpiler does for the lens/surface (targets/glsl.ts): content is\n // uploaded from the 2D canvas WITHOUT flipping, so its V=0 is the scene's top row. This keeps\n // the same order here, otherwise the backdrop and what the lens refracts through it drift\n // apart vertically.\n vec2 uv = gl_FragCoord.xy / u_resolution;\n uv.y = 1.0 - uv.y;\n fragColor = texture(u_content, uv);\n}\n`;\n\n/** The material arrives as ONE channel (web-core spec §4, \"Uniform contract\"): name/size/value\n * as three parallel arrays — exactly the layout that used to get lost with Android Props. */\nfunction applyChannel(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n names: readonly string[],\n sizes: readonly number[],\n values: readonly number[],\n): void {\n let cursor = 0;\n for (let i = 0; i < names.length; i += 1) {\n const size = sizes[i];\n setUniform(gl, get(names[i]), values.slice(cursor, cursor + size));\n cursor += size;\n }\n}\n\nfunction applyObject(\n gl: WebGL2RenderingContext,\n get: (name: string) => WebGLUniformLocation | null,\n values: Record<string, UniformValue>,\n): void {\n for (const name of Object.keys(values)) setUniform(gl, get(name), values[name]);\n}\n\nexport function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer {\n const context = canvas.getContext('webgl2', {\n preserveDrawingBuffer: true,\n alpha: false,\n antialias: false,\n });\n if (!context) throw new Error('vireglass/web: WebGL2 unavailable');\n // Explicit non-nullable typing — otherwise the `!context` narrowing doesn't survive the\n // closures of the nested `function resize/render/destroy` below, and tsc goes back to treating\n // `gl` as `WebGL2RenderingContext | null`.\n const gl: WebGL2RenderingContext = context;\n\n const blitProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, BLIT_FRAGMENT_SOURCE);\n const lensProgram = createProgram(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE, toGLSL(LENS_SHADER));\n const surfaceProgram = createProgram(\n gl,\n FULLSCREEN_TRIANGLE_VERTEX_SOURCE,\n toGLSL(SURFACE_SHADER),\n );\n const probe = createProbe(gl, FULLSCREEN_TRIANGLE_VERTEX_SOURCE);\n\n const blitLoc = locationCache(gl, blitProgram);\n const lensLoc = locationCache(gl, lensProgram);\n const surfaceLoc = locationCache(gl, surfaceProgram);\n\n let width = canvas.width;\n let height = canvas.height;\n\n let sceneCanvas = document.createElement('canvas');\n let sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n // Smoothed backdrop estimate per element: keyed by its position in the pieces list.\n const settled = new Map<number, ProbeStats>();\n /** Fraction of the new sample per frame. Same magnitude as SETTLE on Android. */\n const SETTLE = 0.12;\n\n function settleStats(index: number, fresh: ProbeStats): ProbeStats {\n const prev = settled.get(index);\n if (!prev) {\n settled.set(index, fresh);\n return fresh;\n }\n const mix = (a: number, b: number) => a + (b - a) * SETTLE;\n const next: ProbeStats = {\n luma: mix(prev.luma, fresh.luma),\n busy: mix(prev.busy, fresh.busy),\n lo: mix(prev.lo, fresh.lo),\n hi: mix(prev.hi, fresh.hi),\n slopeX: mix(prev.slopeX, fresh.slopeX),\n slopeY: mix(prev.slopeY, fresh.slopeY),\n r: mix(prev.r, fresh.r),\n g: mix(prev.g, fresh.g),\n b: mix(prev.b, fresh.b),\n };\n settled.set(index, next);\n return next;\n }\n\n let contentTexture = createTexture(gl, {\n width: Math.max(width, 1),\n height: Math.max(height, 1),\n });\n\n // FBO for the `backdrop` path, wrapping `contentTexture` itself — lazy, so a `scene`-only\n // caller never pays for it. Stale after `resize` (it points at a texture that's about to be\n // deleted); dropped there and rebuilt against the new one on next use.\n let backdropFbo: WebGLFramebuffer | null = null;\n function ensureBackdropFbo(): WebGLFramebuffer {\n if (!backdropFbo) backdropFbo = createFramebuffer(gl, contentTexture);\n return backdropFbo;\n }\n\n // GPU timing for `getLastGpuMs()` — the ring buffer and disjoint handling live in\n // `gpu-timer.ts`, isolated so they can be unit-tested against a fake (this extension is\n // unavailable in the headless Chromium the shader gates run in).\n const gpuTimer = createGpuTimer(gl);\n\n // The icon mask is ONE per frame, the size of the canvas. The shader samples it at the pixel's\n // screen coordinate (`u_center + p` is exactly `xy`), so each element's icon is simply drawn\n // into the mask at its own spot: no separate texture per button is needed here.\n const iconTexture = createTexture(gl, { width: 1, height: 1 });\n const colorTexture = createTexture(gl, { width: 1, height: 1 });\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texSubImage2D(\n gl.TEXTURE_2D,\n 0,\n 0,\n 0,\n 1,\n 1,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n new Uint8Array([0, 0, 0, 0]),\n );\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n function resize(widthPx: number, heightPx: number): void {\n width = Math.max(1, Math.round(widthPx));\n height = Math.max(1, Math.round(heightPx));\n canvas.width = width;\n canvas.height = height;\n gl.viewport(0, 0, width, height);\n\n sceneCanvas = document.createElement('canvas');\n sceneCanvas.width = width;\n sceneCanvas.height = height;\n sceneCtx = sceneCanvas.getContext('2d');\n if (!sceneCtx) throw new Error('vireglass/web: scene 2D context unavailable');\n\n gl.deleteTexture(contentTexture);\n contentTexture = createTexture(gl, { width, height });\n\n if (backdropFbo) {\n gl.deleteFramebuffer(backdropFbo);\n backdropFbo = null;\n }\n }\n\n function render(options: VireGlassRenderOptions): VireGlassRenderResult {\n if (!sceneCtx) throw new Error('vireglass/web: renderer not initialized (resize was never called)');\n // Narrowed once, before the timed section: a `let` read from inside the closure below would\n // widen back to `| null`, since TS cannot see that nothing reassigns it in between.\n const ctx = sceneCtx;\n\n // Validated BEFORE the GPU timer starts, not inside it: a bad call here has to throw cleanly\n // with no query left open, which an error thrown mid-timing would risk.\n if (options.backdrop && options.scene) {\n throw new Error(\n 'vireglass/web: render() needs exactly one of options.scene or options.backdrop, not both',\n );\n }\n if (!options.backdrop && !options.scene) {\n throw new Error('vireglass/web: render() needs either options.scene or options.backdrop');\n }\n\n // The rest of the frame, including a caller-supplied `backdrop` pass that may itself throw\n // (a shader typo, a bad uniform), runs inside `time`'s own try/finally — `endQuery` always\n // pairs with `beginQuery` no matter how this exits.\n return gpuTimer.time((): VireGlassRenderResult => {\n // 1. Backdrop. Exactly one of two paths fills `contentTexture` — everything after this only\n // SAMPLES it, never redraws it.\n if (options.backdrop) {\n // GPU pass, straight into `contentTexture` via its own FBO: no 2D canvas, no readback. See\n // `VireGlassBackdropPass` for the orientation contract the pass has to honor.\n const fbo = ensureBackdropFbo();\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.viewport(0, 0, width, height);\n options.backdrop(gl, { framebuffer: fbo, width, height });\n // The pass is free to leave the context in ANY state (per its own JSDoc) — put back\n // everything the rest of this render depends on, not just the obvious framebuffer/\n // viewport pair: a pass that enables depth/stencil/face culling, binds its own VAO, or\n // changes the unpack flags used to upload `iconMask`/`colorLayer` just below would\n // otherwise corrupt a step it never touched directly.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.disable(gl.DEPTH_TEST);\n gl.disable(gl.CULL_FACE);\n gl.disable(gl.STENCIL_TEST);\n gl.colorMask(true, true, true, true);\n gl.depthMask(true);\n gl.bindVertexArray(null);\n gl.activeTexture(gl.TEXTURE0);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL);\n } else {\n // CPU-side: a 2D canvas is easier for text and \"cover art\" (task, item 3), and the texture\n // itself plays the role of the plan's FBO(scene).\n ctx.clearRect(0, 0, width, height);\n options.scene?.(ctx, width, height, options.offsetX ?? 0, options.offsetY ?? 0, options.density);\n gl.bindTexture(gl.TEXTURE_2D, contentTexture);\n gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, sceneCanvas);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n if (options.colorLayer) {\n gl.bindTexture(gl.TEXTURE_2D, colorTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);\n }\n if (options.iconMask) {\n gl.bindTexture(gl.TEXTURE_2D, iconTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);\n gl.bindTexture(gl.TEXTURE_2D, null);\n }\n\n // 2. Backdrop to screen — the backing the element is seen against.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n gl.disable(gl.BLEND);\n gl.disable(gl.SCISSOR_TEST);\n gl.useProgram(blitProgram);\n bindTextureAt(gl, 0, contentTexture, blitProgram, 'u_content');\n setUniform(gl, blitLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n\n const probes: (ProbeStats | null)[] = [];\n\n for (let index = 0; index < options.pieces.length; index += 1) {\n const piece = options.pieces[index];\n\n // 3. Downsample + stats for the rectangle of VISIBLE glass (no lens/surface margins — the\n // same `glassWidth`/`glassHeight` that go into toLensProps). Only the first element\n // captures the grid: it's shared for the frame, the rest just need their own rectangle out\n // of it.\n const halfWidth = (piece.geometry.width * options.density) / 2;\n const halfHeight = (piece.geometry.height * options.density) / 2;\n const rect = {\n centerX: piece.centerX,\n centerY: piece.centerY,\n halfWidth,\n halfHeight,\n };\n const fresh =\n index === 0\n ? probe.sample(contentTexture, width, height, rect)\n : probe.statsFor(width, height, rect);\n // The backdrop estimate eases toward the new value instead of jumping to it. On Android\n // the native view does this (`GlassLensView.kt`, a per-frame SETTLE); nobody did it on the\n // web: under a moving canvas, body density used to jerk with the instantaneous sample, and\n // on screen that read as lighting artifacts.\n const stats = fresh ? settleStats(index, fresh) : null;\n probes.push(stats);\n // Restore the viewport and the content texture binding — the probe pass reuses TEXTURE0\n // and its own FBO, unbinds them itself, but does change the viewport.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.viewport(0, 0, width, height);\n\n gl.enable(gl.BLEND);\n // Premultiplied-over: both the lens and the surface emit premultiplied alpha (see `return\n // half4(half3(...) * alpha, alpha)` in both shaders).\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n // Both passes draw a fullscreen triangle, but the element covers only a small part of the\n // frame: without scissoring, a row of samples multiplies cost by the number of elements (on\n // a headless software renderer this pushed a frame into seconds). Margin is added on both\n // sides — the shadow, bevel and light gathering all reach past the element's own bounds.\n // The morph drop travels past the element's bounds — its travel is part of the margin,\n // otherwise scissoring would cut off the tail right where it matters.\n const reachOf = (m?: VireGlassMorph) =>\n m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;\n const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));\n // Field deformation pushes the element's edge past its own bounds — drag, wave amplitude\n // and growth on press. Without this term, scissoring cuts off exactly the part being\n // dragged toward.\n const touchReach = piece.touch\n ? Math.hypot(piece.touch.pullX, piece.touch.pullY) +\n piece.touch.waveAmp * 2 +\n Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press\n : 0;\n const padPx =\n (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) *\n options.density;\n const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));\n const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));\n const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));\n const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));\n gl.enable(gl.SCISSOR_TEST);\n gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));\n\n // 4. Lens.\n gl.useProgram(lensProgram);\n bindTextureAt(gl, 0, contentTexture, lensProgram, 'content');\n setUniform(gl, lensLoc('u_contentSize'), [width, height]);\n setUniform(gl, lensLoc('u_resolution'), [width, height]);\n setUniform(gl, lensLoc('u_center'), [piece.centerX, piece.centerY]);\n // There's no local-view margin here (one shared coordinate space) — on Android `u_reach`\n // capped adaptive-blur gathering at the edge of the lens view's PADDING; there's no such\n // boundary here, so the value is chosen deliberately larger than any real gather radius, so\n // the `reach - length(p)` condition never triggers before `u_contentMin/Max` does.\n setUniform(gl, lensLoc('u_reach'), Math.max(width, height));\n setUniform(gl, lensLoc('u_contentMin'), [1, 1]);\n setUniform(gl, lensLoc('u_contentMax'), [width - 1, height - 1]);\n if (stats) {\n setUniform(gl, lensLoc('u_probeLuma'), stats.luma);\n setUniform(gl, lensLoc('u_probeBusy'), stats.busy);\n setUniform(gl, lensLoc('u_probeRange'), [stats.lo, stats.hi]);\n setUniform(gl, lensLoc('u_probeSlope'), [stats.slopeX, stats.slopeY]);\n setUniform(gl, lensLoc('u_probe'), [stats.r, stats.g, stats.b]);\n } else {\n // The probe hasn't reported yet (the first frame or two) — the -1 sentinel keeps the\n // shader on its own point samples (see the comment in `lens-shader.ts`).\n setUniform(gl, lensLoc('u_probeLuma'), -1);\n }\n const lens = toLensProps(piece.optics, piece.geometry, options.density, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n touch: piece.touch,\n progress: piece.progress,\n light: piece.light,\n appear: piece.appear,\n accent: piece.accent,\n });\n applyChannel(gl, lensLoc, lens.uniformNames, lens.uniformSizes, lens.uniformValues);\n drawFullscreenTriangle(gl);\n\n // 5. Surface — shares its center with the lens (see the comment at the top of this file).\n // `toSurfaceUniforms`'s contract is dp, shared with Android; the core converts it to pixels.\n gl.useProgram(surfaceProgram);\n const rawSurface = toSurfaceUniforms(piece.optics, piece.geometry, {\n debug: options.debug,\n morph: piece.morph,\n morph2: piece.morph2,\n bodyInLens: true,\n touch: piece.touch,\n progress: piece.progress,\n // The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives\n // in the core: while it lived here, Android didn't have it at all.\n shadow: stats ? shadowOpacity(stats.busy) : 1,\n // The probe has already computed the ambient color — the shadow gets it for free. Taken\n // as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the\n // steps the smoothing was written to remove.\n ambient: stats ? ([stats.r, stats.g, stats.b] as const) : undefined,\n appear: piece.appear,\n lift: piece.lift,\n });\n // The dp → device pixel conversion lives in the core (`toDeviceSurfaceUniforms`): one list\n // of lengths for every field, so a new field can't be forgotten here by oversight.\n applyObject(gl, surfaceLoc, {\n ...toDeviceSurfaceUniforms(rawSurface, options.density),\n u_center: [piece.centerX, piece.centerY],\n });\n // What's worklet dynamics on Android (press, active, tilt) arrives here as fields on the element.\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);\n setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);\n const hasIcon = Boolean(piece.icon && options.iconMask);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);\n // Scale 1: the coordinate is already in screen space, the sampler itself normalizes by size.\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);\n setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);\n bindTextureAt(gl, 1, iconTexture, surfaceProgram, 'u_icon');\n setUniform(gl, surfaceLoc('u_iconSize'), hasIcon ? [width, height] : [1, 1]);\n const hasColor = Boolean(piece.overlay && options.colorLayer);\n setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);\n bindTextureAt(gl, 2, colorTexture, surfaceProgram, 'u_overlay');\n setUniform(gl, surfaceLoc('u_overlaySize'), hasColor ? [width, height] : [1, 1]);\n setUniform(gl, surfaceLoc('u_resolution'), [width, height]);\n drawFullscreenTriangle(gl);\n }\n gl.disable(gl.SCISSOR_TEST);\n\n return { probes };\n });\n }\n\n function destroy(): void {\n probe.destroy();\n gl.deleteProgram(blitProgram);\n gl.deleteProgram(lensProgram);\n gl.deleteProgram(surfaceProgram);\n gl.deleteTexture(contentTexture);\n gl.deleteTexture(iconTexture);\n gl.deleteTexture(colorTexture);\n if (backdropFbo) gl.deleteFramebuffer(backdropFbo);\n gpuTimer.destroy();\n }\n\n return { resize, render, getLastGpuMs: gpuTimer.getLastMs, destroy };\n}\n"]}
package/docs/law.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # The law
2
2
 
3
- `src/law.ts` holds every calibrated number in the material — 120 of them, in 20 groups —
3
+ `src/law.ts` holds every calibrated number in the material — 121 of them, in 20 groups —
4
4
  and nothing else in the source is allowed to hold one. Renderers, shaders and helpers read from
5
5
  it; the shader templates interpolate it into their GLSL and AGSL, so the same constant reaches
6
6
  the web, Android and the DOM path without being copied.
@@ -42,7 +42,7 @@ It checks three things, and reports a fourth:
42
42
  - and it names every unmeasured value, every run — and fails if this page or the README states a
43
43
  different number, because a count written out in prose goes stale the moment a value is added.
44
44
 
45
- Today that last line reads **42 of 120**. That is the real state of the model, and it is meant to
45
+ Today that last line reads **43 of 121**. That is the real state of the model, and it is meant to
46
46
  be uncomfortable. It was 9 until the constants hiding inside `optics.ts`, `geometry.ts` and
47
47
  `touch-response.ts` were brought in — the number did not get worse, the instrument got honest.
48
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vireglass",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "A physically-derived liquid glass material for interfaces. One material model, three render targets: WebGL2, live DOM, and Android AGSL.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Danil Kotlaev",
@@ -89,12 +89,15 @@
89
89
  "test:watch": "vitest",
90
90
  "check:glsl": "tsx scripts/check-glsl.mjs",
91
91
  "check:optics": "tsx scripts/check-optics.mjs",
92
+ "check:backdrop": "tsx scripts/check-backdrop.mjs",
92
93
  "check:law": "node scripts/check-law.mjs",
93
94
  "check:dom": "node scripts/check-dom.mjs",
94
95
  "measure:dom": "node scripts/measure-dom.mjs",
95
96
  "prepare": "tsup",
96
97
  "check:package": "node scripts/check-package.mjs",
97
- "check:readme": "node scripts/check-readme.mjs"
98
+ "check:readme": "node scripts/check-readme.mjs",
99
+ "check:agsl": "tsx scripts/check-agsl.mjs",
100
+ "check:english": "node scripts/check-english.mjs"
98
101
  },
99
102
  "peerDependencies": {
100
103
  "@shopify/react-native-skia": ">=2.0.0",
@@ -129,20 +132,21 @@
129
132
  }
130
133
  },
131
134
  "devDependencies": {
135
+ "@shopify/react-native-skia": "2.6.2",
132
136
  "@types/node": "^22.10.0",
133
137
  "@types/react": "^19.0.0",
138
+ "canvaskit-wasm": "^0.42.0",
134
139
  "esbuild": "^0.28.2",
135
- "playwright": "^1.62.1",
136
- "tsup": "^8.5.0",
137
- "tsx": "^4.23.13",
138
- "typescript": "^5.8.3",
139
- "vitest": "^4.1.11",
140
- "@shopify/react-native-skia": "2.6.2",
141
140
  "expo": "~57.0.18",
142
141
  "expo-blur": "~57.0.2",
143
142
  "expo-sensors": "~57.0.2",
143
+ "playwright": "^1.62.1",
144
144
  "react": "19.2.3",
145
145
  "react-native": "0.86.2",
146
- "react-native-reanimated": "4.5.1"
146
+ "react-native-reanimated": "4.5.1",
147
+ "tsup": "^8.5.0",
148
+ "tsx": "^4.23.13",
149
+ "typescript": "^5.8.3",
150
+ "vitest": "^4.1.11"
147
151
  }
148
152
  }
package/src/dom/body.ts CHANGED
@@ -78,21 +78,36 @@ export function resolveBody(optics: VireGlassOptics, sample: BodyBackdrop, ink:
78
78
 
79
79
  /**
80
80
  * PRESENCE (§3): over a uniform backdrop there is nothing to refract and the glass honestly
81
- * disappears — right for a piece of background, wrong for a control. The sign comes from the
82
- * BACKDROP, not from ink polarity: lighter over dark, darker over light. It is a minimum, not an
83
- * addition, so a body that is already dense enough is left alone.
81
+ * disappears — right for a piece of background, wrong for a control. It is a MINIMUM, not an
82
+ * addition, so a body that already stands apart is left alone.
83
+ *
84
+ * The direction is the body's own. The previous version decided "lighter over dark, darker over
85
+ * light" from the backdrop alone, and then, when the body disagreed, clamped `tintLuma` to the
86
+ * backdrop's mean — the one value that separates from nothing. Light ink over a dark backdrop puts
87
+ * the body at 0.07 against a backdrop of 0.12: already separating, downward, and the clamp pulled
88
+ * it back onto the backdrop. Measured on the default material at presence 0.08: exactly 0.0000 at
89
+ * backdrops of 0.12, 0.20 and 0.35.
90
+ *
91
+ * What the demand is DIVIDED by is deliberately the distance to the tint's pole rather than to the
92
+ * body's own tint. Dividing by the latter is arithmetically tighter and asks for far more density
93
+ * wherever the two are close — enough to drive it to the ceiling over a dark backdrop and stop the
94
+ * glass being a window at all, which check:optics says plainly. Presence is a floor on visibility,
95
+ * not a licence to go opaque.
84
96
  */
85
97
  export function withPresence(body: GlassBody, optics: VireGlassOptics, sample: BodyBackdrop): GlassBody {
86
98
  if (optics.presence <= 0) return body;
87
99
  const mean = clamp(sample.luma, 0, 1);
88
- const lighter = mean < 0.5;
89
- const target = lighter ? Math.min(mean + optics.presence, 1) : Math.max(mean - optics.presence, 0);
90
- const separation = Math.abs(target - mean);
100
+ // Whichever side the body is already on; with nothing to go on, the side with more room.
101
+ const above = Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma > mean : mean < 0.5;
102
+ const pole = above ? TINT_LIGHT : TINT_DARK;
103
+ const separation = Math.min(optics.presence, Math.abs(pole - mean));
91
104
  const reached = Math.abs(body.tintLuma - mean) * body.density;
92
105
  if (reached >= separation) return body;
93
- const needed = separation / Math.max(Math.abs((lighter ? TINT_LIGHT : TINT_DARK) - mean), 1e-4);
106
+ const needed = separation / Math.max(Math.abs(pole - mean), 1e-4);
94
107
  return {
95
- density: Math.max(body.density, Math.min(needed, MAX_DEMAND)),
96
- tintLuma: lighter ? Math.max(body.tintLuma, mean) : Math.min(body.tintLuma, mean),
108
+ density: Math.max(body.density, Math.min(needed, BODY.presenceDemand)),
109
+ // Left where the tint law put it, unless it landed exactly on the backdrop — which is the
110
+ // case that used to be created here rather than avoided.
111
+ tintLuma: Math.abs(body.tintLuma - mean) > 1e-4 ? body.tintLuma : pole,
97
112
  };
98
113
  }
package/src/dom/index.ts CHANGED
@@ -78,8 +78,30 @@ const STYLE_ATTR = 'data-vireglass-styles';
78
78
  * The mask pair is what makes it a ring rather than a fill: the same box painted twice, once
79
79
  * clipped to the content box, composited so only the padding band survives.
80
80
  */
81
- function ensureRimStyles(): void {
82
- if (document.querySelector(`style[${STYLE_ATTR}]`)) return;
81
+ /**
82
+ * Where the filter and the rim styles go.
83
+ *
84
+ * `backdrop-filter: url(#id)` resolves the reference in the element's OWN tree. From inside a
85
+ * shadow root, a filter parked on the page is not found — and the failure is silent, because the
86
+ * reference is valid CSS: the element gets no backdrop at all, not even the blur fallback. A
87
+ * widget in a shadow root (which is how you survive a page full of global `!important`) came out
88
+ * with no material whatsoever.
89
+ *
90
+ * So the host is the element's own root node, which is the shadow root when there is one and the
91
+ * document otherwise. Nothing to configure and nothing to get wrong.
92
+ */
93
+ function hostFor(el: Element): Document | ShadowRoot {
94
+ const root = el.getRootNode();
95
+ return root instanceof ShadowRoot ? root : el.ownerDocument ?? document;
96
+ }
97
+
98
+ /** A shadow root has no `<head>`; a style element goes straight into it. */
99
+ function styleParent(host: Document | ShadowRoot): Node {
100
+ return host instanceof ShadowRoot ? host : host.head;
101
+ }
102
+
103
+ function ensureRimStyles(host: Document | ShadowRoot): void {
104
+ if (host.querySelector(`style[${STYLE_ATTR}]`)) return;
83
105
  const style = document.createElement('style');
84
106
  style.setAttribute(STYLE_ATTR, '');
85
107
  style.textContent =
@@ -87,11 +109,11 @@ function ensureRimStyles(): void {
87
109
  // The touch glow (§5) lights the material from the point of contact. Below the content, above
88
110
  // the refraction — it is light inside the glass, not a film over the label.
89
111
  `[${GLASS_ATTR}]::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;background:var(--vireglass-glow,none);opacity:var(--vireglass-glow-opacity,0)}`;
90
- document.head.appendChild(style);
112
+ styleParent(host).appendChild(style);
91
113
  }
92
114
 
93
- function getFilterHost(): SVGSVGElement {
94
- const existing = document.querySelector<SVGSVGElement>(`svg[${FILTER_HOST_ATTR}]`);
115
+ function getFilterHost(host: Document | ShadowRoot): SVGSVGElement {
116
+ const existing = host.querySelector<SVGSVGElement>(`svg[${FILTER_HOST_ATTR}]`);
95
117
  if (existing) return existing;
96
118
  const svg = document.createElementNS(SVG_NS, 'svg');
97
119
  svg.setAttribute(FILTER_HOST_ATTR, '');
@@ -101,7 +123,8 @@ function getFilterHost(): SVGSVGElement {
101
123
  svg.style.position = 'absolute';
102
124
  svg.style.pointerEvents = 'none';
103
125
  svg.appendChild(document.createElementNS(SVG_NS, 'defs'));
104
- document.body.appendChild(svg);
126
+ // A shadow root takes the svg directly; a document takes it on the body.
127
+ (host instanceof ShadowRoot ? host : host.body).appendChild(svg);
105
128
  return svg;
106
129
  }
107
130
 
@@ -165,6 +188,10 @@ function buildFilterElement(
165
188
  pass.setAttribute('xChannelSelector', 'R');
166
189
  pass.setAttribute('yChannelSelector', 'G');
167
190
  pass.setAttribute('result', `${name}raw`);
191
+ // Each channel displaces by its own share of the base scale. The share is stored on the
192
+ // element itself: under a press the scale is recomputed every frame, with nowhere else to
193
+ // recover the shares from.
194
+ pass.setAttribute('data-vireglass-ratio', String(scale > 0 ? chScale / scale : 1));
168
195
  const only = document.createElementNS(SVG_NS, 'feColorMatrix');
169
196
  only.setAttribute('in', `${name}raw`);
170
197
  only.setAttribute('type', 'matrix');
@@ -403,7 +430,9 @@ export function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): Gla
403
430
 
404
431
  warnIfNested(el);
405
432
 
406
- ensureRimStyles();
433
+ // The element's own tree: a shadow root when it is in one, the document otherwise.
434
+ const host = hostFor(el);
435
+ ensureRimStyles(host);
407
436
  el.setAttribute(GLASS_ATTR, '');
408
437
  // `inset: 0` on the rim needs a positioned ancestor. Only taken over when the host left it at
409
438
  // the initial value, and put back on destroy.
@@ -451,7 +480,7 @@ export function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): Gla
451
480
  if (key !== mapKey || !filterEl) {
452
481
  // Keyed by exactly what the maps are functions of, which is exactly the cache key above.
453
482
  const map = cached(`d|${key}`, () => buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState()));
454
- const defs = getFilterHost().querySelector('defs') as SVGDefsElement;
483
+ const defs = getFilterHost(host).querySelector('defs') as SVGDefsElement;
455
484
  const hue = hasSpectralEdge(opticsNow)
456
485
  ? cached(`h|${key}`, () => buildSpectralMap(opticsNow, geometry, devicePixelRatio()))
457
486
  : null;
@@ -551,9 +580,14 @@ export function attachGlass(el: HTMLElement, opts: AttachGlassOptions = {}): Gla
551
580
  });
552
581
  if (filterEl) {
553
582
  const feImage = filterEl.querySelector('feImage');
554
- const feDisplace = filterEl.querySelector('feDisplacementMap');
555
583
  feImage?.setAttribute('href', map.url);
556
- feDisplace?.setAttribute('scale', String(map.scale));
584
+ // EVERY pass, not the first. With dispersion there are three at different scales, and
585
+ // querySelector returned only red: under a finger it got the undispersed scale while green
586
+ // and blue kept their attach-time values, and the coloured rim stopped following the finger.
587
+ for (const pass of filterEl.querySelectorAll('feDisplacementMap')) {
588
+ const ratio = Number(pass.getAttribute('data-vireglass-ratio') ?? 1);
589
+ pass.setAttribute('scale', String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));
590
+ }
557
591
  }
558
592
  mapKey = '';
559
593
 
package/src/dom/probe.ts CHANGED
@@ -126,11 +126,35 @@ function sampleColorAt(el: HTMLElement, x: number, y: number): RgbColor | null {
126
126
  }
127
127
  const composited = compositeLayers(layers);
128
128
  if (composited) return composited;
129
- const topmost = behind[0];
130
- if (!topmost) return null;
131
- return parseColor(getComputedStyle(topmost).color);
129
+ return canvasColor(el);
132
130
  }
133
131
 
132
+ /**
133
+ * The page's own background — the floor everything else is composited over.
134
+ *
135
+ * Reached whenever nothing in the stack is opaque, which is not an edge case: CSS propagates the
136
+ * body's background to the CANVAS, so `getComputedStyle` reports `<html>` and often `<body>` as
137
+ * transparent on a perfectly ordinary white page. Any element past the end of the body's box —
138
+ * a widget pinned to a corner, say — sees a stack of nothing.
139
+ *
140
+ * This used to fall back to the topmost element's `color`, which is its TEXT colour: a white page
141
+ * with black text read as black, and the material dressed itself for a dark backdrop over a light
142
+ * one. The propagation rule says where to look instead — the root element's background, then the
143
+ * body's, then the user agent's white.
144
+ */
145
+ function canvasColor(el: HTMLElement): RgbColor | null {
146
+ const doc = el.ownerDocument;
147
+ for (const node of [doc.documentElement, doc.body]) {
148
+ if (!node) continue;
149
+ const bg = parseColor(getComputedStyle(node).backgroundColor);
150
+ if (bg && bg.a > 0.001) return bg.a >= 0.999 ? bg : compositeLayers([bg, WHITE]);
151
+ }
152
+ return WHITE;
153
+ }
154
+
155
+ /** What a browser paints the canvas when nobody says otherwise. */
156
+ const WHITE: RgbColor = { r: 255, g: 255, b: 255, a: 1 };
157
+
134
158
  export type ProbeOptions = {
135
159
  /** Grid density override — wider for a hero element, narrower for a tight control. */
136
160
  cols?: number;