@oh-just-another/renderer-canvas 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +36 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/canvas-target.d.ts +83 -0
  6. package/dist/canvas-target.d.ts.map +1 -0
  7. package/dist/canvas-target.js +208 -0
  8. package/dist/canvas-target.js.map +1 -0
  9. package/dist/canvas-text-shaper.d.ts +11 -0
  10. package/dist/canvas-text-shaper.d.ts.map +1 -0
  11. package/dist/canvas-text-shaper.js +56 -0
  12. package/dist/canvas-text-shaper.js.map +1 -0
  13. package/dist/constants.d.ts +52 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +52 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/hi-dpi.d.ts +26 -0
  18. package/dist/hi-dpi.d.ts.map +1 -0
  19. package/dist/hi-dpi.js +62 -0
  20. package/dist/hi-dpi.js.map +1 -0
  21. package/dist/image-source.d.ts +3 -0
  22. package/dist/image-source.d.ts.map +1 -0
  23. package/dist/image-source.js +65 -0
  24. package/dist/image-source.js.map +1 -0
  25. package/dist/index.d.ts +15 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +24 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/layered-canvas.d.ts +46 -0
  30. package/dist/layered-canvas.d.ts.map +1 -0
  31. package/dist/layered-canvas.js +95 -0
  32. package/dist/layered-canvas.js.map +1 -0
  33. package/dist/layered-surface.d.ts +75 -0
  34. package/dist/layered-surface.d.ts.map +1 -0
  35. package/dist/layered-surface.js +262 -0
  36. package/dist/layered-surface.js.map +1 -0
  37. package/dist/offscreen.d.ts +30 -0
  38. package/dist/offscreen.d.ts.map +1 -0
  39. package/dist/offscreen.js +50 -0
  40. package/dist/offscreen.js.map +1 -0
  41. package/dist/recording-target.d.ts +203 -0
  42. package/dist/recording-target.d.ts.map +1 -0
  43. package/dist/recording-target.js +260 -0
  44. package/dist/recording-target.js.map +1 -0
  45. package/dist/render-worker.d.ts +2 -0
  46. package/dist/render-worker.d.ts.map +1 -0
  47. package/dist/render-worker.js +112 -0
  48. package/dist/render-worker.js.map +1 -0
  49. package/dist/tile-compositor.d.ts +44 -0
  50. package/dist/tile-compositor.d.ts.map +1 -0
  51. package/dist/tile-compositor.js +110 -0
  52. package/dist/tile-compositor.js.map +1 -0
  53. package/dist/webgl2-color.d.ts +13 -0
  54. package/dist/webgl2-color.d.ts.map +1 -0
  55. package/dist/webgl2-color.js +26 -0
  56. package/dist/webgl2-color.js.map +1 -0
  57. package/dist/webgl2-curve.d.ts +46 -0
  58. package/dist/webgl2-curve.d.ts.map +1 -0
  59. package/dist/webgl2-curve.js +162 -0
  60. package/dist/webgl2-curve.js.map +1 -0
  61. package/dist/webgl2-ellipse.d.ts +52 -0
  62. package/dist/webgl2-ellipse.d.ts.map +1 -0
  63. package/dist/webgl2-ellipse.js +171 -0
  64. package/dist/webgl2-ellipse.js.map +1 -0
  65. package/dist/webgl2-msdf-text.d.ts +84 -0
  66. package/dist/webgl2-msdf-text.d.ts.map +1 -0
  67. package/dist/webgl2-msdf-text.js +306 -0
  68. package/dist/webgl2-msdf-text.js.map +1 -0
  69. package/dist/webgl2-stroke.d.ts +52 -0
  70. package/dist/webgl2-stroke.d.ts.map +1 -0
  71. package/dist/webgl2-stroke.js +318 -0
  72. package/dist/webgl2-stroke.js.map +1 -0
  73. package/dist/webgl2-target.d.ts +311 -0
  74. package/dist/webgl2-target.d.ts.map +1 -0
  75. package/dist/webgl2-target.js +1368 -0
  76. package/dist/webgl2-target.js.map +1 -0
  77. package/dist/webgpu-detect.d.ts +30 -0
  78. package/dist/webgpu-detect.d.ts.map +1 -0
  79. package/dist/webgpu-detect.js +74 -0
  80. package/dist/webgpu-detect.js.map +1 -0
  81. package/package.json +67 -0
@@ -0,0 +1,306 @@
1
+ export class MsdfTextPipeline {
2
+ gl;
3
+ program;
4
+ vbo;
5
+ uTransform;
6
+ uColor;
7
+ uOpacity;
8
+ uAtlasSize;
9
+ uPxRange;
10
+ uAtlas;
11
+ aPos;
12
+ aUV;
13
+ constructor(gl) {
14
+ this.gl = gl;
15
+ const vert = compile(gl, gl.VERTEX_SHADER, VERTEX_SRC);
16
+ const frag = compile(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC);
17
+ this.program = link(gl, vert, frag);
18
+ this.vbo = glReq(gl.createBuffer());
19
+ this.aPos = gl.getAttribLocation(this.program, "aPos");
20
+ this.aUV = gl.getAttribLocation(this.program, "aUV");
21
+ this.uTransform = glReq(gl.getUniformLocation(this.program, "uTransform"));
22
+ this.uColor = glReq(gl.getUniformLocation(this.program, "uColor"));
23
+ this.uOpacity = glReq(gl.getUniformLocation(this.program, "uOpacity"));
24
+ this.uAtlasSize = glReq(gl.getUniformLocation(this.program, "uAtlasSize"));
25
+ this.uPxRange = glReq(gl.getUniformLocation(this.program, "uPxRange"));
26
+ this.uAtlas = glReq(gl.getUniformLocation(this.program, "uAtlas"));
27
+ }
28
+ /**
29
+ * Build per-glyph quads for `text` starting at the cursor position
30
+ * `(x, y)` in world coordinates (top-left baseline convention —
31
+ * caller adjusts for textAlign / textBaseline upstream).
32
+ *
33
+ * Returns the screen-width of the rendered string in world units so
34
+ * callers can chain text or compute hit-test boxes. Returns 0 if the
35
+ * atlas couldn't bake one of the glyphs (atlas full) — the partial
36
+ * draw still lands.
37
+ */
38
+ drawText(text, x, y, fontSize, atlas, style, surfaceSize,
39
+ /**
40
+ * Horizontal alignment factor: 0 = left (cursor at `x`), 0.5 =
41
+ * centre, 1 = right. Applied as a single world-space x shift after
42
+ * measuring the run, so there's no separate width-measuring walk
43
+ * over the atlas.
44
+ */
45
+ alignFactor = 0,
46
+ /** Embedded font id (0=sans, 1=serif, 2=mono); selects atlas glyphs. */
47
+ fontId = 0) {
48
+ if (text.length === 0)
49
+ return 0;
50
+ // Walk glyphs, pack interleaved position+uv into one batch. Each
51
+ // glyph = 6 vertices (two triangles), 4 floats per vertex
52
+ // (x, y, u, v) = 24 floats.
53
+ const verticesPerGlyph = 6;
54
+ const floatsPerVertex = 4;
55
+ const needed = text.length * verticesPerGlyph * floatsPerVertex;
56
+ // Reuse the module-level scratch buffer — grow on demand.
57
+ ensureGlyphBufCapacity(needed);
58
+ const buf = scratchGlyphBuf;
59
+ let writeOffset = 0;
60
+ let cursor = x;
61
+ for (const ch of text) {
62
+ const cp = ch.codePointAt(0);
63
+ if (cp === undefined)
64
+ continue;
65
+ const glyph = atlas.getOrRasterize(cp, fontId);
66
+ if (!glyph)
67
+ break; // atlas full or shaper unavailable
68
+ const advancePx = (glyph.advance * fontSize) / glyph.unitsPerEm;
69
+ if (glyph.empty) {
70
+ cursor += advancePx;
71
+ continue;
72
+ }
73
+ writeGlyphQuad(buf, writeOffset, glyph, cursor, y, fontSize, atlas);
74
+ writeOffset += verticesPerGlyph * floatsPerVertex;
75
+ cursor += advancePx;
76
+ }
77
+ if (writeOffset === 0)
78
+ return cursor - x; // every glyph empty / unavailable
79
+ const tex = atlas.uploadTo(this.gl);
80
+ const gl = this.gl;
81
+ gl.useProgram(this.program);
82
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
83
+ gl.bufferData(gl.ARRAY_BUFFER, buf.subarray(0, writeOffset), gl.DYNAMIC_DRAW);
84
+ gl.enableVertexAttribArray(this.aPos);
85
+ gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 16, 0);
86
+ gl.enableVertexAttribArray(this.aUV);
87
+ gl.vertexAttribPointer(this.aUV, 2, gl.FLOAT, false, 16, 8);
88
+ // Alignment: shift the whole run left by `width × alignFactor` in
89
+ // world space, folded into the transform's translation (screen
90
+ // shift = column-0 × worldDx). One walk total — no separate width
91
+ // measurement pass.
92
+ const t = style.transform;
93
+ let mat = t;
94
+ if (alignFactor !== 0) {
95
+ const dx = -(cursor - x) * alignFactor;
96
+ mat = { ...t, e: t.e + t.a * dx, f: t.f + t.b * dx };
97
+ }
98
+ writeAffineToClipMat3(scratchMat3, mat, surfaceSize.width, surfaceSize.height);
99
+ gl.uniformMatrix3fv(this.uTransform, false, scratchMat3);
100
+ gl.uniform3f(this.uColor, style.color[0], style.color[1], style.color[2]);
101
+ gl.uniform1f(this.uOpacity, style.opacity);
102
+ gl.uniform1f(this.uAtlasSize, atlas.atlasSize);
103
+ // `pxRange` is the SDF range converted into screen pixels at the
104
+ // current font size: the shader needs it to keep the AA band the
105
+ // right thickness independent of zoom.
106
+ const tileGlyphPx = atlas.tileSize - 2 * atlas.range;
107
+ const pxRange = (atlas.range * fontSize) / Math.max(1, tileGlyphPx);
108
+ gl.uniform1f(this.uPxRange, pxRange);
109
+ gl.activeTexture(gl.TEXTURE0);
110
+ gl.bindTexture(gl.TEXTURE_2D, tex);
111
+ gl.uniform1i(this.uAtlas, 0);
112
+ gl.drawArrays(gl.TRIANGLES, 0, writeOffset / floatsPerVertex);
113
+ return cursor - x;
114
+ }
115
+ dispose() {
116
+ this.gl.deleteBuffer(this.vbo);
117
+ this.gl.deleteProgram(this.program);
118
+ }
119
+ }
120
+ /**
121
+ * Pure-math helper: compute the screen-space rect + atlas UV rect for
122
+ * one glyph. Exported so tests can verify the geometry without booting
123
+ * a real WebGL2 context.
124
+ *
125
+ * Returns `{ left, top, right, bottom, u0, v0, u1, v1 }` in screen
126
+ * pixels / normalised UVs. Caller packs the six vertices into a vertex
127
+ * buffer.
128
+ */
129
+ export const glyphQuadGeometry = (g, cursorX, cursorY, fontSize, atlas) => {
130
+ const unitToPx = fontSize / g.unitsPerEm;
131
+ // The MSDF tile is `tileSize × tileSize` but the glyph itself only
132
+ // occupies a `scaledW + 2*range` × `scaledH + 2*range` rectangle
133
+ // inside it — the rest of the tile is empty ("fully outside" SDF).
134
+ // The rasteriser scales by max(bboxW, bboxH) so the bigger axis fills
135
+ // `tileSize - 2*range` and the smaller axis is proportional. UVs must
136
+ // cover only that used rect, otherwise narrow letters ('i', 'l', 'I')
137
+ // get the empty atlas margin stretched into them and read as
138
+ // wide/skewed/distorted.
139
+ const tileGlyphAtlasPx = Math.max(1, atlas.tileSize - 2 * atlas.range);
140
+ const fontUnitsPerAtlasPx = Math.max(g.bboxW, g.bboxH) / tileGlyphAtlasPx;
141
+ // Atlas pixels occupied by the glyph + its SDF margin.
142
+ const usedW_atlas = g.bboxW / fontUnitsPerAtlasPx + 2 * atlas.range;
143
+ const usedH_atlas = g.bboxH / fontUnitsPerAtlasPx + 2 * atlas.range;
144
+ // Screen-pixel margin = the same `range` atlas pixels mapped through
145
+ // `fontUnitsPerAtlasPx × unitToPx`.
146
+ const marginPx = atlas.range * fontUnitsPerAtlasPx * unitToPx;
147
+ const w = g.bboxW * unitToPx + 2 * marginPx;
148
+ const h = g.bboxH * unitToPx + 2 * marginPx;
149
+ // Glyph quad position in screen coords (y-down). `cursorY` is the
150
+ // text baseline; the font bbox lives from baseline upward, so the
151
+ // glyph top sits at `cursor - bboxYMax * unitToPx`.
152
+ const left = cursorX + g.bboxXMin * unitToPx - marginPx;
153
+ const top = cursorY + (-g.bboxYMin - g.bboxH) * unitToPx - marginPx;
154
+ const right = left + w;
155
+ const bottom = top + h;
156
+ // Atlas UVs — cover the used rect, inset by half a texel on every
157
+ // side so the LINEAR filter never pulls in pixels from the adjacent
158
+ // tile. Without this inset the LINEAR sampler at a tile boundary
159
+ // averages the current glyph's edge with the neighbouring tile, which
160
+ // shows up as faint vertical / horizontal stripes between adjacent
161
+ // letters at certain zooms.
162
+ //
163
+ // The rasteriser writes the glyph right-side-up (y-flip applied in
164
+ // the Rust transform), so UV v=0 maps to the top of the glyph.
165
+ const inset = 0.5;
166
+ const u0 = (g.atlasX + inset) / atlas.atlasSize;
167
+ const v0 = (g.atlasY + inset) / atlas.atlasSize;
168
+ const u1 = (g.atlasX + usedW_atlas - inset) / atlas.atlasSize;
169
+ const v1 = (g.atlasY + usedH_atlas - inset) / atlas.atlasSize;
170
+ return { left, top, right, bottom, u0, v0, u1, v1 };
171
+ };
172
+ const writeGlyphQuad = (buf, offset, g, cursorX, cursorY, fontSize, atlas) => {
173
+ const { left, top, right, bottom, u0, v0, u1, v1 } = glyphQuadGeometry(g, cursorX, cursorY, fontSize, atlas);
174
+ // Two triangles, six vertices, (x, y, u, v) each.
175
+ buf.set([
176
+ left, top, u0, v0,
177
+ right, top, u1, v0,
178
+ left, bottom, u0, v1,
179
+ right, top, u1, v0,
180
+ right, bottom, u1, v1,
181
+ left, bottom, u0, v1,
182
+ ], offset);
183
+ };
184
+ /**
185
+ * Module-level scratch buffers — reused across every `drawText`
186
+ * invocation so the text hot path allocates zero `Float32Array`s after
187
+ * warmup.
188
+ *
189
+ * `scratchGlyphBuf` starts at 512 floats (21 chars worth of glyph
190
+ * quads); longer strings grow to the next power of 2. `scratchMat3` is
191
+ * a fixed mat3 (column-major), no grow needed.
192
+ *
193
+ * Safe for single-threaded WebGL — `drawText` is not reentrant, calls
194
+ * are serialised through the editor render loop. Multiple WebGL2Target
195
+ * instances share the buffer, which is fine.
196
+ */
197
+ let scratchGlyphBuf = new Float32Array(512);
198
+ const scratchMat3 = new Float32Array(9);
199
+ const ensureGlyphBufCapacity = (n) => {
200
+ if (scratchGlyphBuf.length >= n)
201
+ return;
202
+ let cap = scratchGlyphBuf.length;
203
+ while (cap < n)
204
+ cap *= 2;
205
+ scratchGlyphBuf = new Float32Array(cap);
206
+ };
207
+ /**
208
+ * Write the column-major mat3 the shader expects into a caller-owned
209
+ * scratch buffer. The editor affine maps (worldX, worldY) → screen
210
+ * pixels, then we scale pixels into clip space (-1..1) with a y flip so
211
+ * positive y goes down on the screen.
212
+ */
213
+ const writeAffineToClipMat3 = (out, t, w, h) => {
214
+ const sx = 2 / w;
215
+ const sy = -2 / h;
216
+ out[0] = t.a * sx;
217
+ out[1] = t.b * sy;
218
+ out[2] = 0;
219
+ out[3] = t.c * sx;
220
+ out[4] = t.d * sy;
221
+ out[5] = 0;
222
+ out[6] = t.e * sx - 1;
223
+ out[7] = t.f * sy + 1;
224
+ out[8] = 1;
225
+ };
226
+ const VERTEX_SRC = `#version 300 es
227
+ in vec2 aPos;
228
+ in vec2 aUV;
229
+ uniform mat3 uTransform;
230
+ out vec2 vUV;
231
+ void main() {
232
+ vec3 p = uTransform * vec3(aPos, 1.0);
233
+ gl_Position = vec4(p.xy, 0.0, 1.0);
234
+ vUV = aUV;
235
+ }`;
236
+ /**
237
+ * Standard MSDF fragment shader: sample the 3-channel SDF, take the
238
+ * median of (r, g, b) to recover a single signed distance, and use
239
+ * `smoothstep` to antialias the 0.5 isoline. `pxRange` controls how
240
+ * wide the AA band is in screen pixels — without it the smoothstep
241
+ * collapses to a hard edge at high zoom and over-blurs at low zoom.
242
+ *
243
+ * The 0.5 isoline is the canonical inside/outside boundary for MSDF
244
+ * (the generator centres the distance field on 0.5 in u8 encoding:
245
+ * 0 = deep outside, 128 = on the edge, 255 = deep inside).
246
+ */
247
+ const FRAGMENT_SRC = `#version 300 es
248
+ precision mediump float;
249
+ uniform vec3 uColor;
250
+ uniform float uOpacity;
251
+ uniform float uPxRange;
252
+ uniform sampler2D uAtlas;
253
+ in vec2 vUV;
254
+ out vec4 fragColor;
255
+
256
+ float median(float r, float g, float b) {
257
+ return max(min(r, g), min(max(r, g), b));
258
+ }
259
+
260
+ void main() {
261
+ vec3 msd = texture(uAtlas, vUV).rgb;
262
+ float sd = median(msd.r, msd.g, msd.b);
263
+ // Convert signed distance to screen-space AA: fwidth(vUV) tracks how
264
+ // much UV changes per screen pixel, multiplied by pxRange gives the
265
+ // screen-pixel cover of one SDF step.
266
+ float dx = fwidth(sd) * 0.5;
267
+ float alpha = smoothstep(0.5 - dx, 0.5 + dx, sd);
268
+ if (alpha < 0.001) discard;
269
+ // Premultiplied output to match the context's premultipliedAlpha
270
+ // contract + blendFunc(ONE, 1-SRC_ALPHA).
271
+ float a = alpha * uOpacity;
272
+ fragColor = vec4(uColor * a, a);
273
+ }`;
274
+ /**
275
+ * Asserts a WebGL resource handle is non-null. Creation APIs are typed
276
+ * non-null but return `null` on context loss; surface that as a throw.
277
+ */
278
+ const glReq = (v) => {
279
+ if (v === null)
280
+ throw new Error("packages/renderer-canvas: WebGL resource creation failed");
281
+ return v;
282
+ };
283
+ const compile = (gl, type, src) => {
284
+ const sh = glReq(gl.createShader(type));
285
+ gl.shaderSource(sh, src);
286
+ gl.compileShader(sh);
287
+ if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
288
+ const log = gl.getShaderInfoLog(sh);
289
+ gl.deleteShader(sh);
290
+ throw new Error(`MSDF shader compile failed: ${log}`);
291
+ }
292
+ return sh;
293
+ };
294
+ const link = (gl, vert, frag) => {
295
+ const program = gl.createProgram();
296
+ gl.attachShader(program, vert);
297
+ gl.attachShader(program, frag);
298
+ gl.linkProgram(program);
299
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
300
+ const log = gl.getProgramInfoLog(program);
301
+ gl.deleteProgram(program);
302
+ throw new Error(`MSDF program link failed: ${log}`);
303
+ }
304
+ return program;
305
+ };
306
+ //# sourceMappingURL=webgl2-msdf-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl2-msdf-text.js","sourceRoot":"","sources":["../src/webgl2-msdf-text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { LineCap, LineJoin } from "@oh-just-another/renderer-core";
2
+ import type { Transform, Vec2 } from "@oh-just-another/types";
3
+ /**
4
+ * GPU-side stroke pipeline for the WebGL2 backend. Builds a single
5
+ * triangle list per call (joins + caps included), uploads once, and
6
+ * draws via the host's solid-color program. Independent of the
7
+ * fill / text / image pipelines — they each manage their own VBO.
8
+ *
9
+ * Supports the full Canvas2D / SVG join + cap matrix:
10
+ * joins: "miter" (default), "bevel", "round"
11
+ * caps: "butt" (default), "square", "round"
12
+ *
13
+ * One TRIANGLES list rather than a strip + extra primitives: round
14
+ * joins / caps need fan triangles glued on top of the strip, and a
15
+ * single TRIANGLES list avoids re-binding the buffer per join while
16
+ * keeping heterogeneous join geometry easy to author.
17
+ */
18
+ /** Two-vertex pair per polyline vertex (left + right side of the band). */
19
+ interface SideOffset {
20
+ ox: number;
21
+ oy: number;
22
+ }
23
+ export interface StrokeStyle {
24
+ readonly width: number;
25
+ readonly color: readonly [number, number, number];
26
+ readonly opacity: number;
27
+ readonly join: LineJoin;
28
+ readonly cap: LineCap;
29
+ }
30
+ /**
31
+ * Compute one miter offset at the hinge between two unit normals.
32
+ * Returns `{ ox, oy }` along the bisector, clamped to MITER_LIMIT.
33
+ * Exported so `webgl2-target.ts` can reuse it for closed-polyline seam
34
+ * vertices.
35
+ */
36
+ export declare const miterOffset: (n1x: number, n1y: number, n2x: number, n2y: number, half: number) => SideOffset;
37
+ /**
38
+ * Build the stroke geometry for a polyline + style, upload to the
39
+ * caller's dynamic VBO, and draw. Identity uTransform — vertices are
40
+ * pre-projected into clip space here.
41
+ *
42
+ * The caller passes its solid program + cached `aPos` attribute
43
+ * location + its dynamic VBO. This function binds & sets up the
44
+ * attribute itself so it's self-contained — no implicit dependency on
45
+ * the previous draw's GL state.
46
+ */
47
+ export declare const drawPolylineStroke: (gl: WebGL2RenderingContext, polyline: readonly Vec2[], style: StrokeStyle, transform: Transform, size: {
48
+ width: number;
49
+ height: number;
50
+ }, program: WebGLProgram, uTransformLoc: WebGLUniformLocation, uColorLoc: WebGLUniformLocation, uOpacityLoc: WebGLUniformLocation, dynamicVbo: WebGLBuffer, aPosLoc: number, identityMat3: Float32Array) => void;
51
+ export {};
52
+ //# sourceMappingURL=webgl2-stroke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl2-stroke.d.ts","sourceRoot":"","sources":["../src/webgl2-stroke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AAEH,2EAA2E;AAC3E,UAAU,UAAU;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AA+D/C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;CACvB;AAED;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GACtB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,MAAM,EACX,MAAM,MAAM,KACX,UAaF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,sBAAsB,EAC1B,UAAU,SAAS,IAAI,EAAE,EACzB,OAAO,WAAW,EAClB,WAAW,SAAS,EACpB,MAAM;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACvC,SAAS,YAAY,EACrB,eAAe,oBAAoB,EACnC,WAAW,oBAAoB,EAC/B,aAAa,oBAAoB,EACjC,YAAY,WAAW,EACvB,SAAS,MAAM,EACf,cAAc,YAAY,KACzB,IA4KF,CAAC"}