@mirage-engine/painter 1.0.3 → 1.0.5
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/CHANGELOG.md +12 -0
- package/dist/mirage-painter.js +228 -177
- package/dist/mirage-painter.umd.js +41 -21
- package/dist/src/Box/BoxGenerator.d.ts +1 -0
- package/dist/src/tools/parser.d.ts +8 -0
- package/dist/src/types/common.d.ts +3 -0
- package/package.json +1 -1
- package/src/Box/BoxGenerator.ts +33 -2
- package/src/shaders/base/box-fragment.glsl +25 -6
- package/src/tools/parser.ts +34 -0
- package/src/tools/parser.ts.patch +39 -0
- package/src/types/common.ts +3 -0
package/CHANGELOG.md
CHANGED
package/dist/mirage-painter.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var k = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var S = (r, e,
|
|
4
|
-
import * as
|
|
5
|
-
class
|
|
2
|
+
var G = (r, e, n) => e in r ? k(r, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : r[e] = n;
|
|
3
|
+
var S = (r, e, n) => (G(r, typeof e != "symbol" ? e + "" : e, n), n);
|
|
4
|
+
import * as l from "three";
|
|
5
|
+
class I {
|
|
6
6
|
/**
|
|
7
7
|
* Calculates or retrieves the exact alphabetic baseline (in pixels) for the given font.
|
|
8
8
|
* @param font CSS font shorthand string (e.g., "400 16px Inter")
|
|
@@ -11,24 +11,24 @@ class A {
|
|
|
11
11
|
static getBaseline(e) {
|
|
12
12
|
if (this.cache.has(e))
|
|
13
13
|
return this.cache.get(e);
|
|
14
|
-
const
|
|
15
|
-
return this.cache.set(e,
|
|
14
|
+
const n = this.calculateBaselineFromDOM(e);
|
|
15
|
+
return this.cache.set(e, n), n;
|
|
16
16
|
}
|
|
17
17
|
static calculateBaselineFromDOM(e) {
|
|
18
18
|
if (typeof document > "u")
|
|
19
19
|
return 0;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const a = o.offsetTop -
|
|
23
|
-
return document.body.removeChild(
|
|
20
|
+
const n = document.createElement("div"), i = document.createElement("span"), o = document.createElement("img");
|
|
21
|
+
n.style.visibility = "hidden", n.style.position = "absolute", n.style.top = "0px", n.style.left = "0px", n.style.font = e, n.style.margin = "0", n.style.padding = "0", n.style.border = "none", i.style.margin = "0", i.style.padding = "0", i.style.border = "none", i.style.lineHeight = "normal", o.width = 1, o.height = 1, o.style.verticalAlign = "baseline", i.appendChild(document.createTextNode("Hidden Text")), n.appendChild(i), n.appendChild(o), document.body.appendChild(n);
|
|
22
|
+
const a = o.offsetTop - i.offsetTop;
|
|
23
|
+
return document.body.removeChild(n), a;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
S(
|
|
27
|
-
class
|
|
28
|
-
constructor(
|
|
26
|
+
S(I, "cache", /* @__PURE__ */ new Map());
|
|
27
|
+
class L extends l.MeshBasicMaterial {
|
|
28
|
+
constructor(n, i, o, a, t = 2) {
|
|
29
29
|
super({
|
|
30
30
|
transparent: !0,
|
|
31
|
-
side:
|
|
31
|
+
side: l.FrontSide,
|
|
32
32
|
color: 16777215
|
|
33
33
|
});
|
|
34
34
|
S(this, "canvas");
|
|
@@ -36,34 +36,34 @@ class G extends d.MeshBasicMaterial {
|
|
|
36
36
|
S(this, "qualityFactor");
|
|
37
37
|
if (this.canvas = document.createElement("canvas"), this.ctx = this.canvas.getContext("2d"), !this.ctx)
|
|
38
38
|
throw new Error("[Mirage] Failed to create canvas context");
|
|
39
|
-
this.qualityFactor =
|
|
39
|
+
this.qualityFactor = t, this.map = new l.CanvasTexture(this.canvas), this.map.colorSpace = l.LinearSRGBColorSpace, this.map.minFilter = l.LinearFilter, this.map.magFilter = l.LinearFilter, this.updateText(n, i, o, a);
|
|
40
40
|
}
|
|
41
|
-
wrapText(
|
|
42
|
-
const o =
|
|
41
|
+
wrapText(n, i) {
|
|
42
|
+
const o = n.split(`
|
|
43
43
|
`), a = [];
|
|
44
|
-
return o.forEach((
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
44
|
+
return o.forEach((t) => {
|
|
45
|
+
const s = t.match(/[^\s\-]+\-?|\-|\s+/g) || [];
|
|
46
|
+
if (s.length === 0) {
|
|
47
47
|
a.push("");
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
let
|
|
51
|
-
for (let
|
|
52
|
-
const
|
|
53
|
-
this.ctx.measureText(
|
|
50
|
+
let c = s[0];
|
|
51
|
+
for (let u = 1; u < s.length; u++) {
|
|
52
|
+
const d = s[u];
|
|
53
|
+
this.ctx.measureText(c + d).width <= i + 2 ? c += d : (c && a.push(c), c = d.trimStart());
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
c && a.push(c);
|
|
56
56
|
}), a;
|
|
57
57
|
}
|
|
58
|
-
updateText(
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
this.canvas.width !==
|
|
62
|
-
const p = this.wrapText(
|
|
63
|
-
p.forEach((
|
|
64
|
-
const C =
|
|
65
|
-
let
|
|
66
|
-
|
|
58
|
+
updateText(n, i, o, a, t) {
|
|
59
|
+
t !== void 0 && (this.qualityFactor = t);
|
|
60
|
+
const c = (window.devicePixelRatio || 1) * this.qualityFactor, u = o * c, d = a * c;
|
|
61
|
+
this.canvas.width !== u || this.canvas.height !== d ? (this.canvas.width = u, this.canvas.height = d) : this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height), this.ctx.setTransform(c, 0, 0, c, 0, 0), this.ctx.font = i.font, this.ctx.fillStyle = i.color, this.ctx.textBaseline = "alphabetic", this.ctx.globalAlpha = 1;
|
|
62
|
+
const p = this.wrapText(n, o), g = i.lineHeight, f = I.getBaseline(i.font);
|
|
63
|
+
p.forEach((h, B) => {
|
|
64
|
+
const C = B * g + f;
|
|
65
|
+
let m = 0;
|
|
66
|
+
i.textAlign === "center" ? m = o / 2 : i.textAlign === "right" && (m = o), this.ctx.textAlign = i.textAlign, this.ctx.fillText(h, m, C);
|
|
67
67
|
}), this.map && (this.map.needsUpdate = !0);
|
|
68
68
|
}
|
|
69
69
|
dispose() {
|
|
@@ -73,86 +73,102 @@ class G extends d.MeshBasicMaterial {
|
|
|
73
73
|
function x(r, e = 0) {
|
|
74
74
|
if (typeof r == "number")
|
|
75
75
|
return r;
|
|
76
|
-
const
|
|
77
|
-
return typeof r == "string" && r.includes("%") ?
|
|
76
|
+
const n = parseFloat(r) || 0;
|
|
77
|
+
return typeof r == "string" && r.includes("%") ? n / 100 * e : n;
|
|
78
78
|
}
|
|
79
79
|
function w(r) {
|
|
80
80
|
if (!r || r === "transparent")
|
|
81
|
-
return { color: new
|
|
81
|
+
return { color: new l.Color(16777215), alpha: 0 };
|
|
82
82
|
const e = r.match(
|
|
83
83
|
/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/
|
|
84
84
|
);
|
|
85
85
|
if (e) {
|
|
86
|
-
const
|
|
87
|
-
return { color: new
|
|
86
|
+
const n = parseInt(e[1], 10), i = parseInt(e[2], 10), o = parseInt(e[3], 10), a = e[4] !== void 0 ? parseFloat(e[4]) : 1;
|
|
87
|
+
return { color: new l.Color(`rgb(${n}, ${i}, ${o})`), alpha: a };
|
|
88
88
|
}
|
|
89
|
-
return { color: new
|
|
89
|
+
return { color: new l.Color(r), alpha: 1 };
|
|
90
90
|
}
|
|
91
|
-
function
|
|
91
|
+
function A(r) {
|
|
92
92
|
const e = [];
|
|
93
|
-
let
|
|
93
|
+
let n = "", i = 0;
|
|
94
94
|
for (let o = 0; o < r.length; o++) {
|
|
95
95
|
const a = r[o];
|
|
96
96
|
if (a === "(")
|
|
97
|
-
|
|
97
|
+
i++;
|
|
98
98
|
else if (a === ")")
|
|
99
|
-
|
|
100
|
-
else if (a === "," &&
|
|
101
|
-
e.push(
|
|
99
|
+
i--;
|
|
100
|
+
else if (a === "," && i === 0) {
|
|
101
|
+
e.push(n.trim()), n = "";
|
|
102
102
|
continue;
|
|
103
103
|
}
|
|
104
|
-
|
|
104
|
+
n += a;
|
|
105
105
|
}
|
|
106
|
-
return
|
|
106
|
+
return n && e.push(n.trim()), e;
|
|
107
107
|
}
|
|
108
|
-
function
|
|
108
|
+
function z(r) {
|
|
109
109
|
if (!r || typeof r != "string" || !r.includes("linear-gradient"))
|
|
110
110
|
return null;
|
|
111
111
|
const e = r.match(/linear-gradient\((.*)\)/);
|
|
112
112
|
if (!e)
|
|
113
113
|
return null;
|
|
114
|
-
const
|
|
114
|
+
const n = e[1], i = A(n);
|
|
115
115
|
let o = Math.PI, a = 0;
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
else if (
|
|
120
|
-
const
|
|
121
|
-
|
|
116
|
+
const t = i[0].trim();
|
|
117
|
+
if (t.startsWith("to "))
|
|
118
|
+
t === "to top" ? o = 0 : t === "to right" ? o = Math.PI / 2 : t === "to bottom" ? o = Math.PI : t === "to left" ? o = Math.PI * 1.5 : t === "to top right" || t === "to right top" ? o = Math.PI / 4 : t === "to bottom right" || t === "to right bottom" ? o = Math.PI * 0.75 : t === "to bottom left" || t === "to left bottom" ? o = Math.PI * 1.25 : (t === "to top left" || t === "to left top") && (o = Math.PI * 1.75), a = 1;
|
|
119
|
+
else if (t.endsWith("deg") || t.endsWith("rad") || t.endsWith("turn")) {
|
|
120
|
+
const c = parseFloat(t);
|
|
121
|
+
t.endsWith("deg") ? o = c * (Math.PI / 180) : t.endsWith("rad") ? o = c : t.endsWith("turn") && (o = c * Math.PI * 2), a = 1;
|
|
122
122
|
}
|
|
123
|
-
const
|
|
124
|
-
for (let
|
|
125
|
-
const
|
|
126
|
-
let p =
|
|
127
|
-
if (
|
|
128
|
-
const
|
|
129
|
-
(
|
|
123
|
+
const s = [];
|
|
124
|
+
for (let c = a; c < i.length && !(s.length >= 8); c++) {
|
|
125
|
+
const u = i[c].trim(), d = u.lastIndexOf(" ");
|
|
126
|
+
let p = u, g = null;
|
|
127
|
+
if (d !== -1 && !u.endsWith(")")) {
|
|
128
|
+
const h = u.substring(d + 1);
|
|
129
|
+
(h.endsWith("%") || h.endsWith("px") || !isNaN(parseFloat(h))) && (p = u.substring(0, d).trim(), g = h);
|
|
130
130
|
}
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
color:
|
|
134
|
-
alpha:
|
|
135
|
-
rawStop:
|
|
131
|
+
const f = w(p);
|
|
132
|
+
s.push({
|
|
133
|
+
color: f.color,
|
|
134
|
+
alpha: f.alpha,
|
|
135
|
+
rawStop: g,
|
|
136
136
|
stop: 0
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
|
-
if (
|
|
140
|
-
for (let
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
let
|
|
144
|
-
for (let
|
|
145
|
-
if (
|
|
146
|
-
const
|
|
147
|
-
if (
|
|
148
|
-
const p = c
|
|
149
|
-
for (let
|
|
150
|
-
c
|
|
139
|
+
if (s.length > 0) {
|
|
140
|
+
for (let u = 0; u < s.length; u++)
|
|
141
|
+
s[u].rawStop !== null && (s[u].stop = parseFloat(s[u].rawStop) / 100);
|
|
142
|
+
s[0].rawStop === null && (s[0].stop = 0), s.length > 1 && s[s.length - 1].rawStop === null && (s[s.length - 1].stop = 1);
|
|
143
|
+
let c = 0;
|
|
144
|
+
for (let u = 1; u < s.length; u++)
|
|
145
|
+
if (s[u].rawStop !== null || u === s.length - 1) {
|
|
146
|
+
const d = u - c;
|
|
147
|
+
if (d > 1) {
|
|
148
|
+
const p = s[c].stop, f = (s[u].stop - p) / d;
|
|
149
|
+
for (let h = 1; h < d; h++)
|
|
150
|
+
s[c + h].stop = p + f * h;
|
|
151
151
|
}
|
|
152
|
-
|
|
152
|
+
c = u;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
return { angle: o, stops:
|
|
155
|
+
return { angle: o, stops: s };
|
|
156
|
+
}
|
|
157
|
+
function E(r) {
|
|
158
|
+
if (!r || r === "none")
|
|
159
|
+
return null;
|
|
160
|
+
const e = A(r);
|
|
161
|
+
if (e.length === 0)
|
|
162
|
+
return null;
|
|
163
|
+
const n = e[0].trim(), i = /(rgba?\([^)]+\)|#[0-9a-fA-F]+|[a-zA-Z]+)/, o = n.match(i);
|
|
164
|
+
let a = "transparent", t = n;
|
|
165
|
+
if (o && o[1] !== "inset") {
|
|
166
|
+
const f = o[1];
|
|
167
|
+
(f.startsWith("rgb") || f.startsWith("#") || f === "black" || f === "white" || f === "transparent") && (a = f, t = n.replace(f, "").trim());
|
|
168
|
+
}
|
|
169
|
+
t = t.replace("inset", "").trim();
|
|
170
|
+
const s = t.split(/\s+/).map((f) => parseFloat(f) || 0), c = s[0] || 0, u = s[1] || 0, d = s[2] || 0, p = s[3] || 0, g = w(a);
|
|
171
|
+
return { offsetX: c, offsetY: u, blurRadius: d, spreadRadius: p, color: g.color, alpha: g.alpha };
|
|
156
172
|
}
|
|
157
173
|
const F = `varying vec2 vUv;
|
|
158
174
|
varying vec4 vScreenPos;
|
|
@@ -160,8 +176,13 @@ void main() {
|
|
|
160
176
|
vUv = uv;
|
|
161
177
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
162
178
|
vScreenPos = gl_Position;
|
|
163
|
-
}`,
|
|
179
|
+
}`, W = `varying vec2 vUv;
|
|
164
180
|
uniform vec2 uSize;
|
|
181
|
+
uniform vec2 uMeshSize;
|
|
182
|
+
uniform vec4 uShadowColor;
|
|
183
|
+
uniform vec2 uShadowOffset;
|
|
184
|
+
uniform float uShadowBlur;
|
|
185
|
+
uniform float uShadowSpread;
|
|
165
186
|
uniform vec4 uBorderRadius;
|
|
166
187
|
uniform float uBorderWidth;
|
|
167
188
|
uniform vec4 uBgColor;
|
|
@@ -217,11 +238,10 @@ float sdVisualBox(vec2 p, vec2 b, float r) {
|
|
|
217
238
|
return min(max(q.x, q.y), 0.0) + d;
|
|
218
239
|
}
|
|
219
240
|
|
|
220
|
-
vec4 calculateGradientLayer(vec2
|
|
241
|
+
vec4 calculateGradientLayer(vec2 p) {
|
|
221
242
|
if (uGradientCount < 2) return uGradientColors[0];
|
|
222
243
|
|
|
223
244
|
vec2 dir = vec2(sin(uGradientAngle), cos(uGradientAngle));
|
|
224
|
-
vec2 p = (uv - 0.5) * uSize;
|
|
225
245
|
float proj = dot(p, dir);
|
|
226
246
|
float L = abs(uSize.x * dir.x) + abs(uSize.y * dir.y);
|
|
227
247
|
float t = clamp((proj / L) + 0.5, 0.0, 1.0);
|
|
@@ -240,7 +260,7 @@ vec4 calculateGradientLayer(vec2 uv) {
|
|
|
240
260
|
}
|
|
241
261
|
|
|
242
262
|
void main() {
|
|
243
|
-
vec2 p = (vUv - 0.5) *
|
|
263
|
+
vec2 p = (vUv - 0.5) * uMeshSize;
|
|
244
264
|
vec2 halfSize = uSize * 0.5;
|
|
245
265
|
|
|
246
266
|
// CSS Proportional Border-Radius Clamping
|
|
@@ -261,7 +281,7 @@ void main() {
|
|
|
261
281
|
vec4 baseColor = vec4(uBgColor.rgb, uBgColor.a);
|
|
262
282
|
|
|
263
283
|
if (uGradientCount > 0) {
|
|
264
|
-
vec4 gradColor = calculateGradientLayer(
|
|
284
|
+
vec4 gradColor = calculateGradientLayer(p);
|
|
265
285
|
baseColor = blendSrcOver(gradColor, baseColor);
|
|
266
286
|
}
|
|
267
287
|
|
|
@@ -288,11 +308,26 @@ void main() {
|
|
|
288
308
|
|
|
289
309
|
// final blending (border + background) using blendSrcOver
|
|
290
310
|
vec4 borderLayer = vec4(uBorderColor.rgb, borderAlpha);
|
|
291
|
-
vec4
|
|
311
|
+
vec4 mainColor = blendSrcOver(borderLayer, baseColor);
|
|
312
|
+
mainColor.a *= bgMask;
|
|
313
|
+
|
|
314
|
+
vec4 shadowLayer = vec4(0.0);
|
|
315
|
+
if (uShadowColor.a > 0.001) {
|
|
316
|
+
vec2 shadowP = p - vec2(uShadowOffset.x, -uShadowOffset.y);
|
|
317
|
+
float shadowRadius = max(r + uShadowSpread, 0.0);
|
|
318
|
+
vec2 shadowHalfSize = max(halfSize + vec2(uShadowSpread), vec2(0.0));
|
|
319
|
+
float shadowD = sdRoundedBox(shadowP, shadowHalfSize, shadowRadius);
|
|
320
|
+
float blur = max(uShadowBlur, 1.0);
|
|
321
|
+
float shadowMask = 1.0 - smoothstep(-blur * 0.5, blur * 0.5, shadowD);
|
|
322
|
+
shadowLayer = vec4(uShadowColor.rgb, uShadowColor.a * shadowMask);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
vec4 finalColor = blendSrcOver(mainColor, shadowLayer);
|
|
326
|
+
|
|
292
327
|
// final color control (Tint, Noise)
|
|
293
328
|
#INJECT_COLOR_MODIFIER
|
|
294
329
|
|
|
295
|
-
float finalOpacity = finalColor.a *
|
|
330
|
+
float finalOpacity = finalColor.a * uOpacity;
|
|
296
331
|
if (finalOpacity < 0.001) discard;
|
|
297
332
|
|
|
298
333
|
gl_FragColor = vec4(finalColor.rgb, finalOpacity);
|
|
@@ -300,41 +335,47 @@ void main() {
|
|
|
300
335
|
|
|
301
336
|
// #include <colorspace_fragment>
|
|
302
337
|
}
|
|
303
|
-
`,
|
|
338
|
+
`, U = `uniform sampler2D uTexture;
|
|
304
339
|
varying vec4 vScreenPos;
|
|
305
340
|
uniform vec2 uTextureRepeat;
|
|
306
341
|
uniform vec2 uTextureOffset;`, _ = `vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
|
|
307
342
|
vec2 resultUv = screenUv;
|
|
308
343
|
|
|
309
|
-
`,
|
|
344
|
+
`, V = `vec4 texColor = texture2D(uTexture, resultUv);
|
|
310
345
|
baseColor = blendSrcOver(baseColor, texColor);`, R = {
|
|
311
346
|
vertexShader: F,
|
|
312
|
-
fragmentShader:
|
|
313
|
-
},
|
|
314
|
-
declChunk:
|
|
347
|
+
fragmentShader: W
|
|
348
|
+
}, M = {
|
|
349
|
+
declChunk: U,
|
|
315
350
|
uvChunk: _,
|
|
316
|
-
baseColorChunk:
|
|
351
|
+
baseColorChunk: V
|
|
317
352
|
};
|
|
318
|
-
function
|
|
319
|
-
const a =
|
|
320
|
-
let
|
|
321
|
-
const
|
|
353
|
+
function D(r, e, n, i = null, o) {
|
|
354
|
+
const a = i !== null || !!r.imageSrc;
|
|
355
|
+
let t = "";
|
|
356
|
+
const s = {};
|
|
322
357
|
if (o != null && o.uniforms)
|
|
323
|
-
for (const [
|
|
324
|
-
typeof
|
|
325
|
-
`,
|
|
326
|
-
`,
|
|
327
|
-
`,
|
|
328
|
-
`,
|
|
329
|
-
`,
|
|
330
|
-
const
|
|
331
|
-
` +
|
|
358
|
+
for (const [v, b] of Object.entries(o.uniforms))
|
|
359
|
+
typeof b == "number" ? (t += `uniform float ${v};
|
|
360
|
+
`, s[v] = { value: b }) : Array.isArray(b) ? b.length === 2 ? (t += `uniform vec2 ${v};
|
|
361
|
+
`, s[v] = { value: new l.Vector2(...b) }) : b.length === 3 ? (t += `uniform vec3 ${v};
|
|
362
|
+
`, s[v] = { value: new l.Vector3(...b) }) : b.length === 4 && (t += `uniform vec4 ${v};
|
|
363
|
+
`, s[v] = { value: new l.Vector4(...b) }) : (t += `uniform float ${v};
|
|
364
|
+
`, s[v] = { value: b });
|
|
365
|
+
const c = o !== void 0, u = (a || c ? M.declChunk : "") + `
|
|
366
|
+
` + t, d = `vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
|
|
332
367
|
`, p = r.isTraveler ? `vec2 resultUv = screenUv;
|
|
333
|
-
` : `vec2
|
|
334
|
-
|
|
335
|
-
|
|
368
|
+
` : `vec2 localUv = (p / uSize) + 0.5;
|
|
369
|
+
vec2 resultUv = localUv * uTextureRepeat + uTextureOffset;
|
|
370
|
+
`, g = a || c ? d + p + ((o == null ? void 0 : o.uvModifier) || "") : "", f = a || c ? M.baseColorChunk : "", h = (o == null ? void 0 : o.colorModifier) || "", B = R.fragmentShader.replace("#INJECT_DECLARATIONS", u).replace("#INJECT_UV_MODIFIER", g).replace("#INJECT_BASE_COLOR", f).replace("#INJECT_COLOR_MODIFIER", h), C = w(r.backgroundColor), m = w(r.borderColor), y = {
|
|
371
|
+
uSize: { value: new l.Vector2(e, n) },
|
|
372
|
+
uMeshSize: { value: new l.Vector2(e, n) },
|
|
373
|
+
uShadowColor: { value: new l.Vector4(0, 0, 0, 0) },
|
|
374
|
+
uShadowOffset: { value: new l.Vector2(0, 0) },
|
|
375
|
+
uShadowBlur: { value: 0 },
|
|
376
|
+
uShadowSpread: { value: 0 },
|
|
336
377
|
uBgColor: {
|
|
337
|
-
value: new
|
|
378
|
+
value: new l.Vector4(
|
|
338
379
|
C.color.r,
|
|
339
380
|
C.color.g,
|
|
340
381
|
C.color.b,
|
|
@@ -342,56 +383,65 @@ function V(r, e, t, n = null, o) {
|
|
|
342
383
|
)
|
|
343
384
|
},
|
|
344
385
|
uBorderColor: {
|
|
345
|
-
value: new
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
386
|
+
value: new l.Vector4(
|
|
387
|
+
m.color.r,
|
|
388
|
+
m.color.g,
|
|
389
|
+
m.color.b,
|
|
390
|
+
m.alpha
|
|
350
391
|
)
|
|
351
392
|
},
|
|
352
|
-
uBorderRadius: { value: new
|
|
393
|
+
uBorderRadius: { value: new l.Vector4(0, 0, 0, 0) },
|
|
353
394
|
uBorderWidth: { value: x(r.borderWidth) },
|
|
354
395
|
uOpacity: { value: r.opacity ?? 1 },
|
|
355
396
|
uTexture: { value: null },
|
|
356
|
-
uTextureRepeat: { value: new
|
|
357
|
-
uTextureOffset: { value: new
|
|
397
|
+
uTextureRepeat: { value: new l.Vector2(1, 1) },
|
|
398
|
+
uTextureOffset: { value: new l.Vector2(0, 0) },
|
|
358
399
|
uGradientCount: { value: 0 },
|
|
359
400
|
uGradientAngle: { value: 0 },
|
|
360
401
|
uGradientColors: {
|
|
361
|
-
value: Array.from({ length: 8 }, () => new
|
|
402
|
+
value: Array.from({ length: 8 }, () => new l.Vector4(0, 0, 0, 0))
|
|
362
403
|
},
|
|
363
404
|
uGradientStops: { value: new Float32Array(8) }
|
|
364
405
|
};
|
|
365
|
-
|
|
366
|
-
const O = new
|
|
367
|
-
uniforms: { ...
|
|
406
|
+
P(y.uBorderRadius.value, r.borderRadius, Math.min(e, n)), a && (y.uTexture.value = i);
|
|
407
|
+
const O = new l.ShaderMaterial({
|
|
408
|
+
uniforms: { ...y, ...s },
|
|
368
409
|
vertexShader: R.vertexShader,
|
|
369
|
-
fragmentShader:
|
|
410
|
+
fragmentShader: B,
|
|
370
411
|
transparent: !0,
|
|
371
|
-
side:
|
|
412
|
+
side: l.FrontSide
|
|
372
413
|
// for better performance
|
|
373
414
|
});
|
|
374
415
|
return r.backgroundImage && T(O, { backgroundImage: r.backgroundImage }), O;
|
|
375
416
|
}
|
|
376
|
-
function
|
|
417
|
+
function H(r, e, n, i, o) {
|
|
377
418
|
const a = x(e.borderWidth);
|
|
378
419
|
T(r, {
|
|
379
|
-
width:
|
|
380
|
-
height:
|
|
420
|
+
width: n,
|
|
421
|
+
height: i,
|
|
381
422
|
borderRadius: e.borderRadius,
|
|
382
423
|
borderWidth: a,
|
|
383
424
|
backgroundColor: e.backgroundColor,
|
|
384
425
|
borderColor: e.borderColor,
|
|
385
426
|
opacity: e.opacity,
|
|
386
427
|
texture: o,
|
|
387
|
-
backgroundImage: e.backgroundImage
|
|
428
|
+
backgroundImage: e.backgroundImage,
|
|
429
|
+
boxShadow: e.boxShadow
|
|
388
430
|
});
|
|
389
431
|
}
|
|
390
432
|
function T(r, e) {
|
|
391
|
-
var
|
|
392
|
-
if (e.
|
|
433
|
+
var i;
|
|
434
|
+
if (e.boxShadow !== void 0) {
|
|
435
|
+
const o = E(e.boxShadow);
|
|
436
|
+
o ? (r.uniforms.uShadowColor.value.set(o.color.r, o.color.g, o.color.b, o.alpha), r.uniforms.uShadowOffset.value.set(o.offsetX, o.offsetY), r.uniforms.uShadowBlur.value = o.blurRadius, r.uniforms.uShadowSpread.value = o.spreadRadius, r.userData.shadowPadding = o.blurRadius + o.spreadRadius + Math.max(Math.abs(o.offsetX), Math.abs(o.offsetY))) : (r.uniforms.uShadowColor.value.w = 0, r.userData.shadowPadding = 0);
|
|
437
|
+
}
|
|
438
|
+
if (e.width !== void 0 && e.height !== void 0 && r.uniforms.uSize.value.set(e.width, e.height), r.uniforms.uMeshSize) {
|
|
439
|
+
const o = r.userData.shadowPadding || 0, a = e.width !== void 0 ? e.width : r.uniforms.uSize.value.x, t = e.height !== void 0 ? e.height : r.uniforms.uSize.value.y;
|
|
440
|
+
r.uniforms.uMeshSize.value.set(a + o * 2, t + o * 2);
|
|
441
|
+
}
|
|
442
|
+
if (e.borderRadius !== void 0) {
|
|
393
443
|
const o = e.width !== void 0 && e.height !== void 0 ? Math.min(e.width, e.height) : Math.min(r.uniforms.uSize.value.x, r.uniforms.uSize.value.y);
|
|
394
|
-
|
|
444
|
+
P(r.uniforms.uBorderRadius.value, e.borderRadius, o);
|
|
395
445
|
}
|
|
396
446
|
if (e.borderWidth !== void 0 && (r.uniforms.uBorderWidth.value = e.borderWidth), e.backgroundColor !== void 0)
|
|
397
447
|
if (Array.isArray(e.backgroundColor)) {
|
|
@@ -446,43 +496,43 @@ function T(r, e) {
|
|
|
446
496
|
);
|
|
447
497
|
}
|
|
448
498
|
e.opacity !== void 0 && (r.uniforms.uOpacity.value = e.opacity), e.bgOpacity !== void 0 && (r.uniforms.uBgColor.value.w = e.bgOpacity), e.borderOpacity !== void 0 && (r.uniforms.uBorderColor.value.w = e.borderOpacity), r.uniforms.uTexture && e.texture !== void 0 && (r.uniforms.uTexture.value = e.texture);
|
|
449
|
-
const
|
|
450
|
-
if (
|
|
451
|
-
const o =
|
|
452
|
-
if (o && a &&
|
|
453
|
-
const
|
|
454
|
-
if (
|
|
455
|
-
const
|
|
456
|
-
r.uniforms.uTextureRepeat.value.set(
|
|
499
|
+
const n = e.texture !== void 0 ? e.texture : (i = r.uniforms.uTexture) == null ? void 0 : i.value;
|
|
500
|
+
if (n && (n.image instanceof ImageBitmap || n.image instanceof HTMLImageElement || n.image instanceof HTMLCanvasElement)) {
|
|
501
|
+
const o = n.image.naturalWidth || n.image.videoWidth || n.image.width, a = n.image.naturalHeight || n.image.videoHeight || n.image.height, t = e.width ?? r.uniforms.uSize.value.x, s = e.height ?? r.uniforms.uSize.value.y;
|
|
502
|
+
if (o && a && t && s) {
|
|
503
|
+
const c = o / a, u = t / s;
|
|
504
|
+
if (c > u) {
|
|
505
|
+
const d = u / c;
|
|
506
|
+
r.uniforms.uTextureRepeat.value.set(d, 1), r.uniforms.uTextureOffset.value.set((1 - d) / 2, 0);
|
|
457
507
|
} else {
|
|
458
|
-
const
|
|
459
|
-
r.uniforms.uTextureRepeat.value.set(1,
|
|
508
|
+
const d = c / u;
|
|
509
|
+
r.uniforms.uTextureRepeat.value.set(1, d), r.uniforms.uTextureOffset.value.set(0, (1 - d) / 2);
|
|
460
510
|
}
|
|
461
511
|
}
|
|
462
512
|
} else
|
|
463
513
|
r.uniforms.uTextureRepeat && (r.uniforms.uTextureRepeat.value.set(1, 1), r.uniforms.uTextureOffset.value.set(0, 0));
|
|
464
514
|
if (e.backgroundImage !== void 0) {
|
|
465
|
-
const o =
|
|
515
|
+
const o = z(e.backgroundImage);
|
|
466
516
|
if (o) {
|
|
467
517
|
r.uniforms.uGradientCount.value = o.stops.length, r.uniforms.uGradientAngle.value = o.angle;
|
|
468
518
|
for (let a = 0; a < 8; a++)
|
|
469
519
|
if (a < o.stops.length) {
|
|
470
|
-
const
|
|
520
|
+
const t = o.stops[a];
|
|
471
521
|
r.uniforms.uGradientColors.value[a].set(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
), r.uniforms.uGradientStops.value[a] =
|
|
522
|
+
t.color.r,
|
|
523
|
+
t.color.g,
|
|
524
|
+
t.color.b,
|
|
525
|
+
t.alpha
|
|
526
|
+
), r.uniforms.uGradientStops.value[a] = t.stop;
|
|
477
527
|
} else
|
|
478
528
|
r.uniforms.uGradientColors.value[a].set(0, 0, 0, 0), r.uniforms.uGradientStops.value[a] = 1;
|
|
479
529
|
} else
|
|
480
530
|
r.uniforms.uGradientCount.value = 0;
|
|
481
531
|
}
|
|
482
532
|
for (const o of Object.keys(e))
|
|
483
|
-
o !== "width" && o !== "height" && o !== "borderRadius" && o !== "borderWidth" && o !== "backgroundColor" && o !== "borderColor" && o !== "opacity" && o !== "bgOpacity" && o !== "borderOpacity" && o !== "texture" && o !== "backgroundImage" && r.uniforms[o] !== void 0 && (r.uniforms[o].value !== void 0 && r.uniforms[o].value !== null && typeof r.uniforms[o].value.set == "function" ? Array.isArray(e[o]) ? r.uniforms[o].value.set(...e[o]) : e[o] !== void 0 && (e[o].copy ? r.uniforms[o].value.copy(e[o]) : r.uniforms[o].value = e[o]) : r.uniforms[o].value = e[o]);
|
|
533
|
+
o !== "width" && o !== "height" && o !== "borderRadius" && o !== "borderWidth" && o !== "backgroundColor" && o !== "borderColor" && o !== "opacity" && o !== "bgOpacity" && o !== "borderOpacity" && o !== "texture" && o !== "backgroundImage" && o !== "boxShadow" && r.uniforms[o] !== void 0 && (r.uniforms[o].value !== void 0 && r.uniforms[o].value !== null && typeof r.uniforms[o].value.set == "function" ? Array.isArray(e[o]) ? r.uniforms[o].value.set(...e[o]) : e[o] !== void 0 && (e[o].copy ? r.uniforms[o].value.copy(e[o]) : r.uniforms[o].value = e[o]) : r.uniforms[o].value = e[o]);
|
|
484
534
|
}
|
|
485
|
-
function
|
|
535
|
+
function P(r, e, n = 0) {
|
|
486
536
|
if (e == null) {
|
|
487
537
|
r.set(0, 0, 0, 0);
|
|
488
538
|
return;
|
|
@@ -495,38 +545,38 @@ function M(r, e, t = 0) {
|
|
|
495
545
|
r.set(e[0], e[1], e[2], e[3]);
|
|
496
546
|
return;
|
|
497
547
|
}
|
|
498
|
-
const
|
|
499
|
-
r.set(o, a,
|
|
548
|
+
const i = e.split("/")[0].trim().split(/\s+/), o = x(i[0], n), a = x(i[1] ?? i[0], n), t = x(i[2] ?? i[0], n), s = x(i[3] ?? i[1] ?? i[0], n);
|
|
549
|
+
r.set(o, a, t, s);
|
|
500
550
|
}
|
|
501
|
-
const
|
|
502
|
-
create(r, e,
|
|
503
|
-
return r === "BOX" ?
|
|
551
|
+
const q = {
|
|
552
|
+
create(r, e, n, i, o, a = 2, t = null, s) {
|
|
553
|
+
return r === "BOX" ? D(
|
|
504
554
|
e,
|
|
505
|
-
n,
|
|
506
|
-
o,
|
|
507
555
|
i,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
556
|
+
o,
|
|
557
|
+
t,
|
|
558
|
+
s
|
|
559
|
+
) : r === "TEXT" ? new L(
|
|
560
|
+
n || "",
|
|
511
561
|
e,
|
|
512
|
-
|
|
562
|
+
i,
|
|
513
563
|
o,
|
|
514
564
|
a
|
|
515
|
-
) : new
|
|
565
|
+
) : new l.MeshBasicMaterial({ visible: !1 });
|
|
516
566
|
},
|
|
517
|
-
update(r, e,
|
|
518
|
-
e === "BOX" ?
|
|
567
|
+
update(r, e, n, i, o, a, t = 2, s) {
|
|
568
|
+
e === "BOX" ? H(
|
|
519
569
|
r,
|
|
520
|
-
|
|
570
|
+
n,
|
|
521
571
|
o,
|
|
522
572
|
a,
|
|
523
|
-
|
|
573
|
+
s
|
|
524
574
|
) : e === "TEXT" && r.updateText(
|
|
525
|
-
|
|
526
|
-
|
|
575
|
+
i || "",
|
|
576
|
+
n,
|
|
527
577
|
o,
|
|
528
578
|
a,
|
|
529
|
-
|
|
579
|
+
t
|
|
530
580
|
);
|
|
531
581
|
},
|
|
532
582
|
forceUpdateUniforms(r, e) {
|
|
@@ -534,13 +584,14 @@ const N = {
|
|
|
534
584
|
}
|
|
535
585
|
};
|
|
536
586
|
export {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
587
|
+
q as Painter,
|
|
588
|
+
L as TextGenerator,
|
|
589
|
+
D as createBoxMaterial,
|
|
590
|
+
E as parseBoxShadow,
|
|
540
591
|
w as parseColor,
|
|
541
|
-
|
|
592
|
+
z as parseLinearGradient,
|
|
542
593
|
x as parsePixelValue,
|
|
543
594
|
T as setBoxUniforms,
|
|
544
|
-
|
|
545
|
-
|
|
595
|
+
A as splitByComma,
|
|
596
|
+
H as updateBoxMaterial
|
|
546
597
|
};
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
(function(f,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],p):(f=typeof globalThis<"u"?globalThis:f||self,p(f.MiragePainter={},f.THREE))})(this,function(f,p){"use strict";var
|
|
2
|
-
`),a=[];return
|
|
1
|
+
(function(f,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],p):(f=typeof globalThis<"u"?globalThis:f||self,p(f.MiragePainter={},f.THREE))})(this,function(f,p){"use strict";var j=Object.defineProperty;var J=(f,p,w)=>p in f?j(f,p,{enumerable:!0,configurable:!0,writable:!0,value:w}):f[p]=w;var T=(f,p,w)=>(J(f,typeof p!="symbol"?p+"":p,w),w);function w(r){const o=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const n in r)if(n!=="default"){const t=Object.getOwnPropertyDescriptor(r,n);Object.defineProperty(o,n,t.get?t:{enumerable:!0,get:()=>r[n]})}}return o.default=r,Object.freeze(o)}const l=w(p);class P{static getBaseline(o){if(this.cache.has(o))return this.cache.get(o);const n=this.calculateBaselineFromDOM(o);return this.cache.set(o,n),n}static calculateBaselineFromDOM(o){if(typeof document>"u")return 0;const n=document.createElement("div"),t=document.createElement("span"),e=document.createElement("img");n.style.visibility="hidden",n.style.position="absolute",n.style.top="0px",n.style.left="0px",n.style.font=o,n.style.margin="0",n.style.padding="0",n.style.border="none",t.style.margin="0",t.style.padding="0",t.style.border="none",t.style.lineHeight="normal",e.width=1,e.height=1,e.style.verticalAlign="baseline",t.appendChild(document.createTextNode("Hidden Text")),n.appendChild(t),n.appendChild(e),document.body.appendChild(n);const a=e.offsetTop-t.offsetTop;return document.body.removeChild(n),a}}T(P,"cache",new Map);class A extends l.MeshBasicMaterial{constructor(n,t,e,a,i=2){super({transparent:!0,side:l.FrontSide,color:16777215});T(this,"canvas");T(this,"ctx");T(this,"qualityFactor");if(this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),!this.ctx)throw new Error("[Mirage] Failed to create canvas context");this.qualityFactor=i,this.map=new l.CanvasTexture(this.canvas),this.map.colorSpace=l.LinearSRGBColorSpace,this.map.minFilter=l.LinearFilter,this.map.magFilter=l.LinearFilter,this.updateText(n,t,e,a)}wrapText(n,t){const e=n.split(`
|
|
2
|
+
`),a=[];return e.forEach(i=>{const s=i.match(/[^\s\-]+\-?|\-|\s+/g)||[];if(s.length===0){a.push("");return}let c=s[0];for(let u=1;u<s.length;u++){const d=s[u];this.ctx.measureText(c+d).width<=t+2?c+=d:(c&&a.push(c),c=d.trimStart())}c&&a.push(c)}),a}updateText(n,t,e,a,i){i!==void 0&&(this.qualityFactor=i);const c=(window.devicePixelRatio||1)*this.qualityFactor,u=e*c,d=a*c;this.canvas.width!==u||this.canvas.height!==d?(this.canvas.width=u,this.canvas.height=d):this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.setTransform(c,0,0,c,0,0),this.ctx.font=t.font,this.ctx.fillStyle=t.color,this.ctx.textBaseline="alphabetic",this.ctx.globalAlpha=1;const b=this.wrapText(n,e),v=t.lineHeight,h=P.getBaseline(t.font);b.forEach((g,M)=>{const B=M*v+h;let x=0;t.textAlign==="center"?x=e/2:t.textAlign==="right"&&(x=e),this.ctx.textAlign=t.textAlign,this.ctx.fillText(g,x,B)}),this.map&&(this.map.needsUpdate=!0)}dispose(){this.map&&this.map.dispose(),super.dispose()}}function S(r,o=0){if(typeof r=="number")return r;const n=parseFloat(r)||0;return typeof r=="string"&&r.includes("%")?n/100*o:n}function y(r){if(!r||r==="transparent")return{color:new l.Color(16777215),alpha:0};const o=r.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(o){const n=parseInt(o[1],10),t=parseInt(o[2],10),e=parseInt(o[3],10),a=o[4]!==void 0?parseFloat(o[4]):1;return{color:new l.Color(`rgb(${n}, ${t}, ${e})`),alpha:a}}return{color:new l.Color(r),alpha:1}}function R(r){const o=[];let n="",t=0;for(let e=0;e<r.length;e++){const a=r[e];if(a==="(")t++;else if(a===")")t--;else if(a===","&&t===0){o.push(n.trim()),n="";continue}n+=a}return n&&o.push(n.trim()),o}function k(r){if(!r||typeof r!="string"||!r.includes("linear-gradient"))return null;const o=r.match(/linear-gradient\((.*)\)/);if(!o)return null;const n=o[1],t=R(n);let e=Math.PI,a=0;const i=t[0].trim();if(i.startsWith("to "))i==="to top"?e=0:i==="to right"?e=Math.PI/2:i==="to bottom"?e=Math.PI:i==="to left"?e=Math.PI*1.5:i==="to top right"||i==="to right top"?e=Math.PI/4:i==="to bottom right"||i==="to right bottom"?e=Math.PI*.75:i==="to bottom left"||i==="to left bottom"?e=Math.PI*1.25:(i==="to top left"||i==="to left top")&&(e=Math.PI*1.75),a=1;else if(i.endsWith("deg")||i.endsWith("rad")||i.endsWith("turn")){const c=parseFloat(i);i.endsWith("deg")?e=c*(Math.PI/180):i.endsWith("rad")?e=c:i.endsWith("turn")&&(e=c*Math.PI*2),a=1}const s=[];for(let c=a;c<t.length&&!(s.length>=8);c++){const u=t[c].trim(),d=u.lastIndexOf(" ");let b=u,v=null;if(d!==-1&&!u.endsWith(")")){const g=u.substring(d+1);(g.endsWith("%")||g.endsWith("px")||!isNaN(parseFloat(g)))&&(b=u.substring(0,d).trim(),v=g)}const h=y(b);s.push({color:h.color,alpha:h.alpha,rawStop:v,stop:0})}if(s.length>0){for(let u=0;u<s.length;u++)s[u].rawStop!==null&&(s[u].stop=parseFloat(s[u].rawStop)/100);s[0].rawStop===null&&(s[0].stop=0),s.length>1&&s[s.length-1].rawStop===null&&(s[s.length-1].stop=1);let c=0;for(let u=1;u<s.length;u++)if(s[u].rawStop!==null||u===s.length-1){const d=u-c;if(d>1){const b=s[c].stop,h=(s[u].stop-b)/d;for(let g=1;g<d;g++)s[c+g].stop=b+h*g}c=u}}return{angle:e,stops:s}}function G(r){if(!r||r==="none")return null;const o=R(r);if(o.length===0)return null;const n=o[0].trim(),t=/(rgba?\([^)]+\)|#[0-9a-fA-F]+|[a-zA-Z]+)/,e=n.match(t);let a="transparent",i=n;if(e&&e[1]!=="inset"){const h=e[1];(h.startsWith("rgb")||h.startsWith("#")||h==="black"||h==="white"||h==="transparent")&&(a=h,i=n.replace(h,"").trim())}i=i.replace("inset","").trim();const s=i.split(/\s+/).map(h=>parseFloat(h)||0),c=s[0]||0,u=s[1]||0,d=s[2]||0,b=s[3]||0,v=y(a);return{offsetX:c,offsetY:u,blurRadius:d,spreadRadius:b,color:v.color,alpha:v.alpha}}const U=`varying vec2 vUv;
|
|
3
3
|
varying vec4 vScreenPos;
|
|
4
4
|
void main() {
|
|
5
5
|
vUv = uv;
|
|
6
6
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
7
7
|
vScreenPos = gl_Position;
|
|
8
|
-
}`,
|
|
8
|
+
}`,V=`varying vec2 vUv;
|
|
9
9
|
uniform vec2 uSize;
|
|
10
|
+
uniform vec2 uMeshSize;
|
|
11
|
+
uniform vec4 uShadowColor;
|
|
12
|
+
uniform vec2 uShadowOffset;
|
|
13
|
+
uniform float uShadowBlur;
|
|
14
|
+
uniform float uShadowSpread;
|
|
10
15
|
uniform vec4 uBorderRadius;
|
|
11
16
|
uniform float uBorderWidth;
|
|
12
17
|
uniform vec4 uBgColor;
|
|
@@ -62,11 +67,10 @@ float sdVisualBox(vec2 p, vec2 b, float r) {
|
|
|
62
67
|
return min(max(q.x, q.y), 0.0) + d;
|
|
63
68
|
}
|
|
64
69
|
|
|
65
|
-
vec4 calculateGradientLayer(vec2
|
|
70
|
+
vec4 calculateGradientLayer(vec2 p) {
|
|
66
71
|
if (uGradientCount < 2) return uGradientColors[0];
|
|
67
72
|
|
|
68
73
|
vec2 dir = vec2(sin(uGradientAngle), cos(uGradientAngle));
|
|
69
|
-
vec2 p = (uv - 0.5) * uSize;
|
|
70
74
|
float proj = dot(p, dir);
|
|
71
75
|
float L = abs(uSize.x * dir.x) + abs(uSize.y * dir.y);
|
|
72
76
|
float t = clamp((proj / L) + 0.5, 0.0, 1.0);
|
|
@@ -85,7 +89,7 @@ vec4 calculateGradientLayer(vec2 uv) {
|
|
|
85
89
|
}
|
|
86
90
|
|
|
87
91
|
void main() {
|
|
88
|
-
vec2 p = (vUv - 0.5) *
|
|
92
|
+
vec2 p = (vUv - 0.5) * uMeshSize;
|
|
89
93
|
vec2 halfSize = uSize * 0.5;
|
|
90
94
|
|
|
91
95
|
// CSS Proportional Border-Radius Clamping
|
|
@@ -106,7 +110,7 @@ void main() {
|
|
|
106
110
|
vec4 baseColor = vec4(uBgColor.rgb, uBgColor.a);
|
|
107
111
|
|
|
108
112
|
if (uGradientCount > 0) {
|
|
109
|
-
vec4 gradColor = calculateGradientLayer(
|
|
113
|
+
vec4 gradColor = calculateGradientLayer(p);
|
|
110
114
|
baseColor = blendSrcOver(gradColor, baseColor);
|
|
111
115
|
}
|
|
112
116
|
|
|
@@ -133,11 +137,26 @@ void main() {
|
|
|
133
137
|
|
|
134
138
|
// final blending (border + background) using blendSrcOver
|
|
135
139
|
vec4 borderLayer = vec4(uBorderColor.rgb, borderAlpha);
|
|
136
|
-
vec4
|
|
140
|
+
vec4 mainColor = blendSrcOver(borderLayer, baseColor);
|
|
141
|
+
mainColor.a *= bgMask;
|
|
142
|
+
|
|
143
|
+
vec4 shadowLayer = vec4(0.0);
|
|
144
|
+
if (uShadowColor.a > 0.001) {
|
|
145
|
+
vec2 shadowP = p - vec2(uShadowOffset.x, -uShadowOffset.y);
|
|
146
|
+
float shadowRadius = max(r + uShadowSpread, 0.0);
|
|
147
|
+
vec2 shadowHalfSize = max(halfSize + vec2(uShadowSpread), vec2(0.0));
|
|
148
|
+
float shadowD = sdRoundedBox(shadowP, shadowHalfSize, shadowRadius);
|
|
149
|
+
float blur = max(uShadowBlur, 1.0);
|
|
150
|
+
float shadowMask = 1.0 - smoothstep(-blur * 0.5, blur * 0.5, shadowD);
|
|
151
|
+
shadowLayer = vec4(uShadowColor.rgb, uShadowColor.a * shadowMask);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
vec4 finalColor = blendSrcOver(mainColor, shadowLayer);
|
|
155
|
+
|
|
137
156
|
// final color control (Tint, Noise)
|
|
138
157
|
#INJECT_COLOR_MODIFIER
|
|
139
158
|
|
|
140
|
-
float finalOpacity = finalColor.a *
|
|
159
|
+
float finalOpacity = finalColor.a * uOpacity;
|
|
141
160
|
if (finalOpacity < 0.001) discard;
|
|
142
161
|
|
|
143
162
|
gl_FragColor = vec4(finalColor.rgb, finalOpacity);
|
|
@@ -145,20 +164,21 @@ void main() {
|
|
|
145
164
|
|
|
146
165
|
// #include <colorspace_fragment>
|
|
147
166
|
}
|
|
148
|
-
`,
|
|
167
|
+
`,D=`uniform sampler2D uTexture;
|
|
149
168
|
varying vec4 vScreenPos;
|
|
150
169
|
uniform vec2 uTextureRepeat;
|
|
151
|
-
uniform vec2 uTextureOffset;`,
|
|
170
|
+
uniform vec2 uTextureOffset;`,H=`vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
|
|
152
171
|
vec2 resultUv = screenUv;
|
|
153
172
|
|
|
154
|
-
`,
|
|
155
|
-
baseColor = blendSrcOver(baseColor, texColor);`,
|
|
156
|
-
`,
|
|
157
|
-
`,
|
|
158
|
-
`,
|
|
159
|
-
`,
|
|
160
|
-
`,
|
|
173
|
+
`,N=`vec4 texColor = texture2D(uTexture, resultUv);
|
|
174
|
+
baseColor = blendSrcOver(baseColor, texColor);`,E={vertexShader:U,fragmentShader:V},L={declChunk:D,uvChunk:H,baseColorChunk:N};function z(r,o,n,t=null,e){const a=t!==null||!!r.imageSrc;let i="";const s={};if(e!=null&&e.uniforms)for(const[m,C]of Object.entries(e.uniforms))typeof C=="number"?(i+=`uniform float ${m};
|
|
175
|
+
`,s[m]={value:C}):Array.isArray(C)?C.length===2?(i+=`uniform vec2 ${m};
|
|
176
|
+
`,s[m]={value:new l.Vector2(...C)}):C.length===3?(i+=`uniform vec3 ${m};
|
|
177
|
+
`,s[m]={value:new l.Vector3(...C)}):C.length===4&&(i+=`uniform vec4 ${m};
|
|
178
|
+
`,s[m]={value:new l.Vector4(...C)}):(i+=`uniform float ${m};
|
|
179
|
+
`,s[m]={value:C});const c=e!==void 0,u=(a||c?L.declChunk:"")+`
|
|
161
180
|
`+i,d=`vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
|
|
162
|
-
`,
|
|
163
|
-
`:`vec2
|
|
164
|
-
|
|
181
|
+
`,b=r.isTraveler?`vec2 resultUv = screenUv;
|
|
182
|
+
`:`vec2 localUv = (p / uSize) + 0.5;
|
|
183
|
+
vec2 resultUv = localUv * uTextureRepeat + uTextureOffset;
|
|
184
|
+
`,v=a||c?d+b+((e==null?void 0:e.uvModifier)||""):"",h=a||c?L.baseColorChunk:"",g=(e==null?void 0:e.colorModifier)||"",M=E.fragmentShader.replace("#INJECT_DECLARATIONS",u).replace("#INJECT_UV_MODIFIER",v).replace("#INJECT_BASE_COLOR",h).replace("#INJECT_COLOR_MODIFIER",g),B=y(r.backgroundColor),x=y(r.borderColor),I={uSize:{value:new l.Vector2(o,n)},uMeshSize:{value:new l.Vector2(o,n)},uShadowColor:{value:new l.Vector4(0,0,0,0)},uShadowOffset:{value:new l.Vector2(0,0)},uShadowBlur:{value:0},uShadowSpread:{value:0},uBgColor:{value:new l.Vector4(B.color.r,B.color.g,B.color.b,B.alpha)},uBorderColor:{value:new l.Vector4(x.color.r,x.color.g,x.color.b,x.alpha)},uBorderRadius:{value:new l.Vector4(0,0,0,0)},uBorderWidth:{value:S(r.borderWidth)},uOpacity:{value:r.opacity??1},uTexture:{value:null},uTextureRepeat:{value:new l.Vector2(1,1)},uTextureOffset:{value:new l.Vector2(0,0)},uGradientCount:{value:0},uGradientAngle:{value:0},uGradientColors:{value:Array.from({length:8},()=>new l.Vector4(0,0,0,0))},uGradientStops:{value:new Float32Array(8)}};W(I.uBorderRadius.value,r.borderRadius,Math.min(o,n)),a&&(I.uTexture.value=t);const _=new l.ShaderMaterial({uniforms:{...I,...s},vertexShader:E.vertexShader,fragmentShader:M,transparent:!0,side:l.FrontSide});return r.backgroundImage&&O(_,{backgroundImage:r.backgroundImage}),_}function F(r,o,n,t,e){const a=S(o.borderWidth);O(r,{width:n,height:t,borderRadius:o.borderRadius,borderWidth:a,backgroundColor:o.backgroundColor,borderColor:o.borderColor,opacity:o.opacity,texture:e,backgroundImage:o.backgroundImage,boxShadow:o.boxShadow})}function O(r,o){var t;if(o.boxShadow!==void 0){const e=G(o.boxShadow);e?(r.uniforms.uShadowColor.value.set(e.color.r,e.color.g,e.color.b,e.alpha),r.uniforms.uShadowOffset.value.set(e.offsetX,e.offsetY),r.uniforms.uShadowBlur.value=e.blurRadius,r.uniforms.uShadowSpread.value=e.spreadRadius,r.userData.shadowPadding=e.blurRadius+e.spreadRadius+Math.max(Math.abs(e.offsetX),Math.abs(e.offsetY))):(r.uniforms.uShadowColor.value.w=0,r.userData.shadowPadding=0)}if(o.width!==void 0&&o.height!==void 0&&r.uniforms.uSize.value.set(o.width,o.height),r.uniforms.uMeshSize){const e=r.userData.shadowPadding||0,a=o.width!==void 0?o.width:r.uniforms.uSize.value.x,i=o.height!==void 0?o.height:r.uniforms.uSize.value.y;r.uniforms.uMeshSize.value.set(a+e*2,i+e*2)}if(o.borderRadius!==void 0){const e=o.width!==void 0&&o.height!==void 0?Math.min(o.width,o.height):Math.min(r.uniforms.uSize.value.x,r.uniforms.uSize.value.y);W(r.uniforms.uBorderRadius.value,o.borderRadius,e)}if(o.borderWidth!==void 0&&(r.uniforms.uBorderWidth.value=o.borderWidth),o.backgroundColor!==void 0)if(Array.isArray(o.backgroundColor)){const e=r.uniforms.uBgColor.value.w;r.uniforms.uBgColor.value.set(o.backgroundColor[0],o.backgroundColor[1],o.backgroundColor[2],e)}else if(typeof o.backgroundColor=="string"){const e=y(o.backgroundColor);r.uniforms.uBgColor.value.set(e.color.r,e.color.g,e.color.b,e.alpha)}else{const e=r.uniforms.uBgColor.value.w;r.uniforms.uBgColor.value.set(o.backgroundColor.r,o.backgroundColor.g,o.backgroundColor.b,e)}if(o.borderColor!==void 0)if(Array.isArray(o.borderColor)){const e=r.uniforms.uBorderColor.value.w;r.uniforms.uBorderColor.value.set(o.borderColor[0],o.borderColor[1],o.borderColor[2],e)}else if(typeof o.borderColor=="string"){const e=y(o.borderColor);r.uniforms.uBorderColor.value.set(e.color.r,e.color.g,e.color.b,e.alpha)}else{const e=r.uniforms.uBorderColor.value.w;r.uniforms.uBorderColor.value.set(o.borderColor.r,o.borderColor.g,o.borderColor.b,e)}o.opacity!==void 0&&(r.uniforms.uOpacity.value=o.opacity),o.bgOpacity!==void 0&&(r.uniforms.uBgColor.value.w=o.bgOpacity),o.borderOpacity!==void 0&&(r.uniforms.uBorderColor.value.w=o.borderOpacity),r.uniforms.uTexture&&o.texture!==void 0&&(r.uniforms.uTexture.value=o.texture);const n=o.texture!==void 0?o.texture:(t=r.uniforms.uTexture)==null?void 0:t.value;if(n&&(n.image instanceof ImageBitmap||n.image instanceof HTMLImageElement||n.image instanceof HTMLCanvasElement)){const e=n.image.naturalWidth||n.image.videoWidth||n.image.width,a=n.image.naturalHeight||n.image.videoHeight||n.image.height,i=o.width??r.uniforms.uSize.value.x,s=o.height??r.uniforms.uSize.value.y;if(e&&a&&i&&s){const c=e/a,u=i/s;if(c>u){const d=u/c;r.uniforms.uTextureRepeat.value.set(d,1),r.uniforms.uTextureOffset.value.set((1-d)/2,0)}else{const d=c/u;r.uniforms.uTextureRepeat.value.set(1,d),r.uniforms.uTextureOffset.value.set(0,(1-d)/2)}}}else r.uniforms.uTextureRepeat&&(r.uniforms.uTextureRepeat.value.set(1,1),r.uniforms.uTextureOffset.value.set(0,0));if(o.backgroundImage!==void 0){const e=k(o.backgroundImage);if(e){r.uniforms.uGradientCount.value=e.stops.length,r.uniforms.uGradientAngle.value=e.angle;for(let a=0;a<8;a++)if(a<e.stops.length){const i=e.stops[a];r.uniforms.uGradientColors.value[a].set(i.color.r,i.color.g,i.color.b,i.alpha),r.uniforms.uGradientStops.value[a]=i.stop}else r.uniforms.uGradientColors.value[a].set(0,0,0,0),r.uniforms.uGradientStops.value[a]=1}else r.uniforms.uGradientCount.value=0}for(const e of Object.keys(o))e!=="width"&&e!=="height"&&e!=="borderRadius"&&e!=="borderWidth"&&e!=="backgroundColor"&&e!=="borderColor"&&e!=="opacity"&&e!=="bgOpacity"&&e!=="borderOpacity"&&e!=="texture"&&e!=="backgroundImage"&&e!=="boxShadow"&&r.uniforms[e]!==void 0&&(r.uniforms[e].value!==void 0&&r.uniforms[e].value!==null&&typeof r.uniforms[e].value.set=="function"?Array.isArray(o[e])?r.uniforms[e].value.set(...o[e]):o[e]!==void 0&&(o[e].copy?r.uniforms[e].value.copy(o[e]):r.uniforms[e].value=o[e]):r.uniforms[e].value=o[e])}function W(r,o,n=0){if(o==null){r.set(0,0,0,0);return}if(typeof o=="number"){r.set(o,o,o,o);return}if(Array.isArray(o)){r.set(o[0],o[1],o[2],o[3]);return}const t=o.split("/")[0].trim().split(/\s+/),e=S(t[0],n),a=S(t[1]??t[0],n),i=S(t[2]??t[0],n),s=S(t[3]??t[1]??t[0],n);r.set(e,a,i,s)}const q={create(r,o,n,t,e,a=2,i=null,s){return r==="BOX"?z(o,t,e,i,s):r==="TEXT"?new A(n||"",o,t,e,a):new l.MeshBasicMaterial({visible:!1})},update(r,o,n,t,e,a,i=2,s){o==="BOX"?F(r,n,e,a,s):o==="TEXT"&&r.updateText(t||"",n,e,a,i)},forceUpdateUniforms(r,o){O(r,o)}};f.Painter=q,f.TextGenerator=A,f.createBoxMaterial=z,f.parseBoxShadow=G,f.parseColor=y,f.parseLinearGradient=k,f.parsePixelValue=S,f.setBoxUniforms=O,f.splitByComma=R,f.updateBoxMaterial=F,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -14,6 +14,7 @@ export interface BoxUniformValues {
|
|
|
14
14
|
borderOpacity?: number;
|
|
15
15
|
texture?: THREE.Texture | null;
|
|
16
16
|
backgroundImage?: string;
|
|
17
|
+
boxShadow?: string;
|
|
17
18
|
[key: string]: any;
|
|
18
19
|
}
|
|
19
20
|
export declare function setBoxUniforms(material: THREE.ShaderMaterial, values: BoxUniformValues): void;
|
|
@@ -14,3 +14,11 @@ export declare function parseLinearGradient(value: string | null | undefined): {
|
|
|
14
14
|
stop: number;
|
|
15
15
|
}[];
|
|
16
16
|
} | null;
|
|
17
|
+
export declare function parseBoxShadow(value: string | null | undefined): {
|
|
18
|
+
offsetX: number;
|
|
19
|
+
offsetY: number;
|
|
20
|
+
blurRadius: number;
|
|
21
|
+
spreadRadius: number;
|
|
22
|
+
color: THREE.Color;
|
|
23
|
+
alpha: number;
|
|
24
|
+
} | null;
|
|
@@ -7,6 +7,7 @@ export interface TextStyles {
|
|
|
7
7
|
direction: CanvasDirection;
|
|
8
8
|
lineHeight: number;
|
|
9
9
|
letterSpacing: number;
|
|
10
|
+
transform?: string;
|
|
10
11
|
}
|
|
11
12
|
export interface BoxStyles {
|
|
12
13
|
backgroundColor: string;
|
|
@@ -18,6 +19,8 @@ export interface BoxStyles {
|
|
|
18
19
|
borderRadius: string;
|
|
19
20
|
borderColor: string;
|
|
20
21
|
borderWidth: string;
|
|
22
|
+
transform?: string;
|
|
23
|
+
boxShadow?: string;
|
|
21
24
|
}
|
|
22
25
|
export interface ShaderHooks {
|
|
23
26
|
uvModifier?: string;
|
package/package.json
CHANGED
package/src/Box/BoxGenerator.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
parsePixelValue,
|
|
5
5
|
parseColor,
|
|
6
6
|
parseLinearGradient,
|
|
7
|
+
parseBoxShadow,
|
|
7
8
|
} from "../tools/parser";
|
|
8
9
|
import { BoxShader, BoxChunk } from "../shaders/index";
|
|
9
10
|
|
|
@@ -45,7 +46,7 @@ export function createBoxMaterial(
|
|
|
45
46
|
const hasHooks = hooks !== undefined;
|
|
46
47
|
const declChunk = (hasTexture || hasHooks ? BoxChunk.declChunk : "") + "\n" + customUniformsCode;
|
|
47
48
|
const screenUvDecl = "vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;\n";
|
|
48
|
-
const baseUvCode = styles.isTraveler ? "vec2 resultUv = screenUv;\n" : "vec2 resultUv =
|
|
49
|
+
const baseUvCode = styles.isTraveler ? "vec2 resultUv = screenUv;\n" : "vec2 localUv = (p / uSize) + 0.5;\nvec2 resultUv = localUv * uTextureRepeat + uTextureOffset;\n";
|
|
49
50
|
const uvChunk = (hasTexture || hasHooks) ? screenUvDecl + baseUvCode + (hooks?.uvModifier || "") : "";
|
|
50
51
|
const baseColorChunk = (hasTexture || hasHooks) ? BoxChunk.baseColorChunk : "";
|
|
51
52
|
const colorModChunk = hooks?.colorModifier || "";
|
|
@@ -61,6 +62,11 @@ export function createBoxMaterial(
|
|
|
61
62
|
const parsedBorder = parseColor(styles.borderColor);
|
|
62
63
|
const uniforms = {
|
|
63
64
|
uSize: { value: new THREE.Vector2(width, height) },
|
|
65
|
+
uMeshSize: { value: new THREE.Vector2(width, height) },
|
|
66
|
+
uShadowColor: { value: new THREE.Vector4(0, 0, 0, 0) },
|
|
67
|
+
uShadowOffset: { value: new THREE.Vector2(0, 0) },
|
|
68
|
+
uShadowBlur: { value: 0 },
|
|
69
|
+
uShadowSpread: { value: 0 },
|
|
64
70
|
uBgColor: {
|
|
65
71
|
value: new THREE.Vector4(
|
|
66
72
|
parsedBg.color.r,
|
|
@@ -132,6 +138,7 @@ export function updateBoxMaterial(
|
|
|
132
138
|
opacity: styles.opacity,
|
|
133
139
|
texture,
|
|
134
140
|
backgroundImage: styles.backgroundImage,
|
|
141
|
+
boxShadow: styles.boxShadow,
|
|
135
142
|
});
|
|
136
143
|
}
|
|
137
144
|
|
|
@@ -147,6 +154,7 @@ export interface BoxUniformValues {
|
|
|
147
154
|
borderOpacity?: number;
|
|
148
155
|
texture?: THREE.Texture | null;
|
|
149
156
|
backgroundImage?: string;
|
|
157
|
+
boxShadow?: string;
|
|
150
158
|
[key: string]: any;
|
|
151
159
|
}
|
|
152
160
|
|
|
@@ -154,9 +162,31 @@ export function setBoxUniforms(
|
|
|
154
162
|
material: THREE.ShaderMaterial,
|
|
155
163
|
values: BoxUniformValues,
|
|
156
164
|
) {
|
|
165
|
+
if (values.boxShadow !== undefined) {
|
|
166
|
+
const shadow = parseBoxShadow(values.boxShadow);
|
|
167
|
+
if (shadow) {
|
|
168
|
+
material.uniforms.uShadowColor.value.set(shadow.color.r, shadow.color.g, shadow.color.b, shadow.alpha);
|
|
169
|
+
material.uniforms.uShadowOffset.value.set(shadow.offsetX, shadow.offsetY);
|
|
170
|
+
material.uniforms.uShadowBlur.value = shadow.blurRadius;
|
|
171
|
+
material.uniforms.uShadowSpread.value = shadow.spreadRadius;
|
|
172
|
+
material.userData.shadowPadding = shadow.blurRadius + shadow.spreadRadius + Math.max(Math.abs(shadow.offsetX), Math.abs(shadow.offsetY));
|
|
173
|
+
} else {
|
|
174
|
+
material.uniforms.uShadowColor.value.w = 0;
|
|
175
|
+
material.userData.shadowPadding = 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
157
179
|
if (values.width !== undefined && values.height !== undefined) {
|
|
158
180
|
material.uniforms.uSize.value.set(values.width, values.height);
|
|
159
181
|
}
|
|
182
|
+
|
|
183
|
+
if (material.uniforms.uMeshSize) {
|
|
184
|
+
const pad = material.userData.shadowPadding || 0;
|
|
185
|
+
const cw = values.width !== undefined ? values.width : material.uniforms.uSize.value.x;
|
|
186
|
+
const ch = values.height !== undefined ? values.height : material.uniforms.uSize.value.y;
|
|
187
|
+
material.uniforms.uMeshSize.value.set(cw + pad * 2, ch + pad * 2);
|
|
188
|
+
}
|
|
189
|
+
|
|
160
190
|
if (values.borderRadius !== undefined) {
|
|
161
191
|
const baseSize = values.width !== undefined && values.height !== undefined
|
|
162
192
|
? Math.min(values.width, values.height)
|
|
@@ -301,7 +331,8 @@ export function setBoxUniforms(
|
|
|
301
331
|
key !== "bgOpacity" &&
|
|
302
332
|
key !== "borderOpacity" &&
|
|
303
333
|
key !== "texture" &&
|
|
304
|
-
key !== "backgroundImage"
|
|
334
|
+
key !== "backgroundImage" &&
|
|
335
|
+
key !== "boxShadow"
|
|
305
336
|
) {
|
|
306
337
|
if (material.uniforms[key] !== undefined) {
|
|
307
338
|
if (
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
varying vec2 vUv;
|
|
2
2
|
uniform vec2 uSize;
|
|
3
|
+
uniform vec2 uMeshSize;
|
|
4
|
+
uniform vec4 uShadowColor;
|
|
5
|
+
uniform vec2 uShadowOffset;
|
|
6
|
+
uniform float uShadowBlur;
|
|
7
|
+
uniform float uShadowSpread;
|
|
3
8
|
uniform vec4 uBorderRadius;
|
|
4
9
|
uniform float uBorderWidth;
|
|
5
10
|
uniform vec4 uBgColor;
|
|
@@ -55,11 +60,10 @@ float sdVisualBox(vec2 p, vec2 b, float r) {
|
|
|
55
60
|
return min(max(q.x, q.y), 0.0) + d;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
vec4 calculateGradientLayer(vec2
|
|
63
|
+
vec4 calculateGradientLayer(vec2 p) {
|
|
59
64
|
if (uGradientCount < 2) return uGradientColors[0];
|
|
60
65
|
|
|
61
66
|
vec2 dir = vec2(sin(uGradientAngle), cos(uGradientAngle));
|
|
62
|
-
vec2 p = (uv - 0.5) * uSize;
|
|
63
67
|
float proj = dot(p, dir);
|
|
64
68
|
float L = abs(uSize.x * dir.x) + abs(uSize.y * dir.y);
|
|
65
69
|
float t = clamp((proj / L) + 0.5, 0.0, 1.0);
|
|
@@ -78,7 +82,7 @@ vec4 calculateGradientLayer(vec2 uv) {
|
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
void main() {
|
|
81
|
-
vec2 p = (vUv - 0.5) *
|
|
85
|
+
vec2 p = (vUv - 0.5) * uMeshSize;
|
|
82
86
|
vec2 halfSize = uSize * 0.5;
|
|
83
87
|
|
|
84
88
|
// CSS Proportional Border-Radius Clamping
|
|
@@ -99,7 +103,7 @@ void main() {
|
|
|
99
103
|
vec4 baseColor = vec4(uBgColor.rgb, uBgColor.a);
|
|
100
104
|
|
|
101
105
|
if (uGradientCount > 0) {
|
|
102
|
-
vec4 gradColor = calculateGradientLayer(
|
|
106
|
+
vec4 gradColor = calculateGradientLayer(p);
|
|
103
107
|
baseColor = blendSrcOver(gradColor, baseColor);
|
|
104
108
|
}
|
|
105
109
|
|
|
@@ -126,11 +130,26 @@ void main() {
|
|
|
126
130
|
|
|
127
131
|
// final blending (border + background) using blendSrcOver
|
|
128
132
|
vec4 borderLayer = vec4(uBorderColor.rgb, borderAlpha);
|
|
129
|
-
vec4
|
|
133
|
+
vec4 mainColor = blendSrcOver(borderLayer, baseColor);
|
|
134
|
+
mainColor.a *= bgMask;
|
|
135
|
+
|
|
136
|
+
vec4 shadowLayer = vec4(0.0);
|
|
137
|
+
if (uShadowColor.a > 0.001) {
|
|
138
|
+
vec2 shadowP = p - vec2(uShadowOffset.x, -uShadowOffset.y);
|
|
139
|
+
float shadowRadius = max(r + uShadowSpread, 0.0);
|
|
140
|
+
vec2 shadowHalfSize = max(halfSize + vec2(uShadowSpread), vec2(0.0));
|
|
141
|
+
float shadowD = sdRoundedBox(shadowP, shadowHalfSize, shadowRadius);
|
|
142
|
+
float blur = max(uShadowBlur, 1.0);
|
|
143
|
+
float shadowMask = 1.0 - smoothstep(-blur * 0.5, blur * 0.5, shadowD);
|
|
144
|
+
shadowLayer = vec4(uShadowColor.rgb, uShadowColor.a * shadowMask);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
vec4 finalColor = blendSrcOver(mainColor, shadowLayer);
|
|
148
|
+
|
|
130
149
|
// final color control (Tint, Noise)
|
|
131
150
|
#INJECT_COLOR_MODIFIER
|
|
132
151
|
|
|
133
|
-
float finalOpacity = finalColor.a *
|
|
152
|
+
float finalOpacity = finalColor.a * uOpacity;
|
|
134
153
|
if (finalOpacity < 0.001) discard;
|
|
135
154
|
|
|
136
155
|
gl_FragColor = vec4(finalColor.rgb, finalOpacity);
|
package/src/tools/parser.ts
CHANGED
|
@@ -150,3 +150,37 @@ export function parseLinearGradient(value: string | null | undefined) {
|
|
|
150
150
|
|
|
151
151
|
return { angle, stops };
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
export function parseBoxShadow(value: string | null | undefined) {
|
|
155
|
+
if (!value || value === "none") return null;
|
|
156
|
+
|
|
157
|
+
const shadows = splitByComma(value);
|
|
158
|
+
if (shadows.length === 0) return null;
|
|
159
|
+
const shadowStr = shadows[0].trim();
|
|
160
|
+
|
|
161
|
+
const colorRegex = /(rgba?\([^)]+\)|#[0-9a-fA-F]+|[a-zA-Z]+)/;
|
|
162
|
+
const colorMatch = shadowStr.match(colorRegex);
|
|
163
|
+
|
|
164
|
+
let colorStr = "transparent";
|
|
165
|
+
let restStr = shadowStr;
|
|
166
|
+
|
|
167
|
+
if (colorMatch && colorMatch[1] !== 'inset') {
|
|
168
|
+
const c = colorMatch[1];
|
|
169
|
+
if (c.startsWith("rgb") || c.startsWith("#") || c === "black" || c === "white" || c === "transparent") {
|
|
170
|
+
colorStr = c;
|
|
171
|
+
restStr = shadowStr.replace(c, "").trim();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
restStr = restStr.replace("inset", "").trim();
|
|
176
|
+
const lengths = restStr.split(/\s+/).map(s => parseFloat(s) || 0);
|
|
177
|
+
|
|
178
|
+
const offsetX = lengths[0] || 0;
|
|
179
|
+
const offsetY = lengths[1] || 0;
|
|
180
|
+
const blurRadius = lengths[2] || 0;
|
|
181
|
+
const spreadRadius = lengths[3] || 0;
|
|
182
|
+
|
|
183
|
+
const color = parseColor(colorStr);
|
|
184
|
+
|
|
185
|
+
return { offsetX, offsetY, blurRadius, spreadRadius, color: color.color, alpha: color.alpha };
|
|
186
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
--- packages/painter/src/tools/parser.ts
|
|
2
|
+
+++ packages/painter/src/tools/parser.ts
|
|
3
|
+
@@ -194,2 +194,37 @@
|
|
4
|
+
return { angle, stops };
|
|
5
|
+
}
|
|
6
|
+
+
|
|
7
|
+
+export function parseBoxShadow(value: string | null | undefined) {
|
|
8
|
+
+ if (!value || value === "none") return null;
|
|
9
|
+
+
|
|
10
|
+
+ const shadows = splitByComma(value);
|
|
11
|
+
+ if (shadows.length === 0) return null;
|
|
12
|
+
+ const shadowStr = shadows[0].trim();
|
|
13
|
+
+
|
|
14
|
+
+ const colorRegex = /(rgba?\([^)]+\)|#[0-9a-fA-F]+|[a-zA-Z]+)/;
|
|
15
|
+
+ const colorMatch = shadowStr.match(colorRegex);
|
|
16
|
+
+
|
|
17
|
+
+ let colorStr = "transparent";
|
|
18
|
+
+ let restStr = shadowStr;
|
|
19
|
+
+
|
|
20
|
+
+ if (colorMatch && colorMatch[1] !== 'inset') {
|
|
21
|
+
+ const c = colorMatch[1];
|
|
22
|
+
+ if (c.startsWith("rgb") || c.startsWith("#") || c === "black" || c === "white" || c === "transparent") {
|
|
23
|
+
+ colorStr = c;
|
|
24
|
+
+ restStr = shadowStr.replace(c, "").trim();
|
|
25
|
+
+ }
|
|
26
|
+
+ }
|
|
27
|
+
+
|
|
28
|
+
+ restStr = restStr.replace("inset", "").trim();
|
|
29
|
+
+ const lengths = restStr.split(/\s+/).map(s => parseFloat(s) || 0);
|
|
30
|
+
+
|
|
31
|
+
+ const offsetX = lengths[0] || 0;
|
|
32
|
+
+ const offsetY = lengths[1] || 0;
|
|
33
|
+
+ const blurRadius = lengths[2] || 0;
|
|
34
|
+
+ const spreadRadius = lengths[3] || 0;
|
|
35
|
+
+
|
|
36
|
+
+ const color = parseColor(colorStr);
|
|
37
|
+
+
|
|
38
|
+
+ return { offsetX, offsetY, blurRadius, spreadRadius, color: color.color, alpha: color.alpha };
|
|
39
|
+
+}
|
package/src/types/common.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface TextStyles {
|
|
|
8
8
|
direction: CanvasDirection;
|
|
9
9
|
lineHeight: number; // px
|
|
10
10
|
letterSpacing: number; // px
|
|
11
|
+
transform?: string;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
export interface BoxStyles {
|
|
@@ -20,6 +21,8 @@ export interface BoxStyles {
|
|
|
20
21
|
borderRadius: string;
|
|
21
22
|
borderColor: string;
|
|
22
23
|
borderWidth: string;
|
|
24
|
+
transform?: string;
|
|
25
|
+
boxShadow?: string;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export interface ShaderHooks {
|