vireglass 3.1.1 → 3.2.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/dist/dom.d.cts CHANGED
@@ -73,6 +73,11 @@ type DisplacementState = {
73
73
  * caller that only ever had two does not have to change. */
74
74
  morphs?: readonly MorphShape[];
75
75
  };
76
+ /**
77
+ * The `feDisplacementMap` scale for these optics. The map's pixels are a fraction of it and do not
78
+ * depend on it, so a change of strength alone, such as appear, is this attribute and not a bake.
79
+ */
80
+ declare function displacementScale(optics: VireGlassOptics, geometry: VireGlassGeometry): number;
76
81
  /**
77
82
  * The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.
78
83
  * `buildDisplacementMap` below is a thin DOM wrapper around this.
@@ -437,4 +442,4 @@ type GlassHandle = {
437
442
  };
438
443
  declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
439
444
 
440
- export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
445
+ export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, displacementScale, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
package/dist/dom.d.ts CHANGED
@@ -73,6 +73,11 @@ type DisplacementState = {
73
73
  * caller that only ever had two does not have to change. */
74
74
  morphs?: readonly MorphShape[];
75
75
  };
76
+ /**
77
+ * The `feDisplacementMap` scale for these optics. The map's pixels are a fraction of it and do not
78
+ * depend on it, so a change of strength alone, such as appear, is this attribute and not a bake.
79
+ */
80
+ declare function displacementScale(optics: VireGlassOptics, geometry: VireGlassGeometry): number;
76
81
  /**
77
82
  * The raw pixel buffer, with no canvas involved — the part actually worth unit-testing.
78
83
  * `buildDisplacementMap` below is a thin DOM wrapper around this.
@@ -437,4 +442,4 @@ type GlassHandle = {
437
442
  };
438
443
  declare function attachGlass(el: HTMLElement, opts?: AttachGlassOptions): GlassHandle;
439
444
 
440
- export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
445
+ export { type AttachGlassOptions, type BodyBackdrop, type BodyLayer, type DisplacementMap, type DisplacementState, type EdgePaint, type GlassBody, type GlassGroupHandle, type GlassGroupOptions, type GlassHandle, type GlassMorph, type GroupEntry, type ProbeOptions, RIM_WIDTH_PX, type RenderStats, type RgbColor, type RimAmbient, type ScrollEdgeHandle, type ScrollEdgeOptions, type SpectralMap, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, displacementScale, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
package/dist/dom.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { shadowTint, NO_ACCESSIBILITY, createGroupState, createDeform, elasticAllowed, contrastRimLuma, concentricRadius, scrollEdgeStrength, scrollEdgeStyle, applyAppear, accentTone, accentAmount, applyGlassScale, GLASS_SCALE_DEFAULT, applyAccessibility, raiseIntoGlass } from './chunk-VLDD655U.js';
2
2
  import { ambientFrom, shouldInkBeLight, INK_LIGHT, INK_DARK } from './chunk-JNRZNMJJ.js';
3
3
  import { touchWarp, sceneDistance, sceneGradient, sdfRoundedRect, VIREGLASS_MATERIAL, REST_LIGHT, resolveOptics, refractionStrength } from './chunk-YAN2OK4H.js';
4
- import { shadowOpacity, bevelDp, thicknessDp, rimDp, shadowOpacityFrom, shadowReachDp, halfMinDp, MAX_STRETCH, roundedRectGeometry } from './chunk-Z4FKYY47.js';
4
+ import { shadowOpacity, thicknessDp, bevelDp, rimDp, shadowOpacityFrom, shadowReachDp, halfMinDp, MAX_STRETCH, roundedRectGeometry } from './chunk-Z4FKYY47.js';
5
5
  import { LENS, BODY, RIM, TOUCH, SHADOW, SHADOW_GAP, MEDIUM, SCROLL_EDGE, BEVEL, SPECTRAL, DISPERSION } from './chunk-CPSIY2DZ.js';
6
6
 
7
7
  // src/dom/displacement.ts
@@ -21,13 +21,15 @@ function bevelProfile(t) {
21
21
  const raw = Math.min(t / Math.sqrt(Math.max(1 - t * t * BEVEL.sphere, BEVEL.floor)), BEVEL.slopeMax);
22
22
  return raw / BEVEL.slopeMax;
23
23
  }
24
+ function displacementScale(optics, geometry) {
25
+ return Math.min(optics.refraction * thicknessDp(geometry, optics) * SCALE_GAIN, MAX_SCALE);
26
+ }
24
27
  function renderDisplacementPixels(optics, geometry, dpr, state = {}) {
25
28
  const bevel = bevelDp(geometry, optics);
26
29
  const density = mapDensity(geometry, bevel, dpr);
27
30
  const width = Math.max(1, Math.round(geometry.width * density));
28
31
  const height = Math.max(1, Math.round(geometry.height * density));
29
- const rawScale = optics.refraction * thicknessDp(geometry, optics) * SCALE_GAIN;
30
- const scale = Math.min(rawScale, MAX_SCALE);
32
+ const scale = displacementScale(optics, geometry);
31
33
  const smoothing = state.smoothing ?? 0;
32
34
  const shapes = [state.morph, state.morph2, ...state.morphs ?? []];
33
35
  const data = new Uint8ClampedArray(width * height * 4);
@@ -799,6 +801,9 @@ function getFilterHost(host) {
799
801
  (host instanceof ShadowRoot ? host : host.body).appendChild(svg);
800
802
  return svg;
801
803
  }
804
+ function writeAttr(node, name, value) {
805
+ if (node.getAttribute(name) !== value) node.setAttribute(name, value);
806
+ }
802
807
  function buildFilterElement(id, mapUrl, optics, scale, spectral) {
803
808
  const filter = document.createElementNS(SVG_NS, "filter");
804
809
  filter.setAttribute("id", id);
@@ -884,6 +889,7 @@ function withSpectral(filter, spectral) {
884
889
  product.setAttribute("in2", "hue");
885
890
  product.setAttribute("operator", "arithmetic");
886
891
  product.setAttribute("k1", String(spectral.headroom));
892
+ product.setAttribute("data-vireglass-headroom", String(spectral.headroom));
887
893
  product.setAttribute("k2", "0");
888
894
  product.setAttribute("k3", "0");
889
895
  product.setAttribute("k4", "0");
@@ -941,6 +947,7 @@ function attachGlass(el, opts = {}) {
941
947
  let filterEl = null;
942
948
  let destroyed = false;
943
949
  let mapKey = "";
950
+ let shownGeometry = null;
944
951
  let interim = false;
945
952
  let settling = false;
946
953
  let lastSample = null;
@@ -1003,31 +1010,46 @@ function attachGlass(el, opts = {}) {
1003
1010
  settling = true;
1004
1011
  apply();
1005
1012
  }
1006
- function retarget(f, map, hue) {
1013
+ function retarget(f, map, hue, geometry) {
1007
1014
  const images = f.querySelectorAll("feImage");
1008
1015
  images[0]?.setAttribute("href", map.url);
1009
1016
  if (hue) images[1]?.setAttribute("href", hue.url);
1017
+ shownGeometry = geometry;
1018
+ present(f);
1019
+ }
1020
+ function present(f) {
1021
+ if (!shownGeometry) return;
1022
+ const o = optics();
1023
+ const scale = displacementScale(o, shownGeometry);
1010
1024
  for (const pass of f.querySelectorAll("feDisplacementMap")) {
1011
1025
  const ratio = Number(pass.getAttribute("data-vireglass-ratio") ?? 1);
1012
- pass.setAttribute("scale", String(map.scale * (Number.isFinite(ratio) ? ratio : 1)));
1026
+ writeAttr(pass, "scale", String(scale * (Number.isFinite(ratio) ? ratio : 1)));
1027
+ }
1028
+ const frost = f.querySelector("feGaussianBlur");
1029
+ if (frost) writeAttr(frost, "stdDeviation", String(Math.max(o.blur, 0)));
1030
+ const hue = f.querySelector('feComposite[in2="hue"]');
1031
+ if (hue) {
1032
+ const headroom = Number(hue.getAttribute("data-vireglass-headroom") ?? 1);
1033
+ writeAttr(hue, "k1", String(headroom * appear));
1034
+ writeAttr(hue, "k2", String(1 - appear));
1013
1035
  }
1014
1036
  }
1015
1037
  function requestInterimMap() {
1016
1038
  if (!svgSupported || !filterEl || destroyed) return;
1017
1039
  const geometry = opts.geometry ?? measureGeometry(el);
1018
1040
  if (isEmpty(geometry)) return;
1019
- const opticsNow = optics();
1041
+ const full = settledOptics();
1020
1042
  const key = interimKey(
1021
1043
  geometry.width,
1022
1044
  geometry.height,
1023
1045
  geometry.cornerRadius,
1024
1046
  JSON.stringify([morph?.smoothing, morph?.shape, morph?.shape2, morph?.shapes]),
1025
- `a${appear.toFixed(3)}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}`
1047
+ `${full.refraction}:${full.refractionScale}:${full.bevelDp}`
1026
1048
  );
1027
1049
  let rec = interimMaps.get(key);
1028
1050
  if (!rec) {
1029
1051
  bump("reducedBakes");
1030
- rec = { map: buildDisplacementMap(opticsNow, geometry, Math.min(1, devicePixelRatio()), morphState()), ready: false };
1052
+ rec = { map: buildDisplacementMap(full, geometry, Math.min(1, devicePixelRatio()), morphState()), ready: false, geometry };
1031
1053
  interimMaps.set(key, rec);
1032
1054
  }
1033
1055
  const mine = seq += 1;
@@ -1036,7 +1058,7 @@ function attachGlass(el, opts = {}) {
1036
1058
  const show = () => {
1037
1059
  if (destroyed || filterEl !== forFilter || mine <= shownSeq) return;
1038
1060
  shownSeq = mine;
1039
- retarget(forFilter, record.map, null);
1061
+ retarget(forFilter, record.map, null, record.geometry);
1040
1062
  };
1041
1063
  if (record.ready) {
1042
1064
  show();
@@ -1058,17 +1080,18 @@ function attachGlass(el, opts = {}) {
1058
1080
  wasLight = light;
1059
1081
  const body = opts.body === false ? null : bodyCss(settledOptics(), sample, light ? 1 : 0, accent, appear);
1060
1082
  if (svgSupported) {
1061
- const key = `a${appear.toFixed(3)}|m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${opticsNow.refraction}:${opticsNow.refractionScale}:${opticsNow.bevelDp}:${opticsNow.blur}`;
1083
+ const full = settledOptics();
1084
+ const key = `m${morphKey()}|${geometry.width}x${geometry.height}r${geometry.cornerRadius}@${devicePixelRatio()}:${full.refraction}:${full.refractionScale}:${full.bevelDp}:${full.blur}`;
1062
1085
  if (interim && filterEl) ; else if (isEmpty(geometry)) ; else if (key !== mapKey || !filterEl) {
1063
1086
  const map = cached(`d|${key}`, () => {
1064
1087
  bump("fullBakes");
1065
- return buildDisplacementMap(opticsNow, geometry, devicePixelRatio(), morphState());
1088
+ return buildDisplacementMap(full, geometry, devicePixelRatio(), morphState());
1066
1089
  });
1067
- const hue = hasSpectralEdge(opticsNow) ? cached(`h|${key}`, () => {
1090
+ const hue = hasSpectralEdge(full) ? cached(`h|${key}`, () => {
1068
1091
  bump("fullBakes");
1069
- return buildSpectralMap(opticsNow, geometry, devicePixelRatio());
1092
+ return buildSpectralMap(full, geometry, devicePixelRatio());
1070
1093
  }) : null;
1071
- const signature = filterSignature(opticsNow.blur, opticsNow.ior, opticsNow.iorSpread, !!hue);
1094
+ const signature = filterSignature(full.blur, full.ior, full.iorSpread, !!hue);
1072
1095
  if (settling && filterEl?.getAttribute("data-vireglass-signature") === signature) {
1073
1096
  settling = false;
1074
1097
  const mine = seq += 1;
@@ -1077,21 +1100,23 @@ function attachGlass(el, opts = {}) {
1077
1100
  void Promise.all([decoded(map.url), hue ? decoded(hue.url) : void 0]).then(() => {
1078
1101
  if (destroyed || filterEl !== forFilter || mapKey !== forKey || mine <= shownSeq) return;
1079
1102
  shownSeq = mine;
1080
- retarget(forFilter, map, hue);
1103
+ retarget(forFilter, map, hue, geometry);
1081
1104
  });
1082
1105
  } else {
1083
1106
  settling = false;
1084
1107
  invalidate();
1085
1108
  const defs = getFilterHost(host).querySelector("defs");
1086
- const next = buildFilterElement(id, map.url, opticsNow, map.scale, hue);
1109
+ const next = buildFilterElement(id, map.url, full, map.scale, hue);
1087
1110
  next.setAttribute("data-vireglass-signature", signature);
1088
1111
  if (filterEl?.parentNode) defs.replaceChild(next, filterEl);
1089
1112
  else defs.appendChild(next);
1090
1113
  bump("filterSwaps");
1091
1114
  filterEl = next;
1115
+ shownGeometry = geometry;
1092
1116
  }
1093
1117
  mapKey = key;
1094
1118
  }
1119
+ if (filterEl) present(filterEl);
1095
1120
  el.style.setProperty("backdrop-filter", `url(#${id})`);
1096
1121
  el.style.setProperty("-webkit-backdrop-filter", `url(#${id})`);
1097
1122
  } else {
@@ -1292,7 +1317,6 @@ function attachGlass(el, opts = {}) {
1292
1317
  if (next === appear) return;
1293
1318
  appear = next;
1294
1319
  apply();
1295
- if (interim) requestInterimMap();
1296
1320
  },
1297
1321
  setAccent(next) {
1298
1322
  accent = next ?? void 0;
@@ -1342,6 +1366,6 @@ function attachGlass(el, opts = {}) {
1342
1366
  return handle;
1343
1367
  }
1344
1368
 
1345
- export { RIM_WIDTH_PX, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
1369
+ export { RIM_WIDTH_PX, ambientLuma, attachGlass, attachScrollEdge, bodyLayer, boxShadowCss, buildDisplacementMap, buildSpectralMap, cached, clearMapCache, compositeLayers, contrastRimCss, createGlassGroup, displacementScale, hasSpectralEdge, lightConicAngle, mapCacheSize, paintFor, parseColor, probeBackdrop, renderDisplacementPixels, renderSpectralPixels, renderStats, resetRenderStats, resetSupportCache, resolveBody, rimGradientCss, rimLineAlpha, rimLobe, rimStrength, shadowAlphaFrom, statsFromSamples, supportsBackdropFilter, supportsSvgBackdropFilter, systemAccessibility, watchAccessibility, withPresence };
1346
1370
  //# sourceMappingURL=dom.js.map
1347
1371
  //# sourceMappingURL=dom.js.map