@edinstvo/glass 0.0.0-stage → 0.1.0-beta.1
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 +21 -0
- package/README.md +163 -2
- package/css/glass.css +33 -0
- package/dist/backdrop.d.ts +11 -0
- package/dist/backdrop.js +104 -0
- package/dist/backdrop.js.map +1 -0
- package/dist/color.d.ts +4 -0
- package/dist/color.js +29 -0
- package/dist/color.js.map +1 -0
- package/dist/define.d.ts +1 -0
- package/dist/define.js +3 -0
- package/dist/define.js.map +1 -0
- package/dist/element.d.ts +34 -0
- package/dist/element.js +166 -0
- package/dist/element.js.map +1 -0
- package/dist/geometry.d.ts +18 -0
- package/dist/geometry.js +33 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +61 -0
- package/dist/interaction.js +184 -0
- package/dist/interaction.js.map +1 -0
- package/dist/material.d.ts +22 -0
- package/dist/material.js +37 -0
- package/dist/material.js.map +1 -0
- package/dist/renderer.d.ts +49 -0
- package/dist/renderer.js +237 -0
- package/dist/renderer.js.map +1 -0
- package/dist/shader.d.ts +3 -0
- package/dist/shader.js +144 -0
- package/dist/shader.js.map +1 -0
- package/dist/surface.d.ts +64 -0
- package/dist/surface.js +370 -0
- package/dist/surface.js.map +1 -0
- package/package.json +52 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Makar K
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,164 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<h1>@edinstvo/glass</h1>
|
|
4
|
+
|
|
5
|
+
<p><b>Real glass for the web. One material, the same on macOS and Windows.</b></p>
|
|
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>
|
|
11
|
+
|
|
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>
|
|
18
|
+
|
|
19
|
+
<p>
|
|
20
|
+
<a href="#install"><b>Install</b></a>
|
|
21
|
+
·
|
|
22
|
+
<a href="#material">Material</a>
|
|
23
|
+
·
|
|
24
|
+
<a href="#backdrop">Backdrop</a>
|
|
25
|
+
·
|
|
26
|
+
<a href="#limits">Limits</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
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
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm i @edinstvo/glass
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<script type="module">
|
|
51
|
+
import "@edinstvo/glass/define";
|
|
52
|
+
</script>
|
|
53
|
+
|
|
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>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Up to 8 shapes per group, all drawn in one pass. `merge` on the group sets it for every child, `merge="0"` on a child opts out.
|
|
118
|
+
|
|
119
|
+
### Appear
|
|
120
|
+
|
|
121
|
+
Add `appear` to materialise on load, or call `show()` and `hide()`. Both return a promise.
|
|
122
|
+
|
|
123
|
+
## Backdrop
|
|
124
|
+
|
|
125
|
+
WebGL can't read the pixels of a page, so glass needs to be told what is behind it.
|
|
126
|
+
With `source="auto"` it looks for itself: the nearest `<img>`, `<video>`, `<canvas>`, CSS `url()` background
|
|
127
|
+
or solid colour under the element.
|
|
128
|
+
|
|
129
|
+
```html
|
|
130
|
+
<edinstvo-glass source="#scene"></edinstvo-glass>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
glass.source = canvas;
|
|
135
|
+
glass.invalidate();
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
A playing video updates on its own. For a canvas you draw on, call `invalidate()` after drawing or set `live`.
|
|
139
|
+
|
|
140
|
+
## Plain CSS
|
|
141
|
+
|
|
142
|
+
No JavaScript, or no GPU? `@edinstvo/glass/glass.css` gives you `.glass`, `.glass-clear` and `.glass-frost`
|
|
143
|
+
on top of `backdrop-filter`. The element falls back to the same look by itself when WebGL is missing.
|
|
144
|
+
|
|
145
|
+
## Limits
|
|
146
|
+
|
|
147
|
+
- Glass sees other glass under it. Later in the document means on top, `z-index` is not read yet.
|
|
148
|
+
- Text and regular DOM behind the glass aren't refracted, only the sources listed above. Draw them to a canvas if you need them.
|
|
149
|
+
- CSS gradients aren't read yet. Glass skips them and looks further down the stack.
|
|
150
|
+
- Cross-origin images need CORS headers, otherwise that element falls back to CSS.
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run demo
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm test
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
[MIT](LICENSE)
|
package/css/glass.css
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--glass-radius: 24px;
|
|
3
|
+
--glass-shadow: 0 8px 32px rgb(0 0 0 / .1);
|
|
4
|
+
--glass-fallback: rgb(249 249 249 / .22);
|
|
5
|
+
--glass-edge: rgb(255 255 255 / .5);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
@media (prefers-color-scheme: dark) {
|
|
9
|
+
:root:not([data-theme="light"]) {
|
|
10
|
+
--glass-shadow: 0 8px 32px rgb(0 0 0 / .4);
|
|
11
|
+
--glass-fallback: rgb(28 28 30 / .55);
|
|
12
|
+
--glass-edge: rgb(255 255 255 / .22);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:root[data-theme="dark"] {
|
|
17
|
+
--glass-shadow: 0 8px 32px rgb(0 0 0 / .4);
|
|
18
|
+
--glass-fallback: rgb(28 28 30 / .55);
|
|
19
|
+
--glass-edge: rgb(255 255 255 / .22);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.glass,
|
|
23
|
+
.glass-clear,
|
|
24
|
+
.glass-frost {
|
|
25
|
+
border-radius: var(--glass-radius);
|
|
26
|
+
box-shadow: var(--glass-shadow), inset 0 0 0 .5px var(--glass-edge);
|
|
27
|
+
background: var(--glass-fallback);
|
|
28
|
+
-webkit-backdrop-filter: blur(var(--glass-blur, 12px)) saturate(1.6);
|
|
29
|
+
backdrop-filter: blur(var(--glass-blur, 12px)) saturate(1.6);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.glass-clear { --glass-blur: 2px; background: transparent; }
|
|
33
|
+
.glass-frost { --glass-blur: 28px; }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Box } from "./geometry.js";
|
|
2
|
+
export type GlassImage = HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | OffscreenCanvas;
|
|
3
|
+
export type GlassSource = "auto" | string | GlassImage;
|
|
4
|
+
export interface Backdrop {
|
|
5
|
+
image: GlassImage;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
map: Box;
|
|
9
|
+
live: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveBackdrop(host: HTMLElement, rect: DOMRect, source: GlassSource, onReady: () => void): Backdrop | null;
|
package/dist/backdrop.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { parseColor, prefersDark } from "./color.js";
|
|
2
|
+
import { fitBox } from "./geometry.js";
|
|
3
|
+
const viewport = () => ({ x: 0, y: 0, w: innerWidth, h: innerHeight });
|
|
4
|
+
const images = new Map();
|
|
5
|
+
const solids = new Map();
|
|
6
|
+
function naturalSize(image) {
|
|
7
|
+
if (image instanceof HTMLImageElement)
|
|
8
|
+
return image.complete ? [image.naturalWidth, image.naturalHeight] : [0, 0];
|
|
9
|
+
if (image instanceof HTMLVideoElement)
|
|
10
|
+
return image.readyState >= 2 ? [image.videoWidth, image.videoHeight] : [0, 0];
|
|
11
|
+
return [image.width, image.height];
|
|
12
|
+
}
|
|
13
|
+
function whenReady(image, onReady) {
|
|
14
|
+
if (image instanceof HTMLImageElement)
|
|
15
|
+
image.addEventListener("load", onReady, { once: true });
|
|
16
|
+
if (image instanceof HTMLVideoElement)
|
|
17
|
+
image.addEventListener("loadeddata", onReady, { once: true });
|
|
18
|
+
}
|
|
19
|
+
function solid(color) {
|
|
20
|
+
let canvas = solids.get(color);
|
|
21
|
+
if (!canvas) {
|
|
22
|
+
canvas = document.createElement("canvas");
|
|
23
|
+
canvas.width = canvas.height = 1;
|
|
24
|
+
const context = canvas.getContext("2d");
|
|
25
|
+
context.fillStyle = color;
|
|
26
|
+
context.fillRect(0, 0, 1, 1);
|
|
27
|
+
solids.set(color, canvas);
|
|
28
|
+
}
|
|
29
|
+
return { image: canvas, width: 1, height: 1, map: viewport(), live: false };
|
|
30
|
+
}
|
|
31
|
+
function fromImage(image, onReady) {
|
|
32
|
+
const [width, height] = naturalSize(image);
|
|
33
|
+
if (!width || !height) {
|
|
34
|
+
whenReady(image, onReady);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
let map = viewport();
|
|
38
|
+
if (image instanceof Element && image.isConnected) {
|
|
39
|
+
const rect = image.getBoundingClientRect();
|
|
40
|
+
const fit = getComputedStyle(image).objectFit;
|
|
41
|
+
if (rect.width && rect.height)
|
|
42
|
+
map = fitBox({ x: rect.left, y: rect.top, w: rect.width, h: rect.height }, width, height, image instanceof HTMLCanvasElement && fit === "fill" ? "fill" : fit);
|
|
43
|
+
}
|
|
44
|
+
const live = image instanceof HTMLVideoElement ? !image.paused : image instanceof HTMLCanvasElement || image instanceof OffscreenCanvas;
|
|
45
|
+
return { image, width, height, map, live };
|
|
46
|
+
}
|
|
47
|
+
function loadImage(url, onReady) {
|
|
48
|
+
let image = images.get(url);
|
|
49
|
+
if (!image) {
|
|
50
|
+
image = new Image();
|
|
51
|
+
image.crossOrigin = "anonymous";
|
|
52
|
+
image.src = url;
|
|
53
|
+
images.set(url, image);
|
|
54
|
+
}
|
|
55
|
+
if (!image.complete)
|
|
56
|
+
image.addEventListener("load", onReady, { once: true });
|
|
57
|
+
return image;
|
|
58
|
+
}
|
|
59
|
+
function fromBackground(element, onReady) {
|
|
60
|
+
const style = getComputedStyle(element);
|
|
61
|
+
const url = /url\(["']?(.+?)["']?\)/.exec(style.backgroundImage)?.[1];
|
|
62
|
+
if (url) {
|
|
63
|
+
const image = loadImage(url, onReady);
|
|
64
|
+
if (!image.complete || !image.naturalWidth)
|
|
65
|
+
return null;
|
|
66
|
+
const rect = element.getBoundingClientRect();
|
|
67
|
+
const page = element === document.body || element === document.documentElement;
|
|
68
|
+
const box = style.backgroundAttachment === "fixed" || page ? viewport() : { x: rect.left, y: rect.top, w: rect.width, h: rect.height };
|
|
69
|
+
const fit = style.backgroundSize === "cover" ? "cover" : style.backgroundSize === "contain" ? "contain" : style.backgroundSize === "100% 100%" ? "fill" : "none";
|
|
70
|
+
return { image, width: image.naturalWidth, height: image.naturalHeight, map: fitBox(box, image.naturalWidth, image.naturalHeight, fit), live: false };
|
|
71
|
+
}
|
|
72
|
+
if (parseColor(style.backgroundColor)[3] > 0.99)
|
|
73
|
+
return solid(style.backgroundColor);
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
function discover(host, rect, onReady) {
|
|
77
|
+
const stack = document.elementsFromPoint(rect.left + rect.width / 2, rect.top + rect.height / 2);
|
|
78
|
+
for (const element of stack) {
|
|
79
|
+
if (element === host || host.contains(element) || element.hasAttribute("data-engine"))
|
|
80
|
+
continue;
|
|
81
|
+
if (element instanceof HTMLImageElement || element instanceof HTMLCanvasElement || element instanceof HTMLVideoElement) {
|
|
82
|
+
const found = fromImage(element, onReady);
|
|
83
|
+
if (found)
|
|
84
|
+
return found;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const found = fromBackground(element, onReady);
|
|
88
|
+
if (found !== undefined)
|
|
89
|
+
return found;
|
|
90
|
+
}
|
|
91
|
+
return solid(prefersDark() ? "#000" : "#fff");
|
|
92
|
+
}
|
|
93
|
+
export function resolveBackdrop(host, rect, source, onReady) {
|
|
94
|
+
if (source === "auto")
|
|
95
|
+
return discover(host, rect, onReady);
|
|
96
|
+
if (typeof source === "string") {
|
|
97
|
+
const element = document.querySelector(source);
|
|
98
|
+
if (element instanceof HTMLImageElement || element instanceof HTMLCanvasElement || element instanceof HTMLVideoElement)
|
|
99
|
+
return fromImage(element, onReady);
|
|
100
|
+
return element ? (fromBackground(element, onReady) ?? null) : null;
|
|
101
|
+
}
|
|
102
|
+
return fromImage(source, onReady);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=backdrop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backdrop.js","sourceRoot":"","sources":["../src/backdrop.ts"],"names":[],"mappings":"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"}
|
package/dist/color.d.ts
ADDED
package/dist/color.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const cache = new Map();
|
|
2
|
+
let probe = null;
|
|
3
|
+
export function parseColor(color) {
|
|
4
|
+
const known = cache.get(color);
|
|
5
|
+
if (known)
|
|
6
|
+
return known;
|
|
7
|
+
probe ??= document.createElement("canvas").getContext("2d", { willReadFrequently: true });
|
|
8
|
+
if (!probe)
|
|
9
|
+
return [1, 1, 1, 1];
|
|
10
|
+
probe.clearRect(0, 0, 1, 1);
|
|
11
|
+
probe.fillStyle = "#fff";
|
|
12
|
+
probe.fillStyle = color;
|
|
13
|
+
probe.fillRect(0, 0, 1, 1);
|
|
14
|
+
const [r, g, b, a] = probe.getImageData(0, 0, 1, 1).data;
|
|
15
|
+
const rgba = a ? [r / a, g / a, b / a, a / 255] : [0, 0, 0, 0];
|
|
16
|
+
cache.set(color, rgba);
|
|
17
|
+
return rgba;
|
|
18
|
+
}
|
|
19
|
+
export function prefersDark() {
|
|
20
|
+
const theme = document.documentElement.dataset.theme;
|
|
21
|
+
if (theme)
|
|
22
|
+
return theme === "dark";
|
|
23
|
+
return matchMedia("(prefers-color-scheme: dark)").matches;
|
|
24
|
+
}
|
|
25
|
+
export function resolveTint(tint) {
|
|
26
|
+
const [r, g, b] = parseColor(tint === "auto" ? (prefersDark() ? "#1c1c1e" : "#f9f9f9") : tint);
|
|
27
|
+
return [r, g, b];
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.js","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgB,CAAC;AACtC,IAAI,KAAK,GAAoC,IAAI,CAAC;AAElD,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,KAAK,KAAK,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1F,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;IACxB,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACzD,MAAM,IAAI,GAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrE,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC;IACrD,IAAI,KAAK;QAAE,OAAO,KAAK,KAAK,MAAM,CAAC;IACnC,OAAO,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC/F,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACnB,CAAC"}
|
package/dist/define.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/define.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { GlassSource } from "./backdrop.js";
|
|
2
|
+
import { type Material } from "./material.js";
|
|
3
|
+
import { GlassSurface } from "./surface.js";
|
|
4
|
+
declare const Base: typeof HTMLElement;
|
|
5
|
+
export declare class EdinstvoGlass extends Base {
|
|
6
|
+
static observedAttributes: string[];
|
|
7
|
+
protected surface: GlassSurface;
|
|
8
|
+
private group;
|
|
9
|
+
private sourceValue;
|
|
10
|
+
private materialValue;
|
|
11
|
+
constructor();
|
|
12
|
+
protected get isGroup(): boolean;
|
|
13
|
+
connectedCallback(): void;
|
|
14
|
+
disconnectedCallback(): void;
|
|
15
|
+
show(): Promise<void>;
|
|
16
|
+
hide(): Promise<void>;
|
|
17
|
+
attributeChangedCallback(): void;
|
|
18
|
+
get source(): GlassSource;
|
|
19
|
+
set source(value: GlassSource);
|
|
20
|
+
get material(): Partial<Material>;
|
|
21
|
+
set material(value: Partial<Material>);
|
|
22
|
+
invalidate(): void;
|
|
23
|
+
protected sync(): void;
|
|
24
|
+
private composeMaterial;
|
|
25
|
+
}
|
|
26
|
+
export declare class EdinstvoGlassGroup extends EdinstvoGlass {
|
|
27
|
+
protected get isGroup(): boolean;
|
|
28
|
+
connectedCallback(): void;
|
|
29
|
+
adopt(child: EdinstvoGlass): void;
|
|
30
|
+
release(child: EdinstvoGlass): void;
|
|
31
|
+
refresh(): void;
|
|
32
|
+
}
|
|
33
|
+
export declare function defineGlass(tag?: string): void;
|
|
34
|
+
export {};
|
package/dist/element.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { motionKeys } from "./interaction.js";
|
|
2
|
+
import { kebab, numericKeys } from "./material.js";
|
|
3
|
+
import { GlassSurface, placeCanvas } from "./surface.js";
|
|
4
|
+
const Base = (globalThis.HTMLElement ?? class {
|
|
5
|
+
});
|
|
6
|
+
const css = `
|
|
7
|
+
:host {
|
|
8
|
+
display: inline-block;
|
|
9
|
+
position: relative;
|
|
10
|
+
isolation: isolate;
|
|
11
|
+
border-radius: var(--glass-radius, 24px);
|
|
12
|
+
box-shadow: var(--glass-shadow, 0 8px 32px rgb(0 0 0 / .1));
|
|
13
|
+
}
|
|
14
|
+
:host(:not([data-engine="webgl"])) {
|
|
15
|
+
background: var(--glass-fallback, rgb(255 255 255 / .22));
|
|
16
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.6);
|
|
17
|
+
backdrop-filter: blur(16px) saturate(1.6);
|
|
18
|
+
}
|
|
19
|
+
:host([data-grouped]) {
|
|
20
|
+
box-shadow: none;
|
|
21
|
+
background: none;
|
|
22
|
+
-webkit-backdrop-filter: none;
|
|
23
|
+
backdrop-filter: none;
|
|
24
|
+
}
|
|
25
|
+
:host([data-grouped]) > canvas {
|
|
26
|
+
display: none;
|
|
27
|
+
}
|
|
28
|
+
:host([data-glass-group]) {
|
|
29
|
+
display: block;
|
|
30
|
+
box-shadow: none;
|
|
31
|
+
border-radius: 0;
|
|
32
|
+
background: none;
|
|
33
|
+
-webkit-backdrop-filter: none;
|
|
34
|
+
backdrop-filter: none;
|
|
35
|
+
}
|
|
36
|
+
.content {
|
|
37
|
+
display: block;
|
|
38
|
+
position: relative;
|
|
39
|
+
z-index: 1;
|
|
40
|
+
border-radius: inherit;
|
|
41
|
+
scale: var(--glass-scale, 1);
|
|
42
|
+
opacity: var(--glass-appear, 1);
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
const materialAttributes = new Map(numericKeys.map((key) => [kebab(key), key]));
|
|
46
|
+
export class EdinstvoGlass extends Base {
|
|
47
|
+
static observedAttributes = ["source", "live", "tint", "appear", ...motionKeys, ...materialAttributes.keys()];
|
|
48
|
+
surface;
|
|
49
|
+
group = null;
|
|
50
|
+
sourceValue;
|
|
51
|
+
materialValue;
|
|
52
|
+
constructor() {
|
|
53
|
+
super();
|
|
54
|
+
const root = this.attachShadow({ mode: "open" });
|
|
55
|
+
const style = document.createElement("style");
|
|
56
|
+
style.textContent = css;
|
|
57
|
+
const canvas = document.createElement("canvas");
|
|
58
|
+
canvas.setAttribute("part", "glass");
|
|
59
|
+
placeCanvas(canvas);
|
|
60
|
+
const content = document.createElement("span");
|
|
61
|
+
content.className = "content";
|
|
62
|
+
content.setAttribute("part", "content");
|
|
63
|
+
content.append(document.createElement("slot"));
|
|
64
|
+
root.append(style, canvas, content);
|
|
65
|
+
this.surface = new GlassSurface(this, canvas, {}, this.isGroup);
|
|
66
|
+
}
|
|
67
|
+
get isGroup() {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
connectedCallback() {
|
|
71
|
+
this.group = this.parentElement?.closest("[data-glass-group]") ?? null;
|
|
72
|
+
if (this.group) {
|
|
73
|
+
this.dataset.grouped = "";
|
|
74
|
+
this.group.adopt(this);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.sync();
|
|
78
|
+
this.surface.connect();
|
|
79
|
+
}
|
|
80
|
+
disconnectedCallback() {
|
|
81
|
+
if (this.group) {
|
|
82
|
+
this.group.release(this);
|
|
83
|
+
this.group = null;
|
|
84
|
+
delete this.dataset.grouped;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.surface.disconnect();
|
|
88
|
+
}
|
|
89
|
+
show() {
|
|
90
|
+
return this.surface.show();
|
|
91
|
+
}
|
|
92
|
+
hide() {
|
|
93
|
+
return this.surface.hide();
|
|
94
|
+
}
|
|
95
|
+
attributeChangedCallback() {
|
|
96
|
+
if (this.group)
|
|
97
|
+
this.group.refresh();
|
|
98
|
+
else if (this.isConnected)
|
|
99
|
+
this.sync();
|
|
100
|
+
}
|
|
101
|
+
get source() {
|
|
102
|
+
return this.sourceValue ?? this.getAttribute("source") ?? "auto";
|
|
103
|
+
}
|
|
104
|
+
set source(value) {
|
|
105
|
+
this.sourceValue = value;
|
|
106
|
+
this.sync();
|
|
107
|
+
}
|
|
108
|
+
get material() {
|
|
109
|
+
return this.materialValue ?? {};
|
|
110
|
+
}
|
|
111
|
+
set material(value) {
|
|
112
|
+
this.materialValue = value;
|
|
113
|
+
this.sync();
|
|
114
|
+
}
|
|
115
|
+
invalidate() {
|
|
116
|
+
this.surface.invalidate();
|
|
117
|
+
}
|
|
118
|
+
sync() {
|
|
119
|
+
const live = this.getAttribute("live");
|
|
120
|
+
this.surface.set({
|
|
121
|
+
material: this.composeMaterial(),
|
|
122
|
+
source: this.source,
|
|
123
|
+
live: live === null ? undefined : live !== "false",
|
|
124
|
+
appear: this.hasAttribute("appear"),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
composeMaterial() {
|
|
128
|
+
const overrides = {};
|
|
129
|
+
for (const [attribute, key] of materialAttributes) {
|
|
130
|
+
const value = this.getAttribute(attribute);
|
|
131
|
+
if (value !== null)
|
|
132
|
+
overrides[key] = parseFloat(value);
|
|
133
|
+
}
|
|
134
|
+
const tint = this.getAttribute("tint");
|
|
135
|
+
if (tint)
|
|
136
|
+
overrides.tint = tint;
|
|
137
|
+
return { ...this.material, ...overrides };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export class EdinstvoGlassGroup extends EdinstvoGlass {
|
|
141
|
+
get isGroup() {
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
connectedCallback() {
|
|
145
|
+
this.dataset.glassGroup = "";
|
|
146
|
+
super.connectedCallback();
|
|
147
|
+
}
|
|
148
|
+
adopt(child) {
|
|
149
|
+
this.surface.track(child);
|
|
150
|
+
}
|
|
151
|
+
release(child) {
|
|
152
|
+
this.surface.untrack(child);
|
|
153
|
+
}
|
|
154
|
+
refresh() {
|
|
155
|
+
this.surface.restyle();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function defineGlass(tag = "edinstvo-glass") {
|
|
159
|
+
if (!customElements.get(`${tag}-group`))
|
|
160
|
+
customElements.define(`${tag}-group`, class extends EdinstvoGlassGroup {
|
|
161
|
+
});
|
|
162
|
+
if (!customElements.get(tag))
|
|
163
|
+
customElements.define(tag, class extends EdinstvoGlass {
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface Box {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
w: number;
|
|
5
|
+
h: number;
|
|
6
|
+
}
|
|
7
|
+
export type Fit = "fill" | "cover" | "contain" | "none";
|
|
8
|
+
export declare function fitBox(box: Box, naturalW: number, naturalH: number, fit: Fit): Box;
|
|
9
|
+
export declare function uvTransform(rect: {
|
|
10
|
+
left: number;
|
|
11
|
+
top: number;
|
|
12
|
+
}, map: Box, scaleX: number, scaleY: number, dpr: number): {
|
|
13
|
+
origin: readonly [number, number];
|
|
14
|
+
perPixel: readonly [number, number];
|
|
15
|
+
};
|
|
16
|
+
export declare function cornerRadius(value: string, w: number, h: number): number;
|
|
17
|
+
export declare function lightVector(angle: number): [number, number];
|
|
18
|
+
export declare function softPeak(halfW: number, halfH: number, radius: number): number;
|
package/dist/geometry.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function fitBox(box, naturalW, naturalH, fit) {
|
|
2
|
+
if (fit === "fill" || !naturalW || !naturalH)
|
|
3
|
+
return box;
|
|
4
|
+
if (fit === "none")
|
|
5
|
+
return { x: box.x, y: box.y, w: naturalW, h: naturalH };
|
|
6
|
+
const pick = fit === "cover" ? Math.max : Math.min;
|
|
7
|
+
const scale = pick(box.w / naturalW, box.h / naturalH);
|
|
8
|
+
const w = naturalW * scale;
|
|
9
|
+
const h = naturalH * scale;
|
|
10
|
+
return { x: box.x + (box.w - w) / 2, y: box.y + (box.h - h) / 2, w, h };
|
|
11
|
+
}
|
|
12
|
+
export function uvTransform(rect, map, scaleX, scaleY, dpr) {
|
|
13
|
+
return {
|
|
14
|
+
origin: [(rect.left - map.x) / map.w, (rect.top - map.y) / map.h],
|
|
15
|
+
perPixel: [scaleX / (dpr * map.w), scaleY / (dpr * map.h)],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function cornerRadius(value, w, h) {
|
|
19
|
+
const number = parseFloat(value) || 0;
|
|
20
|
+
const px = value.trim().endsWith("%") ? (number / 100) * Math.min(w, h) : number;
|
|
21
|
+
return Math.min(px, Math.min(w, h) / 2);
|
|
22
|
+
}
|
|
23
|
+
export function lightVector(angle) {
|
|
24
|
+
const radians = (angle * Math.PI) / 180;
|
|
25
|
+
return [Math.sin(radians), -Math.cos(radians)];
|
|
26
|
+
}
|
|
27
|
+
export function softPeak(halfW, halfH, radius) {
|
|
28
|
+
const a = halfW + radius;
|
|
29
|
+
const b = halfH + radius;
|
|
30
|
+
const lo = Math.min(a, b);
|
|
31
|
+
return lo * (1 + (lo / Math.max(a, b)) ** 2.7) ** (-1 / 2.7) - radius;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=geometry.js.map
|