vireglass 0.1.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 (72) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +10 -0
  3. package/README.md +216 -0
  4. package/android/build.gradle +15 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/java/expo/modules/glasslens/GlassBackdropView.kt +335 -0
  7. package/android/src/main/java/expo/modules/glasslens/GlassLensModule.kt +49 -0
  8. package/android/src/main/java/expo/modules/glasslens/GlassLensView.kt +463 -0
  9. package/android/src/main/java/expo/modules/glasslens/GlassProbeView.kt +76 -0
  10. package/dist/adaptation-BSbbdExK.d.cts +78 -0
  11. package/dist/adaptation-BSbbdExK.d.ts +78 -0
  12. package/dist/adapters-BPB0D5nr.d.cts +357 -0
  13. package/dist/adapters-BgSc-smX.d.ts +357 -0
  14. package/dist/chunk-HF2AWZEZ.js +1741 -0
  15. package/dist/chunk-HF2AWZEZ.js.map +1 -0
  16. package/dist/chunk-JNRZNMJJ.js +20 -0
  17. package/dist/chunk-JNRZNMJJ.js.map +1 -0
  18. package/dist/index.cjs +2159 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.cts +294 -0
  21. package/dist/index.d.ts +294 -0
  22. package/dist/index.js +286 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/material-CkUHUBoy.d.cts +408 -0
  25. package/dist/material-CkUHUBoy.d.ts +408 -0
  26. package/dist/react.cjs +73 -0
  27. package/dist/react.cjs.map +1 -0
  28. package/dist/react.d.cts +25 -0
  29. package/dist/react.d.ts +25 -0
  30. package/dist/react.js +59 -0
  31. package/dist/react.js.map +1 -0
  32. package/dist/web/index.cjs +1990 -0
  33. package/dist/web/index.cjs.map +1 -0
  34. package/dist/web/index.d.cts +148 -0
  35. package/dist/web/index.d.ts +148 -0
  36. package/dist/web/index.js +657 -0
  37. package/dist/web/index.js.map +1 -0
  38. package/expo-module.config.json +6 -0
  39. package/package.json +127 -0
  40. package/src/accessibility.ts +51 -0
  41. package/src/adaptation.ts +85 -0
  42. package/src/adapters.ts +362 -0
  43. package/src/concentric.ts +25 -0
  44. package/src/geometry.ts +151 -0
  45. package/src/glass-scale.ts +37 -0
  46. package/src/group-model.ts +224 -0
  47. package/src/index.ts +17 -0
  48. package/src/lens-shader.ts +547 -0
  49. package/src/material.ts +553 -0
  50. package/src/native/environment.ts +70 -0
  51. package/src/native/glass-group.tsx +107 -0
  52. package/src/native/glass-ink.tsx +44 -0
  53. package/src/native/glass-surface.tsx +477 -0
  54. package/src/native/index.ts +18 -0
  55. package/src/native/lens.ts +106 -0
  56. package/src/native/provider.tsx +58 -0
  57. package/src/native/surface-registry.ts +51 -0
  58. package/src/native/system-accessibility.ts +90 -0
  59. package/src/optics.ts +177 -0
  60. package/src/react.ts +102 -0
  61. package/src/reference-scene.ts +222 -0
  62. package/src/scroll-edge.ts +30 -0
  63. package/src/sdf.ts +149 -0
  64. package/src/surface-shader.ts +287 -0
  65. package/src/targets/agsl.ts +8 -0
  66. package/src/targets/glsl.ts +140 -0
  67. package/src/touch-response.ts +195 -0
  68. package/src/web/gl.ts +119 -0
  69. package/src/web/index.ts +3 -0
  70. package/src/web/probe.ts +312 -0
  71. package/src/web/reference-draw.ts +142 -0
  72. package/src/web/renderer.ts +524 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/web/gl.ts","../../src/web/probe.ts","../../src/web/renderer.ts","../../src/web/reference-draw.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","/**\n * Drawing the reference canvas onto a canvas element. Lives in `web/` because it knows about the\n * 2D context; the canvases themselves are data in `reference-scene.ts`, and the mobile lab lays\n * out the same data as native views.\n *\n * The same drawer is used by the `check:optics` gate: only this way do the eye at the bench and\n * the number in the gate look at the same canvas. The one difference between them is the fit mode.\n */\n\nimport {\n REFERENCE_SCENE_HEIGHT,\n REFERENCE_SCENE_WIDTH,\n REFERENCE_SURROUND,\n refCheckerCells,\n refGradientSteps,\n refGray,\n type VireGlassRefLayer,\n type VireGlassRefScene,\n} from '../reference-scene';\n\nexport type VireGlassRefDrawOptions = {\n /** Pixels per dp. The same value used for elements: the canvas and the glass must live at the\n * same scale. */\n readonly density: number;\n /** Canvas lightness; canvases that don't need it ignore it. Defaults to the canvas's own. */\n readonly level?: number;\n /**\n * `band` — a `REFERENCE_SCENE_WIDTH`×`REFERENCE_SCENE_HEIGHT` dp panel centered on the stage,\n * with a surrounding field: only this way do two benches show the SAME canvas, including the\n * pattern's phase under the element. `frame` — stripes stretched across the whole frame: the\n * gate has its own fixed stage, and the surrounding field would get in the way of sampling\n * pixels.\n */\n readonly fit?: 'band' | 'frame';\n};\n\nfunction drawLayer(\n ctx: CanvasRenderingContext2D,\n layer: VireGlassRefLayer,\n x: number,\n y: number,\n w: number,\n h: number,\n d: number,\n): void {\n switch (layer.kind) {\n case 'flat': {\n ctx.fillStyle = refGray(layer.level);\n ctx.fillRect(x, y, w, h);\n return;\n }\n case 'stripes': {\n ctx.fillStyle = refGray(layer.level);\n ctx.fillRect(x, y, w, h);\n ctx.fillStyle = refGray(layer.other);\n for (let at = 0; at < w; at += layer.periodDp * d) {\n ctx.fillRect(x + at, y, layer.widthDp * d, h);\n }\n return;\n }\n case 'checker': {\n for (const cell of refCheckerCells(layer, w / d, h / d)) {\n ctx.fillStyle = refGray(cell.level);\n ctx.fillRect(x + cell.xDp * d, y + cell.yDp * d, layer.cellDp * d + 1, layer.cellDp * d + 1);\n }\n return;\n }\n case 'step': {\n ctx.fillStyle = refGray(layer.left);\n ctx.fillRect(x, y, w / 2, h);\n ctx.fillStyle = refGray(layer.right);\n ctx.fillRect(x + w / 2, y, w - w / 2, h);\n return;\n }\n case 'bar': {\n ctx.fillStyle = refGray(layer.level);\n ctx.fillRect(x, y, w, h);\n const t = layer.thicknessDp * d;\n ctx.fillStyle = refGray(layer.barLevel);\n ctx.fillRect(x, y + Math.round((h - t) / 2), w, t);\n return;\n }\n case 'grid': {\n ctx.fillStyle = refGray(layer.level);\n ctx.fillRect(x, y, w, h);\n // A line exactly ONE device pixel wide — the same as what the native view draws\n // (`StyleSheet.hairlineWidth`). Half density gave two pixels on this screen against one,\n // and the two benches' canvases diverged on the scene's finest detail.\n const thin = 1;\n const step = layer.stepDp * d;\n ctx.fillStyle = refGray(layer.lineLevel);\n for (let at = 0; at <= w; at += step) ctx.fillRect(x + Math.round(at), y, thin, h);\n for (let at = 0; at <= h; at += step) ctx.fillRect(x, y + Math.round(at), w, thin);\n return;\n }\n case 'gradient': {\n const steps = refGradientSteps(layer);\n const band = h / steps.length;\n for (let i = 0; i < steps.length; i += 1) {\n ctx.fillStyle = refGray(steps[i]);\n ctx.fillRect(x, y + Math.round(i * band), w, Math.ceil(band) + 1);\n }\n return;\n }\n }\n}\n\nexport function drawReferenceScene(\n ctx: CanvasRenderingContext2D,\n scene: VireGlassRefScene,\n width: number,\n height: number,\n options: VireGlassRefDrawOptions,\n): void {\n const d = options.density;\n const bands = scene.bands(options.level ?? scene.level);\n const fill = options.fit !== 'band';\n\n let x: number;\n let y: number;\n let w: number;\n let scale: number;\n if (fill) {\n x = 0;\n y = 0;\n w = width;\n scale = height / (REFERENCE_SCENE_HEIGHT * d);\n } else {\n ctx.fillStyle = REFERENCE_SURROUND;\n ctx.fillRect(0, 0, width, height);\n w = Math.round(REFERENCE_SCENE_WIDTH * d);\n x = Math.round((width - w) / 2);\n y = Math.round((height - REFERENCE_SCENE_HEIGHT * d) / 2);\n scale = 1;\n }\n\n for (const band of bands) {\n const h = Math.round(band.heightDp * d * scale);\n drawLayer(ctx, band.layer, x, y, w, h, d);\n y += h;\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ {
2
+ "platforms": ["android"],
3
+ "android": {
4
+ "modules": ["expo.modules.glasslens.GlassLensModule"]
5
+ }
6
+ }
package/package.json ADDED
@@ -0,0 +1,127 @@
1
+ {
2
+ "name": "vireglass",
3
+ "version": "0.1.0",
4
+ "description": "A physically-derived liquid glass material for interfaces. One material model, one shader source, two render targets: WebGL2 and Android AGSL.",
5
+ "license": "Apache-2.0",
6
+ "author": "Danil Kotlaev",
7
+ "homepage": "https://github.com/pruffit/vireglass#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/pruffit/vireglass.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/pruffit/vireglass/issues"
14
+ },
15
+ "keywords": [
16
+ "glassmorphism",
17
+ "liquid-glass",
18
+ "webgl2",
19
+ "agsl",
20
+ "shader",
21
+ "refraction",
22
+ "react-native",
23
+ "expo",
24
+ "material",
25
+ "ui"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js",
36
+ "require": "./dist/index.cjs"
37
+ },
38
+ "./web": {
39
+ "types": "./dist/web/index.d.ts",
40
+ "import": "./dist/web/index.js",
41
+ "require": "./dist/web/index.cjs"
42
+ },
43
+ "./react": {
44
+ "types": "./dist/react.d.ts",
45
+ "import": "./dist/react.js",
46
+ "require": "./dist/react.cjs"
47
+ },
48
+ "./native": {
49
+ "types": "./src/native/index.ts",
50
+ "default": "./src/native/index.ts"
51
+ },
52
+ "./package.json": "./package.json"
53
+ },
54
+ "main": "./dist/index.cjs",
55
+ "module": "./dist/index.js",
56
+ "types": "./dist/index.d.ts",
57
+ "files": [
58
+ "dist",
59
+ "src",
60
+ "!src/__tests__",
61
+ "android",
62
+ "!android/build",
63
+ "!android/.gradle",
64
+ "expo-module.config.json",
65
+ "LICENSE",
66
+ "NOTICE",
67
+ "README.md"
68
+ ],
69
+ "scripts": {
70
+ "build": "tsup",
71
+ "typecheck": "tsc --noEmit",
72
+ "test": "vitest run",
73
+ "test:watch": "vitest",
74
+ "check:glsl": "tsx scripts/check-glsl.mjs",
75
+ "check:optics": "tsx scripts/check-optics.mjs",
76
+ "prepare": "tsup"
77
+ },
78
+ "peerDependencies": {
79
+ "@shopify/react-native-skia": ">=2.0.0",
80
+ "expo": ">=54",
81
+ "expo-blur": ">=14",
82
+ "expo-sensors": ">=14",
83
+ "react": ">=19",
84
+ "react-native": ">=0.79",
85
+ "react-native-reanimated": ">=4.0.0"
86
+ },
87
+ "peerDependenciesMeta": {
88
+ "@shopify/react-native-skia": {
89
+ "optional": true
90
+ },
91
+ "expo": {
92
+ "optional": true
93
+ },
94
+ "expo-blur": {
95
+ "optional": true
96
+ },
97
+ "expo-sensors": {
98
+ "optional": true
99
+ },
100
+ "react": {
101
+ "optional": true
102
+ },
103
+ "react-native": {
104
+ "optional": true
105
+ },
106
+ "react-native-reanimated": {
107
+ "optional": true
108
+ }
109
+ },
110
+ "devDependencies": {
111
+ "@types/node": "^22.10.0",
112
+ "@types/react": "^19.0.0",
113
+ "esbuild": "^0.28.2",
114
+ "playwright": "^1.62.1",
115
+ "tsup": "^8.5.0",
116
+ "tsx": "^4.23.13",
117
+ "typescript": "^5.8.3",
118
+ "vitest": "^4.1.11",
119
+ "@shopify/react-native-skia": "2.6.2",
120
+ "expo": "~57.0.18",
121
+ "expo-blur": "~57.0.2",
122
+ "expo-sensors": "~57.0.2",
123
+ "react": "19.2.3",
124
+ "react-native": "0.86.2",
125
+ "react-native-reanimated": "4.5.1"
126
+ }
127
+ }
@@ -0,0 +1,51 @@
1
+ // System accessibility settings change the material's LAYERS, they don't override it (reference
2
+ // 219 @18:15). So what's adjusted here are EFFECTS, like with toggles: the shader knows nothing
3
+ // about accessibility.
4
+ import type { VireGlassOptics } from './material';
5
+
6
+ export type VireGlassAccessibility = {
7
+ /** The glass becomes more frosted and hides content beneath it more strongly (219 @18:22). */
8
+ reduceTransparency: boolean;
9
+ /** The element moves nearly to black or white and picks up a contrasting border (219 @18:29). */
10
+ increaseContrast: boolean;
11
+ /** The material's springiness is turned off, effects are quieter (219 @18:35). Doesn't touch
12
+ * optics: this is about motion, applied by whoever computes that motion. */
13
+ reduceMotion: boolean;
14
+ };
15
+
16
+ export const NO_ACCESSIBILITY: VireGlassAccessibility = {
17
+ reduceTransparency: false,
18
+ increaseContrast: false,
19
+ reduceMotion: false,
20
+ };
21
+
22
+ /** Frost and density below which "reduced transparency" glass never drops. */
23
+ const FROST_MIN_DP = 14;
24
+ const OBSCURE_MIN = 0.45;
25
+ /** Contrast mode: the body is nearly opaque, and the silhouette must be fully visible. */
26
+ const CONTRAST_DENSITY = 0.9;
27
+ const CONTRAST_PRESENCE = 0.5;
28
+
29
+ /** A system setting acts on the whole glass and outranks the material preset (219 @18:45): even
30
+ * a transparent preset moves to the edge of the scale under contrast — the user needs contrast
31
+ * more than they need aesthetics. */
32
+ export function applyAccessibility(
33
+ optics: VireGlassOptics,
34
+ mods: VireGlassAccessibility = NO_ACCESSIBILITY,
35
+ ): VireGlassOptics {
36
+ if (!mods.reduceTransparency && !mods.increaseContrast) return optics;
37
+ const out = { ...optics };
38
+ if (mods.reduceTransparency) {
39
+ out.blur = Math.max(out.blur, FROST_MIN_DP);
40
+ out.bodyDensity = Math.max(out.bodyDensity, OBSCURE_MIN);
41
+ }
42
+ if (mods.increaseContrast) {
43
+ // The border is held by silhouette presence (`presence`), not by filling the body: filling
44
+ // the body dims the content, and the reference's requirement is specifically a contrasting
45
+ // outline around the element.
46
+ out.bodyDensity = Math.max(out.bodyDensity, CONTRAST_DENSITY);
47
+ out.presence = Math.max(out.presence, CONTRAST_PRESENCE);
48
+ out.legibility = 1;
49
+ }
50
+ return out;
51
+ }
@@ -0,0 +1,85 @@
1
+
2
+ /**
3
+ * Automatic content polarity above the glass.
4
+ *
5
+ * The glass adjusts its own body to the backdrop — but that has a limit. When the backdrop is
6
+ * light AND the ink over it is light, no amount of body density can separate them by contrast
7
+ * anymore: the body hits its own ceiling, and the letters drown. Past that point the decision is
8
+ * no longer the glass's to make but the app's — it recolors the ink to the opposite side, and all
9
+ * of the glass's own automation reflows behind it, because it depends on that same polarity.
10
+ *
11
+ * The app has nowhere to get the lightness of the backdrop UNDER the glass from — only the native
12
+ * capture can see it. That's where it comes from: the `onBackdropSample` event (a probe in
13
+ * `GlassBackdropView`).
14
+ *
15
+ * The decision is made BY LIGHTNESS with hysteresis: computing body density here with the
16
+ * shader's formula would mean keeping a second implementation of the model that silently drifts
17
+ * from the first. Whether the body and the ink actually separate by contrast is checked by
18
+ * `check:optics` — against a real render, not a copy of the formula.
19
+ */
20
+
21
+ export type BackdropSample = {
22
+ /** Average lightness of the backdrop under the glass, 0..1, on the same (sRGB-encoded) scale
23
+ * as the screen. */
24
+ luma: number;
25
+ /** Variegation: twice the mean deviation of lightness, 0 on a flat fill, 1 at the limit.
26
+ * Exactly the same quantity the probe computes on the web — otherwise the platforms would
27
+ * drift apart silently. */
28
+ busy: number;
29
+ /** The darkest and lightest spots under the glass. The legibility decision is made from these,
30
+ * not the average: right over a black/white border the average reads as "everything's fine". */
31
+ lo: number;
32
+ hi: number;
33
+ r: number;
34
+ g: number;
35
+ b: number;
36
+ };
37
+
38
+ /** Quantization step for the ambient color — for platforms where the measurement flows through
39
+ * state: every probe sample would otherwise trigger a surface repaint. The shadow is tinted
40
+ * coarsely, it doesn't need precision either. The web draws uniforms imperatively every frame
41
+ * and takes the color as is. */
42
+ const AMBIENT_STEP = 32;
43
+
44
+ /** The element's ambient color from a probe sample — the one that bleeds into its shadow
45
+ * (docs/reference.md §7). */
46
+ export function ambientFrom(sample: { r: number; g: number; b: number }): [number, number, number] {
47
+ const step = (v: number) => Math.round(Math.min(Math.max(v, 0), 1) * AMBIENT_STEP) / AMBIENT_STEP;
48
+ return [step(sample.r), step(sample.g), step(sample.b)];
49
+ }
50
+
51
+ /** Ink lightness at the ends of the scale. The kit keeps light text nearly white and dark text
52
+ * nearly black; there's no in-between polarity state by construction. */
53
+ export const INK_LIGHT = 0.95;
54
+ export const INK_DARK = 0.08;
55
+
56
+ /**
57
+ * Ink polarity from a backdrop sample — ONE place for every platform. A small element and its
58
+ * glyphs switch between light and dark so that contrast is maximized (docs/reference.md §3): over
59
+ * a yellow flower the reference already has black glyphs on light glass. Holding a light ink with
60
+ * body density over a light backdrop just turns the element into a painted plaque.
61
+ *
62
+ * The decision is by lightness with a bias toward the light side — not by average (a white screen
63
+ * with a dark stripe would otherwise never flip) and not by maximum (one light cover peeking under
64
+ * the edge would recolor the whole panel). Hysteresis lives inside; the caller decides how many
65
+ * confirmations it takes.
66
+ */
67
+ export function shouldInkBeLight(sample: { luma: number; hi?: number }, wasLight: boolean): boolean {
68
+ return decisiveLuma(sample) < (wasLight ? FLIP_LUMA : RETURN_LUMA);
69
+ }
70
+
71
+ export const decisiveLuma = (sample: { luma: number; hi?: number }) =>
72
+ sample.luma * 0.75 + (sample.hi ?? sample.luma) * 0.25;
73
+
74
+ /** Lighter than this, a light ink flips to dark. */
75
+ export const FLIP_LUMA = 0.62;
76
+ /** The way back triggers noticeably earlier than the way forward: without the gap the ink would
77
+ * flicker on every light cover sliding under the glass edge. */
78
+ export const RETURN_LUMA = 0.5;
79
+ /** How many consecutive samples have to demand a change. The probe samples ~5 times a second, so
80
+ * three samples is roughly half a second of a stable backdrop, not a random cover flashing by
81
+ * under the edge. */
82
+ export const CONFIRMATIONS = 3;
83
+ /** Duration of the recolor. Slow enough not to read as an event, fast enough that the illegible
84
+ * in-between state doesn't linger noticeably. */
85
+ export const FADE_MS = 420;