@mirage-engine/painter 0.4.0 → 1.0.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/CHANGELOG.md +12 -0
- package/dist/mirage-painter.js +491 -191
- package/dist/mirage-painter.umd.js +138 -72
- package/dist/src/Box/BoxGenerator.d.ts +19 -0
- package/dist/src/Painter.d.ts +5 -3
- package/dist/src/Text/FontMetricsManager.d.ts +10 -0
- package/dist/src/Text/TextGenerator.d.ts +11 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/shaders/index.d.ts +9 -0
- package/dist/src/tools/parser.d.ts +16 -0
- package/dist/src/types/common.d.ts +5 -0
- package/package.json +1 -1
- package/src/Box/BoxGenerator.ts +350 -0
- package/src/Painter.ts +30 -27
- package/src/Text/FontMetricsManager.ts +62 -0
- package/src/Text/TextGenerator.ts +123 -0
- package/src/env.d.ts +4 -0
- package/src/index.ts +4 -3
- package/src/shaders/base/box-fragment.glsl +129 -0
- package/src/shaders/base/box-vertex.glsl +7 -0
- package/src/shaders/chunk/base-color-chunk.glsl +2 -0
- package/src/shaders/chunk/decl-chunk.glsl +4 -0
- package/src/shaders/chunk/uv-chunk.glsl +3 -0
- package/src/shaders/index.ts +16 -0
- package/src/tools/parser.ts +148 -0
- package/src/types/common.ts +5 -1
- package/dist/src/BoxGenerator.d.ts +0 -4
- package/dist/src/TextGenerator.d.ts +0 -3
- package/dist/src/dev/devShader.d.ts +0 -5
- package/src/BoxGenerator.ts +0 -236
- package/src/TextGenerator.ts +0 -85
- package/src/dev/devShader.ts +0 -114
|
@@ -1,85 +1,151 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
`),
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
(function(f,h){typeof exports=="object"&&typeof module<"u"?h(exports,require("three")):typeof define=="function"&&define.amd?define(["exports","three"],h):(f=typeof globalThis<"u"?globalThis:f||self,h(f.MiragePainter={},f.THREE))})(this,function(f,h){"use strict";var N=Object.defineProperty;var q=(f,h,C)=>h in f?N(f,h,{enumerable:!0,configurable:!0,writable:!0,value:C}):f[h]=C;var O=(f,h,C)=>(q(f,typeof h!="symbol"?h+"":h,C),C);function C(r){const o=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const i=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(o,t,i.get?i:{enumerable:!0,get:()=>r[t]})}}return o.default=r,Object.freeze(o)}const u=C(h);class M{static getBaseline(o){if(this.cache.has(o))return this.cache.get(o);const t=this.calculateBaselineFromDOM(o);return this.cache.set(o,t),t}static calculateBaselineFromDOM(o){if(typeof document>"u")return 0;const t=document.createElement("div"),i=document.createElement("span"),e=document.createElement("img");t.style.visibility="hidden",t.style.position="absolute",t.style.top="0px",t.style.left="0px",t.style.font=o,t.style.margin="0",t.style.padding="0",t.style.border="none",i.style.margin="0",i.style.padding="0",i.style.border="none",i.style.lineHeight="normal",e.width=1,e.height=1,e.style.verticalAlign="baseline",i.appendChild(document.createTextNode("Hidden Text")),t.appendChild(i),t.appendChild(e),document.body.appendChild(t);const a=e.offsetTop-i.offsetTop;return document.body.removeChild(t),a}}O(M,"cache",new Map);class R extends u.MeshBasicMaterial{constructor(t,i,e,a,n=2){super({transparent:!0,side:u.FrontSide,color:16777215});O(this,"canvas");O(this,"ctx");O(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=n,this.map=new u.CanvasTexture(this.canvas),this.map.colorSpace=u.LinearSRGBColorSpace,this.map.minFilter=u.LinearFilter,this.map.magFilter=u.LinearFilter,this.updateText(t,i,e,a)}wrapText(t,i){const e=t.split(`
|
|
2
|
+
`),a=[];return e.forEach(n=>{const c=n.match(/[^\s\-]+\-?|\-|\s+/g)||[];if(c.length===0){a.push("");return}let s=c[0];for(let l=1;l<c.length;l++){const d=c[l];this.ctx.measureText(s+d).width<=i+2?s+=d:(s&&a.push(s),s=d.trimStart())}s&&a.push(s)}),a}updateText(t,i,e,a,n){n!==void 0&&(this.qualityFactor=n);const s=(window.devicePixelRatio||1)*this.qualityFactor,l=e*s,d=a*s;this.canvas.width!==l||this.canvas.height!==d?(this.canvas.width=l,this.canvas.height=d):this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.setTransform(s,0,0,s,0,0),this.ctx.font=i.font,this.ctx.fillStyle=i.color,this.ctx.textBaseline="alphabetic",this.ctx.globalAlpha=1;const g=this.wrapText(t,e),y=i.lineHeight,m=M.getBaseline(i.font);g.forEach((p,T)=>{const B=T*y+m;let w=0;i.textAlign==="center"?w=e/2:i.textAlign==="right"&&(w=e),this.ctx.textAlign=i.textAlign,this.ctx.fillText(p,w,B)}),this.map&&(this.map.needsUpdate=!0)}dispose(){this.map&&this.map.dispose(),super.dispose()}}function x(r){return typeof r=="number"?r:parseFloat(r)||0}function S(r){if(!r||r==="transparent")return{color:new u.Color(16777215),alpha:0};const o=r.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);if(o){const t=parseInt(o[1],10),i=parseInt(o[2],10),e=parseInt(o[3],10),a=o[4]!==void 0?parseFloat(o[4]):1;return{color:new u.Color(`rgb(${t}, ${i}, ${e})`),alpha:a}}return{color:new u.Color(r),alpha:1}}function k(r){const o=[];let t="",i=0;for(let e=0;e<r.length;e++){const a=r[e];if(a==="(")i++;else if(a===")")i--;else if(a===","&&i===0){o.push(t.trim()),t="";continue}t+=a}return t&&o.push(t.trim()),o}function P(r){if(!r||typeof r!="string"||!r.includes("linear-gradient"))return null;const o=r.match(/linear-gradient\((.*)\)/);if(!o)return null;const t=o[1],i=k(t);let e=Math.PI,a=0;const n=i[0].trim();if(n.startsWith("to "))n==="to top"?e=0:n==="to right"?e=Math.PI/2:n==="to bottom"?e=Math.PI:n==="to left"?e=Math.PI*1.5:n==="to top right"||n==="to right top"?e=Math.PI/4:n==="to bottom right"||n==="to right bottom"?e=Math.PI*.75:n==="to bottom left"||n==="to left bottom"?e=Math.PI*1.25:(n==="to top left"||n==="to left top")&&(e=Math.PI*1.75),a=1;else if(n.endsWith("deg")||n.endsWith("rad")||n.endsWith("turn")){const s=parseFloat(n);n.endsWith("deg")?e=s*(Math.PI/180):n.endsWith("rad")?e=s:n.endsWith("turn")&&(e=s*Math.PI*2),a=1}const c=[];for(let s=a;s<i.length&&!(c.length>=8);s++){const l=i[s].trim(),d=l.lastIndexOf(" ");let g=l,y=null;if(d!==-1&&!l.endsWith(")")){const p=l.substring(d+1);(p.endsWith("%")||p.endsWith("px")||!isNaN(parseFloat(p)))&&(g=l.substring(0,d).trim(),y=p)}const m=S(g);c.push({color:m.color,alpha:m.alpha,rawStop:y,stop:0})}if(c.length>0){for(let l=0;l<c.length;l++)c[l].rawStop!==null&&(c[l].stop=parseFloat(c[l].rawStop)/100);c[0].rawStop===null&&(c[0].stop=0),c.length>1&&c[c.length-1].rawStop===null&&(c[c.length-1].stop=1);let s=0;for(let l=1;l<c.length;l++)if(c[l].rawStop!==null||l===c.length-1){const d=l-s;if(d>1){const g=c[s].stop,m=(c[l].stop-g)/d;for(let p=1;p<d;p++)c[s+p].stop=g+m*p}s=l}}return{angle:e,stops:c}}const F=`varying vec2 vUv;
|
|
3
|
+
varying vec4 vScreenPos;
|
|
4
|
+
void main() {
|
|
5
|
+
vUv = uv;
|
|
6
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
7
|
+
vScreenPos = gl_Position;
|
|
8
|
+
}`,W=`varying vec2 vUv;
|
|
9
|
+
uniform vec2 uSize;
|
|
10
|
+
uniform vec4 uBorderRadius;
|
|
11
|
+
uniform float uBorderWidth;
|
|
12
|
+
uniform vec4 uBgColor;
|
|
13
|
+
uniform vec4 uBorderColor;
|
|
14
|
+
uniform float uOpacity;
|
|
15
|
+
|
|
16
|
+
uniform int uGradientCount;
|
|
17
|
+
uniform float uGradientAngle;
|
|
18
|
+
uniform vec4 uGradientColors[8];
|
|
19
|
+
uniform float uGradientStops[8];
|
|
20
|
+
|
|
21
|
+
#INJECT_DECLARATIONS
|
|
22
|
+
|
|
23
|
+
vec3 linearToSrgb(vec3 linearColor) {
|
|
24
|
+
vec3 linearPart = 12.92 * linearColor;
|
|
25
|
+
vec3 curvePart = 1.055 * pow(linearColor, vec3(1.0 / 2.4)) - 0.055;
|
|
26
|
+
vec3 switchCondition = step(vec3(0.0031308), linearColor);
|
|
27
|
+
return mix(linearPart, curvePart, switchCondition);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
vec3 srgbToLinear(vec3 srgbColor) {
|
|
31
|
+
vec3 linearPart = srgbColor / 12.92;
|
|
32
|
+
vec3 curvePart = pow((srgbColor + vec3(0.055)) / 1.055, vec3(2.4));
|
|
33
|
+
vec3 switchCondition = step(vec3(0.04045), srgbColor);
|
|
34
|
+
return mix(linearPart, curvePart, switchCondition);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
vec4 blendSrcOverInLinear(vec4 front, vec4 back) {
|
|
38
|
+
front.rgb = srgbToLinear(front.rgb);
|
|
39
|
+
back.rgb = srgbToLinear(back.rgb);
|
|
40
|
+
float aOut = front.a + back.a * (1.0 - front.a);
|
|
41
|
+
float safeAlpha = max(aOut, 0.0001);
|
|
42
|
+
vec3 cOut = (front.rgb * front.a + back.rgb * back.a * (1.0 - front.a)) / safeAlpha;
|
|
43
|
+
return vec4(linearToSrgb(cOut), aOut);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
vec4 blendSrcOver(vec4 front, vec4 back) {
|
|
47
|
+
float aOut = front.a + back.a * (1.0 - front.a);
|
|
48
|
+
float safeAlpha = max(aOut, 0.0001);
|
|
49
|
+
vec3 cOut = (front.rgb * front.a + back.rgb * back.a * (1.0 - front.a)) / safeAlpha;
|
|
50
|
+
return vec4(cOut, aOut);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
float sdRoundedBox(vec2 p, vec2 b, float r) {
|
|
54
|
+
vec2 q = abs(p) - b + r;
|
|
55
|
+
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
float sdVisualBox(vec2 p, vec2 b, float r) {
|
|
59
|
+
vec2 q = abs(p) - b + r;
|
|
60
|
+
float n = 2.01;
|
|
61
|
+
float d = pow(pow(max(q.x, 0.0), n) + pow(max(q.y, 0.0), n), 1.0/n) - r;
|
|
62
|
+
return min(max(q.x, q.y), 0.0) + d;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
vec4 calculateGradientLayer(vec2 uv) {
|
|
66
|
+
if (uGradientCount < 2) return uGradientColors[0];
|
|
67
|
+
|
|
68
|
+
vec2 dir = vec2(sin(uGradientAngle), cos(uGradientAngle));
|
|
69
|
+
vec2 p = (uv - 0.5) * uSize;
|
|
70
|
+
float proj = dot(p, dir);
|
|
71
|
+
float L = abs(uSize.x * dir.x) + abs(uSize.y * dir.y);
|
|
72
|
+
float t = clamp((proj / L) + 0.5, 0.0, 1.0);
|
|
13
73
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
uniform float uOpacity;
|
|
20
|
-
uniform float uBgOpacity;
|
|
21
|
-
uniform float uBorderOpacity;
|
|
22
|
-
|
|
23
|
-
#INJECT_DECLARATIONS
|
|
24
|
-
|
|
25
|
-
float sdRoundedBox(vec2 p, vec2 b, float r) {
|
|
26
|
-
vec2 q = abs(p) - b + r;
|
|
27
|
-
|
|
28
|
-
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
void main() {
|
|
32
|
-
vec2 p = (vUv - 0.5) * uSize;
|
|
33
|
-
vec2 halfSize = uSize * 0.5;
|
|
34
|
-
|
|
35
|
-
#INJECT_UV_MODIFIER
|
|
74
|
+
vec4 color = uGradientColors[0];
|
|
75
|
+
for (int i = 1; i < 8; i++) {
|
|
76
|
+
if (i >= uGradientCount) break;
|
|
77
|
+
float prevStop = uGradientStops[i-1];
|
|
78
|
+
float currStop = uGradientStops[i];
|
|
36
79
|
|
|
37
|
-
|
|
38
|
-
|
|
80
|
+
float factor = clamp((t - prevStop) / (currStop - prevStop + 0.00001), 0.0, 1.0);
|
|
81
|
+
color = mix(color, uGradientColors[i], factor);
|
|
82
|
+
}
|
|
83
|
+
// return vec4(linearToSrgb(color.rgb), color.a);
|
|
84
|
+
return vec4(color);
|
|
85
|
+
}
|
|
39
86
|
|
|
40
|
-
|
|
87
|
+
void main() {
|
|
88
|
+
vec2 p = (vUv - 0.5) * uSize;
|
|
89
|
+
vec2 halfSize = uSize * 0.5;
|
|
41
90
|
|
|
42
|
-
|
|
43
|
-
vec2 xRadii = mix(uBorderRadius.xw, uBorderRadius.yz, step(0.0, p.x));
|
|
44
|
-
float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
|
|
45
|
-
float d = sdRoundedBox(p, halfSize, r);
|
|
91
|
+
#INJECT_UV_MODIFIER
|
|
46
92
|
|
|
47
|
-
|
|
48
|
-
|
|
93
|
+
// color decision pipeline
|
|
94
|
+
vec4 baseColor = vec4(uBgColor.rgb, uBgColor.a);
|
|
49
95
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
borderAlpha = 0.0;
|
|
55
|
-
}
|
|
96
|
+
if (uGradientCount > 0) {
|
|
97
|
+
vec4 gradColor = calculateGradientLayer(vUv);
|
|
98
|
+
baseColor = blendSrcOver(gradColor, baseColor);
|
|
99
|
+
}
|
|
56
100
|
|
|
57
|
-
|
|
58
|
-
float aFront = borderAlpha;
|
|
59
|
-
float aBack = baseColor.a;
|
|
60
|
-
float aOut = aFront + aBack * (1.0 - aFront);
|
|
101
|
+
#INJECT_BASE_COLOR
|
|
61
102
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
103
|
+
// Hybrid SDF
|
|
104
|
+
vec2 xRadii = mix(uBorderRadius.xw, uBorderRadius.yz, step(0.0, p.x));
|
|
105
|
+
float r = mix(xRadii.y, xRadii.x, step(0.0, p.y));
|
|
106
|
+
r = min(r, min(halfSize.x, halfSize.y));
|
|
65
107
|
|
|
66
|
-
|
|
67
|
-
#INJECT_COLOR_MODIFIER
|
|
108
|
+
float d = sdRoundedBox(p, halfSize, r);
|
|
68
109
|
|
|
69
|
-
|
|
70
|
-
|
|
110
|
+
float d_smooth = sdVisualBox(p, halfSize, r);
|
|
111
|
+
float d_visual = d_smooth / fwidth(d_smooth);
|
|
71
112
|
|
|
72
|
-
|
|
113
|
+
// rendering pipeline
|
|
114
|
+
float bgMask = 1.0 - smoothstep(-0.5, 0.5, d_visual);
|
|
73
115
|
|
|
74
|
-
|
|
116
|
+
float halfBorder = uBorderWidth * 0.5;
|
|
117
|
+
float borderD = abs(d + halfBorder) - halfBorder;
|
|
118
|
+
float borderAlpha = (1.0 - smoothstep(0.0, 1.0, borderD)) * uBorderColor.a;
|
|
119
|
+
if (uBorderWidth <= 0.01) {
|
|
120
|
+
borderAlpha = 0.0;
|
|
75
121
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
122
|
+
|
|
123
|
+
// final blending (border + background) using blendSrcOver
|
|
124
|
+
vec4 borderLayer = vec4(uBorderColor.rgb, borderAlpha);
|
|
125
|
+
vec4 finalColor = blendSrcOver(borderLayer, baseColor);
|
|
126
|
+
// final color control (Tint, Noise)
|
|
127
|
+
#INJECT_COLOR_MODIFIER
|
|
128
|
+
|
|
129
|
+
float finalOpacity = finalColor.a * bgMask * uOpacity;
|
|
130
|
+
if (finalOpacity < 0.001) discard;
|
|
131
|
+
|
|
132
|
+
gl_FragColor = vec4(finalColor.rgb, finalOpacity);
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
// #include <colorspace_fragment>
|
|
136
|
+
}
|
|
137
|
+
`,U=`uniform sampler2D uTexture;
|
|
138
|
+
varying vec4 vScreenPos;
|
|
139
|
+
uniform vec2 uTextureRepeat;
|
|
140
|
+
uniform vec2 uTextureOffset;`,V=`vec2 screenUv = (vScreenPos.xy / vScreenPos.w) * 0.5 + 0.5;
|
|
141
|
+
vec2 resultUv = screenUv;
|
|
142
|
+
|
|
143
|
+
`,z=`vec4 texColor = texture2D(uTexture, resultUv);
|
|
144
|
+
baseColor = blendSrcOver(baseColor, texColor);`,G={vertexShader:F,fragmentShader:W},A={declChunk:U,uvChunk:V,baseColorChunk:z};function E(r,o,t,i=null,e){const a=i!==null||!!r.imageSrc;let n="";const c={};if(e!=null&&e.uniforms)for(const[b,v]of Object.entries(e.uniforms))typeof v=="number"?(n+=`uniform float ${b};
|
|
145
|
+
`,c[b]={value:v}):Array.isArray(v)?v.length===2?(n+=`uniform vec2 ${b};
|
|
146
|
+
`,c[b]={value:new u.Vector2(...v)}):v.length===3?(n+=`uniform vec3 ${b};
|
|
147
|
+
`,c[b]={value:new u.Vector3(...v)}):v.length===4&&(n+=`uniform vec4 ${b};
|
|
148
|
+
`,c[b]={value:new u.Vector4(...v)}):(n+=`uniform float ${b};
|
|
149
|
+
`,c[b]={value:v});const s=(a?A.declChunk:"")+`
|
|
150
|
+
`+n,l=r.isTraveler?A.uvChunk:`vec2 resultUv = vUv * uTextureRepeat + uTextureOffset;
|
|
151
|
+
`,d=a?l+((e==null?void 0:e.uvModifier)||""):"",g=a?A.baseColorChunk:"",y=(e==null?void 0:e.colorModifier)||"",m=G.fragmentShader.replace("#INJECT_DECLARATIONS",s).replace("#INJECT_UV_MODIFIER",d).replace("#INJECT_BASE_COLOR",g).replace("#INJECT_COLOR_MODIFIER",y),p=S(r.backgroundColor),T=S(r.borderColor),B={uSize:{value:new u.Vector2(o,t)},uBgColor:{value:new u.Vector4(p.color.r,p.color.g,p.color.b,p.alpha)},uBorderColor:{value:new u.Vector4(T.color.r,T.color.g,T.color.b,T.alpha)},uBorderRadius:{value:new u.Vector4(0,0,0,0)},uBorderWidth:{value:x(r.borderWidth)},uOpacity:{value:r.opacity??1},uTexture:{value:null},uTextureRepeat:{value:new u.Vector2(1,1)},uTextureOffset:{value:new u.Vector2(0,0)},uGradientCount:{value:0},uGradientAngle:{value:0},uGradientColors:{value:Array.from({length:8},()=>new u.Vector4(0,0,0,0))},uGradientStops:{value:new Float32Array(8)}};_(B.uBorderRadius.value,r.borderRadius),a&&(B.uTexture.value=i);const w=new u.ShaderMaterial({uniforms:{...B,...c},vertexShader:G.vertexShader,fragmentShader:m,transparent:!0,side:u.FrontSide});return r.backgroundImage&&I(w,{backgroundImage:r.backgroundImage}),w}function L(r,o,t,i,e){const a=x(o.borderWidth);I(r,{width:t,height:i,borderRadius:o.borderRadius,borderWidth:a,backgroundColor:o.backgroundColor,borderColor:o.borderColor,opacity:o.opacity,texture:e,backgroundImage:o.backgroundImage})}function I(r,o){var i;if(o.width!==void 0&&o.height!==void 0&&r.uniforms.uSize.value.set(o.width,o.height),o.borderRadius!==void 0&&_(r.uniforms.uBorderRadius.value,o.borderRadius),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=S(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=S(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 t=o.texture!==void 0?o.texture:(i=r.uniforms.uTexture)==null?void 0:i.value;if(t&&(t.image instanceof ImageBitmap||t.image instanceof HTMLImageElement||t.image instanceof HTMLCanvasElement)){const e=t.image.width,a=t.image.height,n=o.width??r.uniforms.uSize.value.x,c=o.height??r.uniforms.uSize.value.y;if(e&&a&&n&&c){const s=e/a,l=n/c;if(s>l){const d=l/s;r.uniforms.uTextureRepeat.value.set(d,1),r.uniforms.uTextureOffset.value.set((1-d)/2,0)}else{const d=s/l;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=P(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 n=e.stops[a];r.uniforms.uGradientColors.value[a].set(n.color.r,n.color.g,n.color.b,n.alpha),r.uniforms.uGradientStops.value[a]=n.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"&&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 _(r,o){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+/),i=x(t[0]),e=x(t[1]??t[0]),a=x(t[2]??t[0]),n=x(t[3]??t[1]??t[0]);r.set(i,e,a,n)}const D={create(r,o,t,i,e,a=2,n=null,c){return r==="BOX"?E(o,i,e,n,c):r==="TEXT"?new R(t||"",o,i,e,a):new u.MeshBasicMaterial({visible:!1})},update(r,o,t,i,e,a,n=2,c){o==="BOX"?L(r,t,e,a,c):o==="TEXT"&&r.updateText(i||"",t,e,a,n)},forceUpdateUniforms(r,o){I(r,o)}};f.Painter=D,f.TextGenerator=R,f.createBoxMaterial=E,f.parseColor=S,f.parseLinearGradient=P,f.parsePixelValue=x,f.setBoxUniforms=I,f.splitByComma=k,f.updateBoxMaterial=L,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BoxStyles, ShaderHooks } from '../types';
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
export declare function createBoxMaterial(styles: BoxStyles, width: number, height: number, texture?: THREE.Texture | null, hooks?: ShaderHooks): THREE.ShaderMaterial;
|
|
4
|
+
export declare function updateBoxMaterial(material: THREE.ShaderMaterial, styles: BoxStyles, width: number, height: number, texture?: THREE.Texture | null): void;
|
|
5
|
+
export interface BoxUniformValues {
|
|
6
|
+
width?: number;
|
|
7
|
+
height?: number;
|
|
8
|
+
borderRadius?: string | number | [number, number, number, number];
|
|
9
|
+
borderWidth?: number;
|
|
10
|
+
backgroundColor?: THREE.Color | [number, number, number] | string;
|
|
11
|
+
borderColor?: THREE.Color | [number, number, number] | string;
|
|
12
|
+
opacity?: number;
|
|
13
|
+
bgOpacity?: number;
|
|
14
|
+
borderOpacity?: number;
|
|
15
|
+
texture?: THREE.Texture | null;
|
|
16
|
+
backgroundImage?: string;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
export declare function setBoxUniforms(material: THREE.ShaderMaterial, values: BoxUniformValues): void;
|
package/dist/src/Painter.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { ShaderHooks } from './types';
|
|
1
|
+
import { BoxStyles, TextStyles, ShaderHooks } from './types';
|
|
2
|
+
import { BoxUniformValues } from './Box/BoxGenerator';
|
|
2
3
|
import * as THREE from "three";
|
|
3
4
|
export declare const Painter: {
|
|
4
|
-
create(type: "BOX" | "TEXT", styles:
|
|
5
|
-
update(material: THREE.Material, type: "BOX" | "TEXT", styles:
|
|
5
|
+
create(type: "BOX" | "TEXT", styles: BoxStyles | TextStyles, content: string, width: number, height: number, quality?: number, texture?: THREE.Texture | null, shaderHooks?: ShaderHooks): THREE.Material;
|
|
6
|
+
update(material: THREE.Material, type: "BOX" | "TEXT", styles: BoxStyles | TextStyles, content: string, width: number, height: number, quality?: number, texture?: THREE.Texture | null): void;
|
|
7
|
+
forceUpdateUniforms(material: THREE.ShaderMaterial, values: BoxUniformValues): void;
|
|
6
8
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class FontMetricsManager {
|
|
2
|
+
private static cache;
|
|
3
|
+
/**
|
|
4
|
+
* Calculates or retrieves the exact alphabetic baseline (in pixels) for the given font.
|
|
5
|
+
* @param font CSS font shorthand string (e.g., "400 16px Inter")
|
|
6
|
+
* @returns Baseline Y offset in pixels
|
|
7
|
+
*/
|
|
8
|
+
static getBaseline(font: string): number;
|
|
9
|
+
private static calculateBaselineFromDOM;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TextStyles } from '../types';
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
export declare class TextGenerator extends THREE.MeshBasicMaterial {
|
|
4
|
+
private canvas;
|
|
5
|
+
private ctx;
|
|
6
|
+
private qualityFactor;
|
|
7
|
+
constructor(text: string, styles: TextStyles, rectWidth: number, rectHeight: number, qualityFactor?: number);
|
|
8
|
+
private wrapText;
|
|
9
|
+
updateText(text: string, styles: TextStyles, rectWidth: number, rectHeight: number, qualityFactor?: number): void;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export declare function parsePixelValue(value: string | number): number;
|
|
3
|
+
export declare function parseColor(colorStr: string): {
|
|
4
|
+
color: THREE.Color;
|
|
5
|
+
alpha: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function splitByComma(str: string): string[];
|
|
8
|
+
export declare function parseLinearGradient(value: string | null | undefined): {
|
|
9
|
+
angle: number;
|
|
10
|
+
stops: {
|
|
11
|
+
color: THREE.Color;
|
|
12
|
+
alpha: number;
|
|
13
|
+
rawStop: string | null;
|
|
14
|
+
stop: number;
|
|
15
|
+
}[];
|
|
16
|
+
} | null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface TextStyles {
|
|
2
2
|
font: string;
|
|
3
|
+
fontSize: string;
|
|
3
4
|
color: string;
|
|
4
5
|
textAlign: CanvasTextAlign;
|
|
5
6
|
textBaseline: CanvasTextBaseline;
|
|
@@ -9,6 +10,9 @@ export interface TextStyles {
|
|
|
9
10
|
}
|
|
10
11
|
export interface BoxStyles {
|
|
11
12
|
backgroundColor: string;
|
|
13
|
+
backgroundImage: string;
|
|
14
|
+
imageSrc?: string;
|
|
15
|
+
isTraveler?: boolean;
|
|
12
16
|
opacity: number;
|
|
13
17
|
zIndex: number;
|
|
14
18
|
borderRadius: string;
|
|
@@ -18,4 +22,5 @@ export interface BoxStyles {
|
|
|
18
22
|
export interface ShaderHooks {
|
|
19
23
|
uvModifier?: string;
|
|
20
24
|
colorModifier?: string;
|
|
25
|
+
uniforms?: Record<string, any>;
|
|
21
26
|
}
|