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.
- package/LICENSE +202 -0
- package/NOTICE +10 -0
- package/README.md +216 -0
- package/android/build.gradle +15 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/expo/modules/glasslens/GlassBackdropView.kt +335 -0
- package/android/src/main/java/expo/modules/glasslens/GlassLensModule.kt +49 -0
- package/android/src/main/java/expo/modules/glasslens/GlassLensView.kt +463 -0
- package/android/src/main/java/expo/modules/glasslens/GlassProbeView.kt +76 -0
- package/dist/adaptation-BSbbdExK.d.cts +78 -0
- package/dist/adaptation-BSbbdExK.d.ts +78 -0
- package/dist/adapters-BPB0D5nr.d.cts +357 -0
- package/dist/adapters-BgSc-smX.d.ts +357 -0
- package/dist/chunk-HF2AWZEZ.js +1741 -0
- package/dist/chunk-HF2AWZEZ.js.map +1 -0
- package/dist/chunk-JNRZNMJJ.js +20 -0
- package/dist/chunk-JNRZNMJJ.js.map +1 -0
- package/dist/index.cjs +2159 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +294 -0
- package/dist/index.d.ts +294 -0
- package/dist/index.js +286 -0
- package/dist/index.js.map +1 -0
- package/dist/material-CkUHUBoy.d.cts +408 -0
- package/dist/material-CkUHUBoy.d.ts +408 -0
- package/dist/react.cjs +73 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +25 -0
- package/dist/react.d.ts +25 -0
- package/dist/react.js +59 -0
- package/dist/react.js.map +1 -0
- package/dist/web/index.cjs +1990 -0
- package/dist/web/index.cjs.map +1 -0
- package/dist/web/index.d.cts +148 -0
- package/dist/web/index.d.ts +148 -0
- package/dist/web/index.js +657 -0
- package/dist/web/index.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/package.json +127 -0
- package/src/accessibility.ts +51 -0
- package/src/adaptation.ts +85 -0
- package/src/adapters.ts +362 -0
- package/src/concentric.ts +25 -0
- package/src/geometry.ts +151 -0
- package/src/glass-scale.ts +37 -0
- package/src/group-model.ts +224 -0
- package/src/index.ts +17 -0
- package/src/lens-shader.ts +547 -0
- package/src/material.ts +553 -0
- package/src/native/environment.ts +70 -0
- package/src/native/glass-group.tsx +107 -0
- package/src/native/glass-ink.tsx +44 -0
- package/src/native/glass-surface.tsx +477 -0
- package/src/native/index.ts +18 -0
- package/src/native/lens.ts +106 -0
- package/src/native/provider.tsx +58 -0
- package/src/native/surface-registry.ts +51 -0
- package/src/native/system-accessibility.ts +90 -0
- package/src/optics.ts +177 -0
- package/src/react.ts +102 -0
- package/src/reference-scene.ts +222 -0
- package/src/scroll-edge.ts +30 -0
- package/src/sdf.ts +149 -0
- package/src/surface-shader.ts +287 -0
- package/src/targets/agsl.ts +8 -0
- package/src/targets/glsl.ts +140 -0
- package/src/touch-response.ts +195 -0
- package/src/web/gl.ts +119 -0
- package/src/web/index.ts +3 -0
- package/src/web/probe.ts +312 -0
- package/src/web/reference-draw.ts +142 -0
- package/src/web/renderer.ts +524 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { CONFIRMATIONS, FLIP_LUMA, RETURN_LUMA } from './chunk-JNRZNMJJ.js';
|
|
2
|
+
export { CONFIRMATIONS, FADE_MS, FLIP_LUMA, INK_DARK, INK_LIGHT, RETURN_LUMA, ambientFrom, decisiveLuma, shouldInkBeLight } from './chunk-JNRZNMJJ.js';
|
|
3
|
+
export { ACCENT_AMOUNT, ADAPT_RADIUS, ALL_EFFECTS_ON, DEBUG_MODES, DYNAMIC_UNIFORMS, EFFECTS, FRESNEL_EXPONENT, ICON_UNIFORMS, LEGACY_NAMES, LEGACY_OPTICS, LENS_SHADER, MATERIAL_PRESETS, MATERIAL_RANGES, MAX_BEVEL_FRACTION, MAX_STRETCH, OVERLAY_UNIFORMS, PRESET_NAMES, PRODUCT_DIM, REFERENCE_PIECE_AT, REFERENCE_SCENES, REFERENCE_SCENE_HEIGHT, REFERENCE_SCENE_WIDTH, REFERENCE_SHAPES, REFERENCE_SURROUND, REST_LIGHT, RIM_FRACTION, SURFACE_LENGTH_UNIFORMS, SURFACE_SHADER, VG_FALLOFF, VG_SDF, VIREGLASS_CLEAR_MATERIAL, VIREGLASS_CONTROL_MATERIAL, VIREGLASS_LYRICS_MATERIAL, VIREGLASS_MATERIAL, VIREGLASS_MATERIAL_V4, VIREGLASS_MATERIAL_V5, VIREGLASS_SHEET_MATERIAL, absorption, activeMaterial, addPrologue, applyToggles, bevelDp, bevelFraction, blur, bodyDensity, capsuleGeometry, circleGeometry, colorPickup, convertEntryPoint, convertEvalCalls, convertHalfTypes, convertReturns, convertShaderUniforms, convertVecTypes, debugIndex, diffraction, dispersion, edgeDensity, edgeLight, fresnelF0, fresnelStrength, gatherRadius, halfMinDp, iorSpread, iridescence, lensMagnify, lensPadDp, materialForInk, mediumTint, morphBetween, morphReachDp, refCheckerCells, refGradientSteps, refGray, referenceScene, refractionScale, refractionStrength, resolveMaterial, resolveOptics, rimDp, roundedRectGeometry, shadowOpacity, shadowOpacityFrom, shadowReachDp, sizeGain, specularPower, specularStrength, surfacePadDp, thicknessDp, toDeviceSurfaceUniforms, toGLSL, toLensProps, toSurfaceUniforms } from './chunk-HF2AWZEZ.js';
|
|
4
|
+
|
|
5
|
+
// src/touch-response.ts
|
|
6
|
+
var HOLD_STIFFNESS = 260;
|
|
7
|
+
var HOLD_DAMPING = 46;
|
|
8
|
+
var RELEASE_STIFFNESS = 420;
|
|
9
|
+
var RELEASE_DAMPING = 34;
|
|
10
|
+
var PRESS_ATTACK = 0.07;
|
|
11
|
+
var PRESS_RELEASE = 0.16;
|
|
12
|
+
var WAVE_DECAY = 0.22;
|
|
13
|
+
var WAVE_TURNS_PER_SECOND = 3;
|
|
14
|
+
function createDeform() {
|
|
15
|
+
let touchX = 0;
|
|
16
|
+
let touchY = 0;
|
|
17
|
+
let targetTouchX = 0;
|
|
18
|
+
let targetTouchY = 0;
|
|
19
|
+
let pullX = 0;
|
|
20
|
+
let pullY = 0;
|
|
21
|
+
let vx = 0;
|
|
22
|
+
let vy = 0;
|
|
23
|
+
let targetX = 0;
|
|
24
|
+
let targetY = 0;
|
|
25
|
+
let held = false;
|
|
26
|
+
let press = 0;
|
|
27
|
+
let active = 0;
|
|
28
|
+
let waveAmp = 0;
|
|
29
|
+
let wavePhase = 0;
|
|
30
|
+
function grab(x, y, waveStart) {
|
|
31
|
+
const atRest = idle();
|
|
32
|
+
held = true;
|
|
33
|
+
targetTouchX = x;
|
|
34
|
+
targetTouchY = y;
|
|
35
|
+
if (atRest) {
|
|
36
|
+
touchX = x;
|
|
37
|
+
touchY = y;
|
|
38
|
+
}
|
|
39
|
+
targetX = 0;
|
|
40
|
+
targetY = 0;
|
|
41
|
+
waveAmp = Math.min(waveAmp + waveStart, waveStart * 1.6);
|
|
42
|
+
}
|
|
43
|
+
function drag(dx, dy, limit) {
|
|
44
|
+
if (!held) return;
|
|
45
|
+
const len = Math.hypot(dx, dy);
|
|
46
|
+
const scale = len > 1e-3 ? limit * Math.tanh(len / limit) / len : 0;
|
|
47
|
+
targetX = dx * scale;
|
|
48
|
+
targetY = dy * scale;
|
|
49
|
+
}
|
|
50
|
+
function release(waveStart) {
|
|
51
|
+
held = false;
|
|
52
|
+
targetX = 0;
|
|
53
|
+
targetY = 0;
|
|
54
|
+
waveAmp = Math.min(waveAmp + waveStart, waveStart * 2);
|
|
55
|
+
}
|
|
56
|
+
function integrate(dt) {
|
|
57
|
+
const k = held ? HOLD_STIFFNESS : RELEASE_STIFFNESS;
|
|
58
|
+
const c = held ? HOLD_DAMPING : RELEASE_DAMPING;
|
|
59
|
+
vx += (k * (targetX - pullX) - c * vx) * dt;
|
|
60
|
+
vy += (k * (targetY - pullY) - c * vy) * dt;
|
|
61
|
+
pullX += vx * dt;
|
|
62
|
+
pullY += vy * dt;
|
|
63
|
+
const pressTarget = held ? 1 : 0;
|
|
64
|
+
const tau = held ? PRESS_ATTACK : PRESS_RELEASE;
|
|
65
|
+
press += (pressTarget - press) * (1 - Math.exp(-dt / tau));
|
|
66
|
+
active += (pressTarget - active) * (1 - Math.exp(-dt / 0.09));
|
|
67
|
+
const follow = 1 - Math.exp(-dt / 0.045);
|
|
68
|
+
touchX += (targetTouchX - touchX) * follow;
|
|
69
|
+
touchY += (targetTouchY - touchY) * follow;
|
|
70
|
+
wavePhase += dt * WAVE_TURNS_PER_SECOND;
|
|
71
|
+
waveAmp *= Math.exp(-dt / WAVE_DECAY);
|
|
72
|
+
if (waveAmp < 0.01) waveAmp = 0;
|
|
73
|
+
}
|
|
74
|
+
function step(dt) {
|
|
75
|
+
let rest = Math.min(Math.max(dt, 0), 0.25);
|
|
76
|
+
const h = 1 / 120;
|
|
77
|
+
while (rest > 1e-6) {
|
|
78
|
+
const slice = Math.min(h, rest);
|
|
79
|
+
integrate(slice);
|
|
80
|
+
rest -= slice;
|
|
81
|
+
}
|
|
82
|
+
if (idle()) {
|
|
83
|
+
pullX = 0;
|
|
84
|
+
pullY = 0;
|
|
85
|
+
vx = 0;
|
|
86
|
+
vy = 0;
|
|
87
|
+
press = 0;
|
|
88
|
+
active = 0;
|
|
89
|
+
wavePhase = 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function idle() {
|
|
93
|
+
return !held && Math.abs(pullX) < 0.05 && Math.abs(pullY) < 0.05 && Math.hypot(vx, vy) < 0.5 && press < 4e-3 && active < 4e-3 && waveAmp === 0;
|
|
94
|
+
}
|
|
95
|
+
function sample() {
|
|
96
|
+
return { touchX, touchY, pullX, pullY, press, active, waveAmp, wavePhase };
|
|
97
|
+
}
|
|
98
|
+
return { grab, drag, release, step, idle, sample };
|
|
99
|
+
}
|
|
100
|
+
function raiseIntoGlass(press) {
|
|
101
|
+
const t = press < 0 ? 0 : press > 1 ? 1 : press;
|
|
102
|
+
return { glass: Math.pow(t, 0.6), solid: 1 - Math.pow(t, 1.4) };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/accessibility.ts
|
|
106
|
+
var NO_ACCESSIBILITY = {
|
|
107
|
+
reduceTransparency: false,
|
|
108
|
+
increaseContrast: false,
|
|
109
|
+
reduceMotion: false
|
|
110
|
+
};
|
|
111
|
+
var FROST_MIN_DP = 14;
|
|
112
|
+
var OBSCURE_MIN = 0.45;
|
|
113
|
+
var CONTRAST_DENSITY = 0.9;
|
|
114
|
+
var CONTRAST_PRESENCE = 0.5;
|
|
115
|
+
function applyAccessibility(optics, mods = NO_ACCESSIBILITY) {
|
|
116
|
+
if (!mods.reduceTransparency && !mods.increaseContrast) return optics;
|
|
117
|
+
const out = { ...optics };
|
|
118
|
+
if (mods.reduceTransparency) {
|
|
119
|
+
out.blur = Math.max(out.blur, FROST_MIN_DP);
|
|
120
|
+
out.bodyDensity = Math.max(out.bodyDensity, OBSCURE_MIN);
|
|
121
|
+
}
|
|
122
|
+
if (mods.increaseContrast) {
|
|
123
|
+
out.bodyDensity = Math.max(out.bodyDensity, CONTRAST_DENSITY);
|
|
124
|
+
out.presence = Math.max(out.presence, CONTRAST_PRESENCE);
|
|
125
|
+
out.legibility = 1;
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/glass-scale.ts
|
|
131
|
+
var GLASS_SCALE_DEFAULT = 0.35;
|
|
132
|
+
var TINTED_DENSITY = 0.9;
|
|
133
|
+
var clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
134
|
+
function applyGlassScale(optics, scale) {
|
|
135
|
+
const s = clamp01(scale);
|
|
136
|
+
if (s === GLASS_SCALE_DEFAULT) return optics;
|
|
137
|
+
if (s < GLASS_SCALE_DEFAULT) {
|
|
138
|
+
const k2 = s / GLASS_SCALE_DEFAULT;
|
|
139
|
+
return { ...optics, legibility: optics.legibility * k2, dimming: optics.dimming * k2 };
|
|
140
|
+
}
|
|
141
|
+
const k = (s - GLASS_SCALE_DEFAULT) / (1 - GLASS_SCALE_DEFAULT);
|
|
142
|
+
return { ...optics, bodyDensity: Math.max(optics.bodyDensity, TINTED_DENSITY * k) };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/scroll-edge.ts
|
|
146
|
+
function scrollEdgeStyle(inkLight, pinned = false) {
|
|
147
|
+
if (pinned) return "hard";
|
|
148
|
+
return inkLight ? "dim" : "dissolve";
|
|
149
|
+
}
|
|
150
|
+
var SCROLL_EDGE_ENGAGE_DP = 24;
|
|
151
|
+
function scrollEdgeStrength(side, scroll, maxScroll) {
|
|
152
|
+
const room = side === "top" ? scroll : maxScroll - scroll;
|
|
153
|
+
return Math.min(Math.max(room / SCROLL_EDGE_ENGAGE_DP, 0), 1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/concentric.ts
|
|
157
|
+
function concentricRadius(outerRadius, inset, minimum = 0) {
|
|
158
|
+
return Math.max(outerRadius - inset, Math.max(minimum, 0));
|
|
159
|
+
}
|
|
160
|
+
function concentricInset(outerRadius, innerRadius) {
|
|
161
|
+
return Math.max(outerRadius - innerRadius, 0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/group-model.ts
|
|
165
|
+
var SMOOTH = 0.25;
|
|
166
|
+
var SETTLE = 1e-6;
|
|
167
|
+
var GRADIENT = 0.35;
|
|
168
|
+
var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
169
|
+
function fitLuma(members) {
|
|
170
|
+
const n = members.length;
|
|
171
|
+
let mx = 0;
|
|
172
|
+
let ml = 0;
|
|
173
|
+
for (const m of members) {
|
|
174
|
+
mx += m.x;
|
|
175
|
+
ml += m.sample.luma;
|
|
176
|
+
}
|
|
177
|
+
mx /= n;
|
|
178
|
+
ml /= n;
|
|
179
|
+
let sxx = 0;
|
|
180
|
+
let sxl = 0;
|
|
181
|
+
for (const m of members) {
|
|
182
|
+
const dx = m.x - mx;
|
|
183
|
+
sxx += dx * dx;
|
|
184
|
+
sxl += dx * m.sample.luma;
|
|
185
|
+
}
|
|
186
|
+
return { mx, ml, slope: sxx > 1e-6 ? sxl / sxx : 0 };
|
|
187
|
+
}
|
|
188
|
+
function aggregate(members) {
|
|
189
|
+
if (members.length === 0) return null;
|
|
190
|
+
const { mx, ml, slope } = fitLuma(members);
|
|
191
|
+
let busy = 0;
|
|
192
|
+
let lo = 1;
|
|
193
|
+
let hi = 0;
|
|
194
|
+
let base = 0;
|
|
195
|
+
let r = 0;
|
|
196
|
+
let g = 0;
|
|
197
|
+
let b = 0;
|
|
198
|
+
let legibility = 0;
|
|
199
|
+
for (const m of members) {
|
|
200
|
+
busy = Math.max(busy, m.sample.busy);
|
|
201
|
+
lo = Math.min(lo, m.sample.lo);
|
|
202
|
+
hi = Math.max(hi, m.sample.hi);
|
|
203
|
+
base = Math.max(base, m.sample.luma);
|
|
204
|
+
r += m.sample.r;
|
|
205
|
+
g += m.sample.g;
|
|
206
|
+
b += m.sample.b;
|
|
207
|
+
legibility = Math.max(legibility, m.legibility);
|
|
208
|
+
}
|
|
209
|
+
const k = members.length;
|
|
210
|
+
return {
|
|
211
|
+
plane: { mx, ml, slope, base, rest: [busy, lo, hi, r / k, g / k, b / k] },
|
|
212
|
+
// The polarity decision is one per group, by its AVERAGE lightness. Deciding on its own,
|
|
213
|
+
// each button used to end up a different color over a busy backdrop.
|
|
214
|
+
decision: { decisive: ml * 0.75 + hi * 0.25, legibility }
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function smoothPlane(prev, next) {
|
|
218
|
+
if (!prev) return next;
|
|
219
|
+
const e = (was, now) => Math.abs(now - was) < SETTLE ? now : was + (now - was) * SMOOTH;
|
|
220
|
+
const ml = e(prev.ml, next.ml);
|
|
221
|
+
const slope = e(prev.slope, next.slope);
|
|
222
|
+
const base = e(prev.base, next.base);
|
|
223
|
+
const rest = next.rest.map((v, i) => e(prev.rest[i], v));
|
|
224
|
+
const same = next.mx === prev.mx && ml === prev.ml && slope === prev.slope && base === prev.base && rest.every((v, i) => v === prev.rest[i]);
|
|
225
|
+
return same ? prev : { mx: next.mx, ml, slope, base, rest };
|
|
226
|
+
}
|
|
227
|
+
function probeValuesAt(plane, x) {
|
|
228
|
+
const here = plane.ml + plane.slope * (x - plane.mx);
|
|
229
|
+
const luma = clamp012(plane.base - (plane.base - here) * GRADIENT);
|
|
230
|
+
return [luma, plane.rest[0], plane.rest[1], plane.rest[2], 0, 0, plane.rest[3], plane.rest[4], plane.rest[5]];
|
|
231
|
+
}
|
|
232
|
+
function wantsPolarityChange(decision, polarity) {
|
|
233
|
+
return polarity === 1 ? decision.decisive >= FLIP_LUMA : decision.decisive < RETURN_LUMA;
|
|
234
|
+
}
|
|
235
|
+
function createGroupState(sink) {
|
|
236
|
+
const members = /* @__PURE__ */ new Map();
|
|
237
|
+
let plane = null;
|
|
238
|
+
let pending = 0;
|
|
239
|
+
let polarity = 1;
|
|
240
|
+
const measure = () => {
|
|
241
|
+
const next = aggregate([...members.values()]);
|
|
242
|
+
if (!next) {
|
|
243
|
+
pending = 0;
|
|
244
|
+
plane = null;
|
|
245
|
+
sink.plane(null);
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
plane = smoothPlane(plane, next.plane);
|
|
249
|
+
sink.plane(plane);
|
|
250
|
+
return next.decision;
|
|
251
|
+
};
|
|
252
|
+
return {
|
|
253
|
+
report(id, x, y, sample, legibility) {
|
|
254
|
+
members.set(id, { x, y, sample, legibility });
|
|
255
|
+
const decision = measure();
|
|
256
|
+
if (!decision) return;
|
|
257
|
+
if (!wantsPolarityChange(decision, polarity)) {
|
|
258
|
+
pending = 0;
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
pending += 1;
|
|
262
|
+
if (pending < CONFIRMATIONS) return;
|
|
263
|
+
pending = 0;
|
|
264
|
+
polarity = polarity === 1 ? 0 : 1;
|
|
265
|
+
sink.flip(polarity);
|
|
266
|
+
},
|
|
267
|
+
// Only recomputes the estimate: losing a member isn't a backdrop sample and can't count as a
|
|
268
|
+
// polarity confirmation — unmounting the group used to rack up CONFIRMATIONS instantly and
|
|
269
|
+
// trigger a recolor nobody was left to cancel.
|
|
270
|
+
release(id) {
|
|
271
|
+
if (members.delete(id)) measure();
|
|
272
|
+
},
|
|
273
|
+
plane: () => plane,
|
|
274
|
+
polarity: () => polarity,
|
|
275
|
+
confirmations: () => pending
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// src/targets/agsl.ts
|
|
280
|
+
function toAGSL(shaderSource) {
|
|
281
|
+
return shaderSource;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export { GLASS_SCALE_DEFAULT, GRADIENT, NO_ACCESSIBILITY, SCROLL_EDGE_ENGAGE_DP, SETTLE, SMOOTH, aggregate, applyAccessibility, applyGlassScale, concentricInset, concentricRadius, createDeform, createGroupState, probeValuesAt, raiseIntoGlass, scrollEdgeStrength, scrollEdgeStyle, smoothPlane, toAGSL };
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
286
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/touch-response.ts","../src/accessibility.ts","../src/glass-scale.ts","../src/scroll-edge.ts","../src/concentric.ts","../src/group-model.ts","../src/targets/agsl.ts"],"names":["k","clamp01"],"mappings":"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","file":"index.js","sourcesContent":["// The element's response to a finger — PART OF THE MATERIAL, not the app: the springs here\n// describe what the medium feels like, exactly the way ior describes what it looks like through.\n// Keeping them with the consumer would mean web and Android end up with two different glasses\n// under one name.\n//\n// It's the FIELD around the touch point that deforms (vgTouchWarp in sdf.ts), so four values are\n// computed here: where it was touched, how far it's being dragged, how deep the press is, and\n// what wave is currently running.\n//\n// The key point: drag is anchored to the touch BLOB. Pull the right edge and the right edge\n// moves, the left stays put; the finger has area, not a point — the plateau inside `vgTouchWarp`.\n// Scaling the shape's bounding box isn't an option: that would make a rightward pull also bulge\n// the left side, which liquid doesn't do.\n//\n// PRESS is viscous: it dents shallow and releases slowly.\n// DRAG is thick: the body noticeably lags the finger, travel is short, and on release it snaps\n// back quickly with almost no overshoot. A wide, springy overshoot would be liquid jelly, not\n// dense glass.\n// WAVE: touch and lift-off each throw a short ring that decays within a quarter second.\n\nexport type DeformSample = {\n /** Touch point relative to the element's center, CSS pixels. */\n touchX: number;\n touchY: number;\n pullX: number;\n pullY: number;\n press: number;\n active: number;\n /** Wave amplitude in CSS pixels and its phase in turns. */\n waveAmp: number;\n wavePhase: number;\n};\n\nconst HOLD_STIFFNESS = 260;\nconst HOLD_DAMPING = 46;\n/** Release is stiffer than hold, but damping is high: a dense medium snaps back fast with almost\n * no overshoot. A visible overshoot would be liquid jelly, not dense glass. */\nconst RELEASE_STIFFNESS = 420;\nconst RELEASE_DAMPING = 34;\n\nconst PRESS_ATTACK = 0.07;\nconst PRESS_RELEASE = 0.16;\n\n/** The wave is short and weak: in a viscous medium ripples decay within a quarter second rather\n * than oscillating. */\nconst WAVE_DECAY = 0.22;\nconst WAVE_TURNS_PER_SECOND = 3.0;\n\nexport function createDeform() {\n let touchX = 0;\n let touchY = 0;\n let targetTouchX = 0;\n let targetTouchY = 0;\n let pullX = 0;\n let pullY = 0;\n let vx = 0;\n let vy = 0;\n let targetX = 0;\n let targetY = 0;\n let held = false;\n let press = 0;\n let active = 0;\n let waveAmp = 0;\n let wavePhase = 0;\n\n /** `x`, `y` — touch point relative to the element's center, CSS pixels. */\n function grab(x: number, y: number, waveStart: number): void {\n // Rest is checked BEFORE the grab: idle() looks at !held, and after `held = true` it's\n // always false — the point would then jump even on a first touch of a resting element.\n const atRest = idle();\n held = true;\n targetTouchX = x;\n targetTouchY = y;\n // On a resting element the finger lands instantly; if it hasn't settled yet from the\n // previous touch, the point travels there over a couple of frames. An instant jump tears the\n // deformation, and on rapid taps that reads as jitter.\n if (atRest) {\n touchX = x;\n touchY = y;\n }\n targetX = 0;\n targetY = 0;\n // Impulses ADD UP rather than restart, and phase isn't reset: resetting it would cut off a\n // running wave mid-period, which is exactly what causes a jolt on rapid clicks.\n waveAmp = Math.min(waveAmp + waveStart, waveStart * 1.6);\n }\n\n function drag(dx: number, dy: number, limit: number): void {\n if (!held) return;\n const len = Math.hypot(dx, dy);\n // Travel saturates rather than clips: near the limit the finger keeps moving while the field\n // barely does — that's how a thick liquid behaves once it hits its limit.\n const scale = len > 1e-3 ? (limit * Math.tanh(len / limit)) / len : 0;\n targetX = dx * scale;\n targetY = dy * scale;\n }\n\n /** Lifting the finger throws a second wave — weaker than the one from touching down. */\n function release(waveStart: number): void {\n held = false;\n targetX = 0;\n targetY = 0;\n waveAmp = Math.min(waveAmp + waveStart, waveStart * 2);\n }\n\n function integrate(dt: number): void {\n const k = held ? HOLD_STIFFNESS : RELEASE_STIFFNESS;\n const c = held ? HOLD_DAMPING : RELEASE_DAMPING;\n vx += (k * (targetX - pullX) - c * vx) * dt;\n vy += (k * (targetY - pullY) - c * vy) * dt;\n pullX += vx * dt;\n pullY += vy * dt;\n\n const pressTarget = held ? 1 : 0;\n const tau = held ? PRESS_ATTACK : PRESS_RELEASE;\n press += (pressTarget - press) * (1 - Math.exp(-dt / tau));\n active += (pressTarget - active) * (1 - Math.exp(-dt / 0.09));\n\n // The touch point catches up to the finger fast, but not instantly — see grab().\n const follow = 1 - Math.exp(-dt / 0.045);\n touchX += (targetTouchX - touchX) * follow;\n touchY += (targetTouchY - touchY) * follow;\n\n wavePhase += dt * WAVE_TURNS_PER_SECOND;\n waveAmp *= Math.exp(-dt / WAVE_DECAY);\n if (waveAmp < 0.01) waveAmp = 0;\n }\n\n /**\n * The step is fixed, the frame isn't: on a software renderer there can be as few as ten frames\n * a second, and integrating \"however much time passed\" makes the response lag behind real time\n * (and at a large step the spring can even diverge). So time is caught up in sub-steps.\n */\n function step(dt: number): void {\n let rest = Math.min(Math.max(dt, 0), 0.25);\n const h = 1 / 120;\n while (rest > 1e-6) {\n const slice = Math.min(h, rest);\n integrate(slice);\n rest -= slice;\n }\n // Settled means exactly at rest. The `idle()` threshold stops rendering, but the values\n // themselves only approach zero asymptotically, and the element would stay forever very\n // slightly deformed: invisible to the eye, but a frame-vs-reference comparison would flag the\n // mismatch forever.\n if (idle()) {\n pullX = 0;\n pullY = 0;\n vx = 0;\n vy = 0;\n press = 0;\n active = 0;\n wavePhase = 0;\n }\n }\n\n /** Whether the element has settled — the bench uses this to decide whether to keep drawing frames. */\n function idle(): boolean {\n return (\n !held &&\n Math.abs(pullX) < 0.05 &&\n Math.abs(pullY) < 0.05 &&\n Math.hypot(vx, vy) < 0.5 &&\n press < 0.004 &&\n active < 0.004 &&\n waveAmp === 0\n );\n }\n\n function sample(): DeformSample {\n return { touchX, touchY, pullX, pullY, press, active, waveAmp, wavePhase };\n }\n\n return { grab, drag, release, step, idle, sample };\n}\n\n/**\n * RAISING INTO GLASS (reference §5, M 4:10–4:30). A control that isn't glass at rest — a switch\n * knob, a slider handle — stops being frosted under the finger and becomes a lens: whatever is\n * beneath it shows through.\n *\n * Glass comes in FASTER than frost leaves: the two fractions overlap, otherwise midway through\n * the transition the backdrop flashes through the knob for an instant — a hole where the control\n * should be.\n *\n * Lifting off the backdrop is NOT part of this. The shader's `u_lift` is a direction (\"this kind\n * of element sinks in or rises\"), not a magnitude — how far it has already risen is carried by\n * the press value that `u_lift` gets multiplied by. Returning a third fraction here would mean\n * multiplying press by itself — which is exactly what happened the first time the web bench wired\n * this up.\n */\nexport function raiseIntoGlass(press: number): { glass: number; solid: number } {\n const t = press < 0 ? 0 : press > 1 ? 1 : press;\n return { glass: Math.pow(t, 0.6), solid: 1 - Math.pow(t, 1.4) };\n}\n","// System accessibility settings change the material's LAYERS, they don't override it (reference\n// 219 @18:15). So what's adjusted here are EFFECTS, like with toggles: the shader knows nothing\n// about accessibility.\nimport type { VireGlassOptics } from './material';\n\nexport type VireGlassAccessibility = {\n /** The glass becomes more frosted and hides content beneath it more strongly (219 @18:22). */\n reduceTransparency: boolean;\n /** The element moves nearly to black or white and picks up a contrasting border (219 @18:29). */\n increaseContrast: boolean;\n /** The material's springiness is turned off, effects are quieter (219 @18:35). Doesn't touch\n * optics: this is about motion, applied by whoever computes that motion. */\n reduceMotion: boolean;\n};\n\nexport const NO_ACCESSIBILITY: VireGlassAccessibility = {\n reduceTransparency: false,\n increaseContrast: false,\n reduceMotion: false,\n};\n\n/** Frost and density below which \"reduced transparency\" glass never drops. */\nconst FROST_MIN_DP = 14;\nconst OBSCURE_MIN = 0.45;\n/** Contrast mode: the body is nearly opaque, and the silhouette must be fully visible. */\nconst CONTRAST_DENSITY = 0.9;\nconst CONTRAST_PRESENCE = 0.5;\n\n/** A system setting acts on the whole glass and outranks the material preset (219 @18:45): even\n * a transparent preset moves to the edge of the scale under contrast — the user needs contrast\n * more than they need aesthetics. */\nexport function applyAccessibility(\n optics: VireGlassOptics,\n mods: VireGlassAccessibility = NO_ACCESSIBILITY,\n): VireGlassOptics {\n if (!mods.reduceTransparency && !mods.increaseContrast) return optics;\n const out = { ...optics };\n if (mods.reduceTransparency) {\n out.blur = Math.max(out.blur, FROST_MIN_DP);\n out.bodyDensity = Math.max(out.bodyDensity, OBSCURE_MIN);\n }\n if (mods.increaseContrast) {\n // The border is held by silhouette presence (`presence`), not by filling the body: filling\n // the body dims the content, and the reference's requirement is specifically a contrasting\n // outline around the element.\n out.bodyDensity = Math.max(out.bodyDensity, CONTRAST_DENSITY);\n out.presence = Math.max(out.presence, CONTRAST_PRESENCE);\n out.legibility = 1;\n }\n return out;\n}\n","// User-facing glass transparency scale: iOS 26.1 gave a choice between two options (\"default clear\n// look\" or \"tinted look which increases opacity of the material\"), iOS 27 a continuous slider\n// \"ultra clear → fully tinted\", and apps get it without recompiling.\n//\n// It adjusts EFFECTS, not causes, and that's not a compromise. The cause \"medium density\" is\n// deliberately absent from the model: the glass has no color of its own, `bodyDensity` is derived\n// from absorption through the body and never exceeds 0.03, and the visible density is held by the\n// legibility requirement and scattering. A thickness scale would move a number that isn't visible\n// in the frame (measured by the `check:optics` gate).\nimport type { VireGlassOptics } from './material';\n\n/** The point on the scale where the material stays exactly as it is today. */\nexport const GLASS_SCALE_DEFAULT = 0.35;\n\n/** Body density at the \"fully tinted\" end: content under the glass must be hidden. */\nconst TINTED_DENSITY = 0.9;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * `scale` 0 is ultra clear, 1 is fully tinted. Toward the transparent end, the legibility\n * requirement and the dimming layer are relaxed (the user chose clarity); toward the tinted end,\n * body density grows.\n *\n * Accessibility settings apply AFTER the scale: they set floors, and the user's chosen clarity\n * does not override them (219 @18:45).\n */\nexport function applyGlassScale(optics: VireGlassOptics, scale: number): VireGlassOptics {\n const s = clamp01(scale);\n if (s === GLASS_SCALE_DEFAULT) return optics;\n if (s < GLASS_SCALE_DEFAULT) {\n const k = s / GLASS_SCALE_DEFAULT;\n return { ...optics, legibility: optics.legibility * k, dimming: optics.dimming * k };\n }\n const k = (s - GLASS_SCALE_DEFAULT) / (1 - GLASS_SCALE_DEFAULT);\n return { ...optics, bodyDensity: Math.max(optics.bodyDensity, TINTED_DENSITY * k) };\n}\n","// Scroll edge effect (reference 219 @8:52) — the SCREEN's job, not the material's: it sits over\n// the content beneath the panel, and the glass sees an already-dimmed backdrop. Only the general\n// rules live here.\n\nexport type ScrollEdgeStyle = 'dissolve' | 'dim' | 'hard';\n\n/**\n * The edge style follows the style of the nearest glass: light ink means dark glass, and the\n * content beneath it fades into a light dimming; dark ink means light glass, and the content\n * dissolves into the background. A pinned view under the panel (column headers) gets a flat\n * band with no gradient.\n */\nexport function scrollEdgeStyle(inkLight: boolean, pinned = false): ScrollEdgeStyle {\n if (pinned) return 'hard';\n return inkLight ? 'dim' : 'dissolve';\n}\n\n/** How far the content has to slide under the panel for the effect to fully engage, dp. */\nexport const SCROLL_EDGE_ENGAGE_DP = 24;\n\n/**\n * Edge strength as a function of scroll. With no scroll, content near the top doesn't slide\n * under the panel yet — so there's no effect (a mail screen at the top: the header sits on a\n * clean background). At the bottom, content slides under it for as long as there's room left\n * to scroll.\n */\nexport function scrollEdgeStrength(side: 'top' | 'bottom', scroll: number, maxScroll: number): number {\n const room = side === 'top' ? scroll : maxScroll - scroll;\n return Math.min(Math.max(room / SCROLL_EDGE_ENGAGE_DP, 0), 1);\n}\n","// Concentricity (reference 219 @7:53): nested shapes share the CENTER of curvature, not the radius.\n// So the inner shape's radius is smaller by exactly the inset — otherwise the corners don't run\n// parallel and the gap between the shapes either gets eaten or spreads apart.\n\n/**\n * Radius of a nested shape: outer radius minus inset. Zero is a square corner; it never goes\n * negative — once the inset exceeds the outer radius, the corner is simply a right angle.\n *\n * `minimum` — a floor on the radius (analogous to `concentric(minimum:)` in SwiftUI): far from\n * the edge, honest concentricity yields zero and the nested element drops out of the family with\n * a sharp corner. The floor breaks concentricity on purpose — here kinship between shapes matters\n * more than a shared center of curvature.\n */\nexport function concentricRadius(outerRadius: number, inset: number, minimum = 0): number {\n return Math.max(outerRadius - inset, Math.max(minimum, 0));\n}\n\n/**\n * The inset at which an inner shape with a given radius stays concentric with the outer one.\n * The inverse problem: the element's radius is known (its size dictates it), and what's needed\n * is the margin around it.\n */\nexport function concentricInset(outerRadius: number, innerRadius: number): number {\n return Math.max(outerRadius - innerRadius, 0);\n}\n","import { CONFIRMATIONS, FLIP_LUMA, RETURN_LUMA, type BackdropSample } from './adaptation';\n\n/**\n * GLASS GROUP ESTIMATE — the pure part of the surface group (`glass-group.tsx`).\n *\n * Everything that decides lives here: the lightness plane from members' samples, the group's\n * aggregates, the polarity requirement and its hysteresis. None of these rules need React or the\n * native layer, so they live apart from the component and are checked by a unit test.\n */\n\nexport type GroupMember = { x: number; y: number; sample: BackdropSample; legibility: number };\n\n/** Group estimate: center and average lightness, slope along x, the lightest spot, and the\n * measurement values shared by everyone — [variegation, lo, hi, r, g, b]. */\nexport type GroupPlane = {\n mx: number;\n ml: number;\n slope: number;\n base: number;\n rest: number[];\n};\n\n/** Input to the polarity decision: the lightness the group judges by, and the strictest of the requirements. */\nexport type GroupDecision = { decisive: number; legibility: number };\n\n/** Fraction of a new sample in the smoothed estimate. Samples come in from every member, so the\n * group collects roughly twenty a second — a quarter is enough for a response within ~200 ms. */\nexport const SMOOTH = 0.25;\n\n/** The remainder below which smoothing snaps the value to the sample. An exponential never\n * actually reaches its target, and the estimate kept \"changing\" by denormals for two more\n * minutes after the backdrop had settled. */\nexport const SETTLE = 1e-6;\n\n/**\n * Fraction of the slope that reaches the members.\n *\n * A plane through four points nearly interpolates them: right at a black/white border, buttons\n * were getting 0.0, 0.3, 0.7 and 1.0 — that is, exactly their own individual values, and the\n * group fell apart into independent elements again. Density is set by the group's LIGHTEST spot;\n * the slope only lets it off slightly at the dark end.\n */\nexport const GRADIENT = 0.35;\n\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * Lightness plane from members' samples. The slope is a least-squares fit along x: the group's\n * members stand in a row, and one axis is enough — there's no vertical spread among them. The\n * coordinates are centered, so the normal equations decouple.\n */\nfunction fitLuma(members: readonly GroupMember[]): {\n mx: number;\n ml: number;\n slope: number;\n} {\n const n = members.length;\n let mx = 0;\n let ml = 0;\n for (const m of members) {\n mx += m.x;\n ml += m.sample.luma;\n }\n mx /= n;\n ml /= n;\n let sxx = 0;\n let sxl = 0;\n for (const m of members) {\n const dx = m.x - mx;\n sxx += dx * dx;\n sxl += dx * m.sample.luma;\n }\n return { mx, ml, slope: sxx > 1e-6 ? sxl / sxx : 0 };\n}\n\n/** Group estimate from its members. An empty group has nothing to estimate — that's `null`. */\nexport function aggregate(\n members: readonly GroupMember[],\n): { plane: GroupPlane; decision: GroupDecision } | null {\n if (members.length === 0) return null;\n\n const { mx, ml, slope } = fitLuma(members);\n let busy = 0;\n let lo = 1;\n let hi = 0;\n // The group's lightest SPOT: density for everyone is computed from it. Otherwise, right at a\n // black/white border the group would hold to the average, a light ink would never darken\n // against anything, and it would drown over the light half.\n let base = 0;\n let r = 0;\n let g = 0;\n let b = 0;\n // The legibility requirement is the group's strictest: polarity is one for all, and going by\n // the weakest requirement would leave a neighbor with pickier optics illegible.\n let legibility = 0;\n for (const m of members) {\n busy = Math.max(busy, m.sample.busy);\n lo = Math.min(lo, m.sample.lo);\n hi = Math.max(hi, m.sample.hi);\n base = Math.max(base, m.sample.luma);\n r += m.sample.r;\n g += m.sample.g;\n b += m.sample.b;\n legibility = Math.max(legibility, m.legibility);\n }\n const k = members.length;\n return {\n plane: { mx, ml, slope, base, rest: [busy, lo, hi, r / k, g / k, b / k] },\n // The polarity decision is one per group, by its AVERAGE lightness. Deciding on its own,\n // each button used to end up a different color over a busy backdrop.\n decision: { decisive: ml * 0.75 + hi * 0.25, legibility },\n };\n}\n\n/**\n * Smoothing runs over samples, not frames: the native lens smooths ITS OWN estimate, and the\n * group estimate overrides it with an already-finished value. Without this the group's tone\n * changed in steps — the probe's 180 ms cadence is too coarse for the adaptation to read as\n * unnoticeable.\n */\nexport function smoothPlane(prev: GroupPlane | null, next: GroupPlane): GroupPlane {\n if (!prev) return next;\n const e = (was: number, now: number) =>\n Math.abs(now - was) < SETTLE ? now : was + (now - was) * SMOOTH;\n const ml = e(prev.ml, next.ml);\n const slope = e(prev.slope, next.slope);\n const base = e(prev.base, next.base);\n const rest = next.rest.map((v, i) => e(prev.rest[i], v));\n // A converged estimate is handed back as the same object: otherwise `setPlane` would repaint\n // the group on every sample — twenty times a second, even on a still screen.\n const same =\n next.mx === prev.mx &&\n ml === prev.ml &&\n slope === prev.slope &&\n base === prev.base &&\n rest.every((v, i) => v === prev.rest[i]);\n return same ? prev : { mx: next.mx, ml, slope, base, rest };\n}\n\n/** The sample a member at position `x` hands its own lens — in the order of its prop. */\nexport function probeValuesAt(plane: GroupPlane, x: number): number[] {\n // Down from the group's lightest spot — by exactly as much as that spot is darker along the\n // plane, and even then only a GRADIENT fraction of it. This lets the dark end off on density,\n // without canceling it: the group stays a single material.\n const here = plane.ml + plane.slope * (x - plane.mx);\n const luma = clamp01(plane.base - (plane.base - here) * GRADIENT);\n // The slope doesn't carry over into the lens: the group's is measured in screen dp, while the\n // shader multiplies `u_probeSlope` by a normalized position within the element — different\n // units.\n return [luma, plane.rest[0], plane.rest[1], plane.rest[2], 0, 0, plane.rest[3], plane.rest[4], plane.rest[5]];\n}\n\n/** Whether the group needs to flip ink polarity given the current one (1 light, 0 dark). */\nfunction wantsPolarityChange(decision: GroupDecision, polarity: number): boolean {\n return polarity === 1 ? decision.decisive >= FLIP_LUMA : decision.decisive < RETURN_LUMA;\n}\n\nexport type GroupSink = {\n /** The group estimate has been recomputed: members take their values from it. */\n plane: (plane: GroupPlane | null) => void;\n /** The group flips ink polarity for everyone at once. */\n flip: (polarity: number) => void;\n};\n\nexport type GroupState = {\n report: (\n id: string,\n x: number,\n y: number,\n sample: BackdropSample,\n legibility: number,\n ) => void;\n release: (id: string) => void;\n plane: () => GroupPlane | null;\n polarity: () => number;\n confirmations: () => number;\n};\n\n/** Group state: members, the smoothed estimate, and polarity hysteresis. */\nexport function createGroupState(sink: GroupSink): GroupState {\n const members = new Map<string, GroupMember>();\n let plane: GroupPlane | null = null;\n let pending = 0;\n let polarity = 1;\n\n const measure = (): GroupDecision | null => {\n const next = aggregate([...members.values()]);\n if (!next) {\n pending = 0;\n plane = null;\n sink.plane(null);\n return null;\n }\n plane = smoothPlane(plane, next.plane);\n sink.plane(plane);\n return next.decision;\n };\n\n return {\n report(id, x, y, sample, legibility) {\n members.set(id, { x, y, sample, legibility });\n const decision = measure();\n if (!decision) return;\n if (!wantsPolarityChange(decision, polarity)) {\n pending = 0;\n return;\n }\n pending += 1;\n if (pending < CONFIRMATIONS) return;\n pending = 0;\n polarity = polarity === 1 ? 0 : 1;\n sink.flip(polarity);\n },\n // Only recomputes the estimate: losing a member isn't a backdrop sample and can't count as a\n // polarity confirmation — unmounting the group used to rack up CONFIRMATIONS instantly and\n // trigger a recolor nobody was left to cancel.\n release(id) {\n if (members.delete(id)) measure();\n },\n plane: () => plane,\n polarity: () => polarity,\n confirmations: () => pending,\n };\n}\n","// Android target. AGSL and SkSL are the same language, so `lens-shader.ts`/`surface-shader.ts`\n// already assemble the finished AGSL text as a string (SDF + body via `${VG_SDF}`) — there's\n// nothing to translate. The identity function here fixes the \"input = output\" contract as a\n// target in its own right, symmetric with `targets/glsl.ts`, and guards the native path against\n// an accidental edit in some future refactor.\nexport function toAGSL(shaderSource: string): string {\n return shaderSource;\n}\n"]}
|