@edinstvo/glass 0.1.0-beta.2 → 0.1.0-beta.3

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/README.md CHANGED
@@ -1,46 +1,16 @@
1
- <div align="center">
1
+ <img src="logo.png" alt="Edinstvo Glass" width="148">
2
2
 
3
- <h1>@edinstvo/glass</h1>
3
+ Edinstvo Glass is a simple library for real glass on the web.
4
4
 
5
- <p><b>Real glass for the web. One material, the same on macOS and Windows.</b></p>
5
+ At its core is a WebGL lens that bends light through a curved edge, splits colours and frosts what is behind it, the same on macOS and Windows. It comes as one web component with no dependencies.
6
6
 
7
- <p>
8
- A WebGL lens with refraction, dispersion, frost and light,<br>
9
- wrapped in a single web component that works in any framework.
10
- </p>
7
+ ## Documentation
11
8
 
12
- <p>
13
- <a href="https://www.npmjs.com/package/@edinstvo/glass"><img src="https://img.shields.io/npm/v/@edinstvo/glass?style=for-the-badge&labelColor=000000&color=1a1a1a&label=npm" alt="npm version"></a>
14
- <img src="https://img.shields.io/badge/WebGL-2-1a1a1a?style=for-the-badge&labelColor=000000&logo=webgl&logoColor=white" alt="WebGL 2">
15
- <img src="https://img.shields.io/badge/dependencies-0-1a1a1a?style=for-the-badge&labelColor=000000" alt="Zero dependencies">
16
- <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-1a1a1a?style=for-the-badge&labelColor=000000" alt="MIT license"></a>
17
- </p>
9
+ See the full documentation, with a playground and examples, at [edinstvoai.github.io/edinstvo-glass-documentation-](https://edinstvoai.github.io/edinstvo-glass-documentation-/).
18
10
 
19
- <p>
20
- <a href="#install"><b>Install</b></a>
21
- &nbsp;·&nbsp;
22
- <a href="#material">Material</a>
23
- &nbsp;·&nbsp;
24
- <a href="#backdrop">Backdrop</a>
25
- &nbsp;·&nbsp;
26
- <a href="#limits">Limits</a>
27
- </p>
11
+ ## npm
28
12
 
29
- </div>
30
-
31
- <br>
32
-
33
- ## Principles
34
-
35
- > **Optics, not blur.** Light bends through a curved edge by Snell's law, so glass behaves like glass
36
- > instead of a tinted rectangle.
37
- >
38
- > **Quiet by default.** A frame is drawn only when something changes. Nothing on screen moves, nothing
39
- > runs on the GPU.
40
- >
41
- > **One context.** Every element on the page shares a single WebGL context, however many there are.
42
-
43
- ## Install
13
+ To install from npm:
44
14
 
45
15
  ```bash
46
16
  npm i @edinstvo/glass
@@ -51,118 +21,37 @@ npm i @edinstvo/glass
51
21
  import "@edinstvo/glass/define";
52
22
  </script>
53
23
 
54
- <edinstvo-glass frost="0.4" refraction="0.5">
55
- Hello
56
- </edinstvo-glass>
57
- ```
58
-
59
- The corner radius comes from CSS `border-radius`, the size from your layout. Everything else is optional.
60
-
61
- Not a fan of custom elements? Attach glass to any node:
62
-
63
- ```js
64
- import { attachGlass } from "@edinstvo/glass";
65
-
66
- const glass = attachGlass(element, { material: { frost: 0.7 } });
67
- glass.set({ material: { frost: 0.4 } });
68
- glass.destroy();
69
- ```
70
-
71
- ## Material
72
-
73
- There are no types of glass, only settings. Set anything with an attribute, a `--glass-*` CSS variable or the `material` property. The defaults are tuned against the system glass on macOS, pixel by pixel.
74
-
75
- | Attribute | Range | What it does |
76
- |---|---|---|
77
- | `refraction` | 0 to 1 | How hard the edge bends what is behind it |
78
- | `depth` | 0 to 96 px | Width of the curved edge |
79
- | `splay` | 0 to 1 | Spreads the curve from the edge towards the centre |
80
- | `dispersion` | 0 to 1 | How far colours split wherever the glass bends |
81
- | `frost` | 0 to 1 | Matte surface, a true gaussian up to 20 px |
82
- | `transparency` | 0 to 1 | How much of the backdrop survives the tint |
83
- | `tint` | any CSS colour | Glass colour. `auto` follows the theme |
84
- | `lift` | 0 to 1 | Brightens everything behind the glass |
85
- | `light` | 0 to 1 | Shading across the curve, bright towards the light and dark away from it |
86
- | `rim` | 0 to 1 | Thin light line along the edge, brightest in line with the light |
87
- | `glint` | 0 to 1 | Sharp highlight along the edge. Off in every preset |
88
- | `light-angle` | -180 to 180° | Where the light comes from. 0 is the top |
89
- | `bloom` | 0 to 1 | Glow inside the glass and around it |
90
-
91
- ## Motion
92
-
93
- Change an element's size or position in CSS and the glass flows there with a spring, overshoot included.
94
- Each of these is its own setting, on a group or on a single child. `prefers-reduced-motion` turns them all off.
95
-
96
- | Attribute | Range | What it does |
97
- |---|---|---|
98
- | `morph` | 0 to 1 | Softness of the flow. 0 jumps straight to the new shape |
99
- | `jelly` | 0 to 1 | Stretch while moving and under a drag |
100
- | `press` | 0 to 1 | How much the glass swells when held |
101
- | `glow` | 0 to 1 | Light that spreads from under the finger |
102
- | `follow` | 0 to 1 | How far the light chases the pointer |
103
- | `merge` | 0 to 64 px | Melts this element into others that have it too. 0 stays separate |
104
-
105
- ### Merge
106
-
107
- Merging is opt-in, per element. Give `merge` to the pieces that should become one shape: they melt together when they get close and pull apart like liquid. Everything else in the group stays separate.
108
-
109
- ```html
110
- <edinstvo-glass-group>
111
- <edinstvo-glass merge="28"></edinstvo-glass>
112
- <edinstvo-glass merge="28"></edinstvo-glass>
113
- <edinstvo-glass></edinstvo-glass>
114
- </edinstvo-glass-group>
24
+ <edinstvo-glass frost="0.4" refraction="0.5">Hello</edinstvo-glass>
115
25
  ```
116
26
 
117
- Up to 64 merged shapes per group, all drawn in one pass. Pieces without `merge` are bodies of their own and slide over the rest. `merge` on the group sets it for every child, `merge="0"` on a child opts out.
27
+ ## Exports
118
28
 
119
- ### Appear
29
+ - `@edinstvo/glass` - `attachGlass`, the element classes, defaults and ranges of every setting.
30
+ - `@edinstvo/glass/define` - Registers `edinstvo-glass` and `edinstvo-glass-group`.
31
+ - `@edinstvo/glass/glass.css` - Base materials on `backdrop-filter`, for pages without JavaScript or a GPU.
120
32
 
121
- Add `appear` to materialise on load, or call `show()` and `hide()`. Both return a promise.
33
+ ## Contributing
122
34
 
123
- ## Layers
35
+ Edinstvo Glass is open source and we appreciate issue reports and pull requests.
124
36
 
125
- Glass sees the glass under it. `layer` picks who is on top, higher wins. It is `z-index` with a shorter name, so plain `z-index` works too. On a tie the later element in the document is on top.
37
+ ### Setting up for development
126
38
 
127
- ```html
128
- <edinstvo-glass layer="1"></edinstvo-glass>
129
- <edinstvo-glass layer="2"></edinstvo-glass>
130
- ```
39
+ Initialize the repo:
131
40
 
132
- ## Backdrop
133
-
134
- WebGL can't read the pixels of a page, so glass needs to be told what is behind it.
135
- With `source="auto"` it looks for itself: the nearest `<img>`, `<video>`, `<canvas>`, CSS `url()` background
136
- or solid colour under the element.
137
-
138
- ```html
139
- <edinstvo-glass source="#scene"></edinstvo-glass>
140
- ```
141
-
142
- ```js
143
- glass.source = canvas;
144
- glass.invalidate();
41
+ ```bash
42
+ git clone https://github.com/EdinstvoAI/edinstvo-glass.git
43
+ cd edinstvo-glass
44
+ npm ci
145
45
  ```
146
46
 
147
- A playing video updates on its own. For a canvas you draw on, call `invalidate()` after drawing or set `live`.
148
-
149
- ## Plain CSS
150
-
151
- No JavaScript, or no GPU? `@edinstvo/glass/glass.css` gives you `.glass`, `.glass-clear` and `.glass-frost`
152
- on top of `backdrop-filter`. The element falls back to the same look by itself when WebGL is missing.
153
-
154
- ## Limits
155
-
156
- - Text and regular DOM behind the glass aren't refracted, only the sources listed above. Draw them to a canvas if you need them.
157
- - CSS gradients aren't read yet. Glass skips them and looks further down the stack.
158
- - Cross-origin images need CORS headers, otherwise that element falls back to CSS.
159
-
160
- ## Development
47
+ Run the bench:
161
48
 
162
49
  ```bash
163
50
  npm run demo
164
51
  ```
165
52
 
53
+ Test:
54
+
166
55
  ```bash
167
56
  npm test
168
57
  ```
package/dist/geometry.js CHANGED
@@ -28,6 +28,9 @@ export function softPeak(halfW, halfH, radius) {
28
28
  const a = halfW + radius;
29
29
  const b = halfH + radius;
30
30
  const lo = Math.min(a, b);
31
- return lo * (1 + (lo / Math.max(a, b)) ** 2.7) ** (-1 / 2.7) - radius;
31
+ const soft = lo * (1 + (lo / Math.max(a, b)) ** 2.7) ** (-1 / 2.7) - radius;
32
+ const half = Math.min(halfW, halfH);
33
+ const round = half ? radius / half : 0;
34
+ return soft + (half - soft) * round;
32
35
  }
33
36
  //# sourceMappingURL=geometry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../src/geometry.ts"],"names":[],"mappings":"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"}
package/dist/shader.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export declare const vertex = "#version 300 es\nvoid main() {\n vec2 p = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);\n gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n}";
2
- export declare const fragment = "#version 300 es\nprecision highp float;\n\nconst int MAX_SHAPES = 64;\nconst float SOFTNESS = 2.7;\n\nuniform sampler2D uBackdrop, uFrosted;\nuniform vec4 uBoxes[MAX_SHAPES];\nuniform vec2 uForms[MAX_SHAPES];\nuniform int uCount;\nuniform vec2 uCanvas, uUvOrigin, uUvPerPx, uTexSize, uLightDir;\nuniform vec3 uTint, uTouch;\nuniform float uViewY, uPad, uDpr, uPeak, uAppear, uLight, uTransparency, uRefraction, uDepth, uDispersion, uFrost, uSplay, uBloom, uGlint, uRim, uLift;\nout vec4 outColor;\n\nfloat roundedBox(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\nfloat softMin(float a, float b) {\n float lo = min(a, b);\n return lo * pow(1.0 + pow(lo / max(a, b), SOFTNESS), -1.0 / SOFTNESS);\n}\n\nfloat blend(float a, float b, float k) {\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - h * h * k * 0.25;\n}\n\n// \u2500\u2500 x is the distance to the merged outline, y how deep the point sits inside it, without creases\nvec2 field(vec2 p) {\n float joined = 1e5;\n float apart = 1e5;\n float inset = -1e5;\n for (int i = 0; i < MAX_SHAPES; i++) {\n if (i >= uCount) break;\n vec2 c = p - uBoxes[i].xy;\n vec2 b = uBoxes[i].zw;\n float r = uForms[i].x;\n float own = roundedBox(c, b, r);\n if (uForms[i].y > 0.0) joined = blend(joined, own, uForms[i].y);\n else apart = min(apart, own);\n if (own < 0.0) {\n vec2 edges = max(b - abs(c), 0.0) + r + 0.001;\n inset = max(inset, softMin(edges.x, edges.y) - r);\n }\n }\n float d = min(joined, apart);\n return vec2(d, max(inset, -d));\n}\n\nvec2 toUv(vec2 px) {\n return uUvOrigin + px * uUvPerPx;\n}\n\nvec3 pick(vec2 px, float lod) {\n return uFrost > 0.0 ? texture(uFrosted, toUv(px)).rgb : textureLod(uBackdrop, toUv(px), lod).rgb;\n}\n\nvoid main() {\n vec2 px = vec2(gl_FragCoord.x, uCanvas.y - (gl_FragCoord.y - uViewY));\n vec2 f = field(px);\n float d = f.x;\n float texels = max(uUvPerPx.x * uTexSize.x, uUvPerPx.y * uTexSize.y);\n float haloLod = log2(max(28.0 * uDpr * texels, 1.0));\n vec3 halo = textureLod(uBackdrop, toUv(px), haloLod).rgb;\n\n float mask = 1.0 - smoothstep(-0.75, 0.75, d);\n float spill = exp(-max(d, 0.0) / (uPad * 0.3)) * uBloom * 0.4 * uLight;\n vec3 spillColor = mix(halo, vec3(1.0), 0.6);\n\n float band = min(mix(max(uDepth * uDpr, 1.0), uPeak, uSplay * uSplay), uPeak);\n float s = 1.0 - clamp(f.y / band, 0.0, 1.0);\n float height = sqrt(max(1.0 - s * s, 0.0));\n float e = uDpr;\n vec2 slope = vec2(field(px - vec2(e, 0.0)).y - field(px + vec2(e, 0.0)).y, field(px - vec2(0.0, e)).y - field(px + vec2(0.0, e)).y);\n vec2 g = slope / max(length(slope), 0.0001);\n vec3 n = normalize(vec3(g * s * s / sqrt(1.02 - s * s), 1.0));\n\n vec3 ray = refract(vec3(0.0, 0.0, -1.0), n, 1.0 / 1.5);\n vec2 shift = ray.xy / max(-ray.z, 0.5) * band * (0.35 + height) * uRefraction * 1.2 * uAppear;\n\n vec2 fromTouch = px - uTouch.xy;\n float reach = 90.0 * uDpr;\n float touch = exp(-dot(fromTouch, fromTouch) / (reach * reach)) * uTouch.z;\n shift -= fromTouch * touch * 0.12;\n\n vec2 at = px + shift;\n float squeeze = log2(max(max(length(dFdx(at)), length(dFdy(at))) * texels, 1.0));\n float k = 0.04 + uDispersion * 0.3;\n vec3 col = vec3(\n pick(at - shift * k, squeeze).r,\n pick(at, squeeze).g,\n pick(at + shift * k, squeeze).b\n );\n\n col = mix(vec3(dot(col, vec3(0.2126, 0.7152, 0.0722))), col, 1.08);\n col = mix(uTint, col, uTransparency);\n col = col * (1.0 + uLift) + uLift * 0.12;\n col += halo * uBloom * 0.22 * s;\n\n float facing = dot(n.xy, uLightDir);\n vec2 centered = (px - uCanvas * 0.5) / (uCanvas * 0.5);\n col += uLight * (max(facing, 0.0) * 0.3 + dot(centered, uLightDir) * 0.03);\n col *= 1.0 - uLight * max(-facing, 0.0) * 0.2;\n\n float toward = dot(g, uLightDir);\n col += uGlint * pow(s, 5.0) * (pow(max(toward, 0.0), 6.0) + pow(max(-toward, 0.0), 6.0) * 0.4);\n\n float line = smoothstep(-1.6 * uDpr, -0.6 * uDpr, d);\n col += uRim * line * (0.18 + 0.82 * toward * toward);\n col += touch * (0.16 + halo * 0.3);\n\n vec3 inside = clamp(col, 0.0, 1.0) * mask;\n float rest = (1.0 - mask) * spill;\n outColor = vec4(inside + spillColor * rest, mask + rest) * uAppear;\n}";
2
+ export declare const fragment = "#version 300 es\nprecision highp float;\n\nconst int MAX_SHAPES = 64;\nconst float SOFTNESS = 2.7;\n\nuniform sampler2D uBackdrop, uFrosted;\nuniform vec4 uBoxes[MAX_SHAPES];\nuniform vec2 uForms[MAX_SHAPES];\nuniform int uCount;\nuniform vec2 uCanvas, uUvOrigin, uUvPerPx, uTexSize, uLightDir;\nuniform vec3 uTint, uTouch;\nuniform float uViewY, uPad, uDpr, uPeak, uAppear, uLight, uTransparency, uRefraction, uDepth, uDispersion, uFrost, uSplay, uBloom, uGlint, uRim, uLift;\nout vec4 outColor;\n\nfloat roundedBox(vec2 p, vec2 b, float r) {\n vec2 q = abs(p) - b + r;\n return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;\n}\n\nfloat softMin(float a, float b) {\n float lo = min(a, b);\n return lo * pow(1.0 + pow(lo / max(a, b), SOFTNESS), -1.0 / SOFTNESS);\n}\n\nfloat blend(float a, float b, float k) {\n float h = max(k - abs(a - b), 0.0) / k;\n return min(a, b) - h * h * k * 0.25;\n}\n\n// \u2500\u2500 x is the distance to the merged outline, y how deep the point sits inside it, without creases\nvec2 field(vec2 p) {\n float joined = 1e5;\n float apart = 1e5;\n float inset = -1e5;\n for (int i = 0; i < MAX_SHAPES; i++) {\n if (i >= uCount) break;\n vec2 c = p - uBoxes[i].xy;\n vec2 b = uBoxes[i].zw;\n float r = uForms[i].x;\n float own = roundedBox(c, b, r);\n if (uForms[i].y > 0.0) joined = blend(joined, own, uForms[i].y);\n else apart = min(apart, own);\n if (own < 0.0) {\n vec2 edges = max(b - abs(c), 0.0) + r + 0.001;\n inset = max(inset, mix(softMin(edges.x, edges.y) - r, -own, r / min(b.x, b.y)));\n }\n }\n float d = min(joined, apart);\n return vec2(d, max(inset, -d));\n}\n\nvec2 toUv(vec2 px) {\n return uUvOrigin + px * uUvPerPx;\n}\n\nvec3 pick(vec2 px, float lod) {\n return uFrost > 0.0 ? texture(uFrosted, toUv(px)).rgb : textureLod(uBackdrop, toUv(px), lod).rgb;\n}\n\nvoid main() {\n vec2 px = vec2(gl_FragCoord.x, uCanvas.y - (gl_FragCoord.y - uViewY));\n vec2 f = field(px);\n float d = f.x;\n float texels = max(uUvPerPx.x * uTexSize.x, uUvPerPx.y * uTexSize.y);\n float haloLod = log2(max(28.0 * uDpr * texels, 1.0));\n vec3 halo = textureLod(uBackdrop, toUv(px), haloLod).rgb;\n\n float mask = 1.0 - smoothstep(-0.75, 0.75, d);\n float spill = exp(-max(d, 0.0) / (uPad * 0.3)) * uBloom * 0.4 * uLight;\n vec3 spillColor = mix(halo, vec3(1.0), 0.6);\n\n float band = min(mix(max(uDepth * uDpr, 1.0), uPeak, uSplay * uSplay), uPeak);\n float s = 1.0 - clamp(f.y / band, 0.0, 1.0);\n float height = sqrt(max(1.0 - s * s, 0.0));\n float e = uDpr;\n vec2 slope = vec2(field(px - vec2(e, 0.0)).y - field(px + vec2(e, 0.0)).y, field(px - vec2(0.0, e)).y - field(px + vec2(0.0, e)).y);\n vec2 g = slope / max(length(slope), 0.0001);\n vec3 n = normalize(vec3(g * s * s / sqrt(1.02 - s * s), 1.0));\n\n vec3 ray = refract(vec3(0.0, 0.0, -1.0), n, 1.0 / 1.5);\n vec2 shift = ray.xy / max(-ray.z, 0.5) * band * (0.35 + height) * uRefraction * 1.2 * uAppear;\n\n vec2 fromTouch = px - uTouch.xy;\n float reach = 90.0 * uDpr;\n float touch = exp(-dot(fromTouch, fromTouch) / (reach * reach)) * uTouch.z;\n shift -= fromTouch * touch * 0.12;\n\n vec2 at = px + shift;\n float squeeze = log2(max(max(length(dFdx(at)), length(dFdy(at))) * texels, 1.0));\n float k = 0.04 + uDispersion * 0.3;\n vec3 col = vec3(\n pick(at - shift * k, squeeze).r,\n pick(at, squeeze).g,\n pick(at + shift * k, squeeze).b\n );\n\n col = mix(vec3(dot(col, vec3(0.2126, 0.7152, 0.0722))), col, 1.08);\n col = mix(uTint, col, uTransparency);\n col = col * (1.0 + uLift) + uLift * 0.12;\n col += halo * uBloom * 0.22 * s;\n\n float facing = dot(n.xy, uLightDir);\n vec2 centered = (px - uCanvas * 0.5) / (uCanvas * 0.5);\n col += uLight * (max(facing, 0.0) * 0.3 + dot(centered, uLightDir) * 0.03);\n col *= 1.0 - uLight * max(-facing, 0.0) * 0.2;\n\n float toward = dot(g, uLightDir);\n col += uGlint * pow(s, 5.0) * (pow(max(toward, 0.0), 6.0) + pow(max(-toward, 0.0), 6.0) * 0.4);\n\n float line = smoothstep(-1.6 * uDpr, -0.6 * uDpr, d);\n col += uRim * line * (0.18 + 0.82 * toward * toward);\n col += touch * (0.16 + halo * 0.3);\n\n vec3 inside = clamp(col, 0.0, 1.0) * mask;\n float rest = (1.0 - mask) * spill;\n outColor = vec4(inside + spillColor * rest, mask + rest) * uAppear;\n}";
3
3
  export declare const blurFragment = "#version 300 es\nprecision highp float;\n\nuniform sampler2D uSource;\nuniform vec2 uStep, uInvSize;\nuniform float uLod;\nout vec4 outColor;\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy * uInvSize;\n vec3 sum = vec3(0.0);\n float total = 0.0;\n for (int i = -8; i <= 8; i++) {\n float x = float(i);\n float weight = exp(-x * x / 18.0);\n sum += textureLod(uSource, uv + uStep * x, uLod).rgb * weight;\n total += weight;\n }\n outColor = vec4(sum / total, 1.0);\n}";
package/dist/shader.js CHANGED
@@ -48,7 +48,7 @@ vec2 field(vec2 p) {
48
48
  else apart = min(apart, own);
49
49
  if (own < 0.0) {
50
50
  vec2 edges = max(b - abs(c), 0.0) + r + 0.001;
51
- inset = max(inset, softMin(edges.x, edges.y) - r);
51
+ inset = max(inset, mix(softMin(edges.x, edges.y) - r, -own, r / min(b.x, b.y)));
52
52
  }
53
53
  }
54
54
  float d = min(joined, apart);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edinstvo/glass",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.3",
4
4
  "description": "Liquid glass for the web: one WebGL material that looks the same on macOS and Windows.",
5
5
  "license": "MIT",
6
6
  "type": "module",