@weasel-js/renderer 1.9.4 → 1.10.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.
@@ -1,19 +1,13 @@
1
- import { TextureHandle, TilePatternSpec, PosedFill, CommandFill, FillStyle } from '@weasel-js/paint';
1
+ import { TextureHandle, PosedPaint, CommandPaint, Paint, TilePatternSpec } from '@weasel-js/paint';
2
2
  import { Reflection } from '@weasel-js/registry';
3
3
  import { Mesh } from '@weasel-js/geom/tessellate';
4
4
  import { GlMat3 } from '@weasel-js/geom';
5
- import { b as ShaderProgram } from './paintKinds-B2vEy9A4.js';
5
+ import { b as ShaderProgram } from './paintKinds-BmPAT51k.js';
6
6
 
7
7
  /**
8
- * registerTexture — accepts an image source, assigns an opaque id, stores in
9
- * a module-level registry. Actual GL upload happens lazily at draw time in
10
- * drawShader() via GLTextureCache.upload (which is idempotent).
11
- *
12
- * Lifecycle: a texture lives until `unregisterTexture`. Each renderer frees
13
- * its own GL copy at the top of its next frame.
14
- *
15
- * Convention §9: this registry stores image data only — no per-renderer state.
16
- * Each WeaselRenderer's GLTextureCache does its own dedup by id and source.
8
+ * A module-level registry of image sources by opaque id. It stores image data
9
+ * only — no per-renderer state; each renderer uploads to GL lazily at draw
10
+ * time. A texture lives until `unregisterTexture`.
17
11
  */
18
12
 
19
13
  /** A registered texture's image source, uploaded to GL lazily at first draw. */
@@ -25,13 +19,14 @@ declare const textureRegistry: Reflection<TextureEntry>;
25
19
  /** @internal Test helper — do not call from product code. */
26
20
  declare function _resetTextureRegistryForTests(): void;
27
21
  /**
28
- * Register an image for use as a shader texture uniform.
22
+ * Register an image for use as a shader texture uniform. Returns a
23
+ * TextureHandle whose `id` can be passed as a ShaderUniform value.
29
24
  *
30
- * Returns a TextureHandle whose `id` can be passed as a ShaderUniform value.
31
- * The handle is valid for the lifetime of the renderer it will be used with.
25
+ * The texture holds premultiplied texels whichever source it came from, so a
26
+ * shader sampling one reads `vec4(rgb * a, a)`, the form its own output takes.
32
27
  *
33
- * @param image The image to register. HTMLImageElement must be fully loaded.
34
- * @returns Opaque TextureHandle.
28
+ * @param image HTMLImageElement must be fully loaded. An ImageBitmap must
29
+ * hold premultiplied pixels, the `createImageBitmap` default.
35
30
  */
36
31
  declare function registerTexture(image: HTMLImageElement | ImageBitmap): TextureHandle;
37
32
  /**
@@ -48,8 +43,7 @@ declare function unregisterTexture(handle: TextureHandle): boolean;
48
43
  * needs no stencil and does not break the run.
49
44
  *
50
45
  * A stencil clip is GL state, so content inside one cannot share a draw with
51
- * content outside it, and every clipped group paid a flush on the way in and
52
- * another on the way out. A rect under a transform that keeps it axis-aligned
46
+ * content outside it. A rect under a transform that keeps it axis-aligned
53
47
  * is the common clip, and for that one the clip can ride the geometry instead:
54
48
  * cut each staged polygon to the rect before it joins the run.
55
49
  *
@@ -70,47 +64,32 @@ interface ClipRect {
70
64
 
71
65
  /**
72
66
  * Growable vertex staging for a run of solid-fill geometry, image quads and
73
- * glyphs.
74
- *
75
- * Geometry only: `draw.ts` owns when a run starts, what breaks it, and the
76
- * uniforms the flush draws under.
67
+ * glyphs. Geometry only: the caller owns when a run starts, what breaks it, and
68
+ * the uniforms the flush draws under.
77
69
  *
78
- * **One batch for all three, because a page interleaves them.** A grid of
79
- * thumbnails is a ground rect under an atlas quad under a caption, per cell,
80
- * and while each kind staged separately every one had to drain the others
81
- * before it could stage — so a shape that batches perfectly in any one half
82
- * alone paid a flush per command. Everything a vertex needs to say which it is
83
- * fits in the same vertex: solids carry the UV of a 1x1 white texel and are
84
- * their own color, quads carry their atlas UV and a white color, glyphs carry
85
- * a font atlas UV, their text color, and a paint mode saying the texel is a
86
- * distance field rather than a color. Gradients join as a fourth off the ramp
87
- * atlas — a linear one without a mode of its own, since (ramp position, row) is
88
- * what the plain mode already samples, and a radial or conic one with a mode
89
- * that says its UV is a gradient-space coordinate to take a `length` or an
90
- * `atan` of. See `shaders/batchFill.ts`.
70
+ * One batch for all of them, because a page interleaves them. Everything a
71
+ * vertex needs to say which it is fits in the same vertex: solids carry the UV
72
+ * of a 1x1 white texel and are their own color, quads carry their atlas UV and
73
+ * a white color, glyphs carry a font atlas UV, their text color, and a paint
74
+ * mode saying the texel is a distance field rather than a color. Gradients
75
+ * sample the ramp atlas. See `shaders/batchFill.ts`.
91
76
  *
92
- * Colors ride the vertices because shapes in a run differ in color and a merged
93
- * draw has one set of uniforms — and so does the model transform, applied here
94
- * rather than uploaded, so shapes under different transforms still share a
95
- * draw. The texture rides them too, as a slot index into the units the flush
96
- * binds: slot 0 is the white texel every solid samples, and `draw.ts` hands out
97
- * the rest per bitmap. A run holds as many bitmaps as there are slots, so an
98
- * atlas is what makes a wall of one sheet coalesce and a handful of loose
99
- * bitmaps no longer breaks a run per command.
77
+ * The model transform is applied here rather than uploaded, so shapes under
78
+ * different transforms still share a draw. The texture rides the vertices as a
79
+ * slot index into the units the flush binds: slot 0 is the white texel every
80
+ * solid samples.
100
81
  */
101
82
 
102
83
  /** vec2 a_position + vec4 a_vertexColor + vec2 a_uv + float a_post + float
103
- * a_texSlot. Exported so the buffer-replay tests read fields by name rather
104
- * than by a stride they repeat — a hard-coded one silently reads a different
105
- * field when the vertex grows, instead of failing. */
84
+ * a_texSlot. */
106
85
  declare const FLOATS_PER_VERTEX = 10;
107
86
  /**
108
87
  * A gradient vertex's `a_uv`, each channel affine in the coordinates the
109
88
  * geometry arrives in: `u = ux*x + uy*y + u0`, and the same for `v`.
110
89
  *
111
- * One shape for all three gradients. A linear one's `v` row is the constant
112
- * atlas row and its `u` row is the ramp position; a radial or conic one's two
113
- * rows are the gradient-space coordinate, and the row rides `a_post` instead.
90
+ * A linear gradient's `v` row is the constant atlas row and its `u` row is the
91
+ * ramp position; a radial or conic one's two rows are the gradient-space
92
+ * coordinate, and the atlas row rides `a_post` instead.
114
93
  */
115
94
  interface GradientUV {
116
95
  ux: number;
@@ -141,8 +120,7 @@ declare class DrawBatch {
141
120
  /** Whether the staged run is quads alone, so its indices are the canonical
142
121
  * pattern and a slot already holding that pattern needs no upload. */
143
122
  private pureRects;
144
- /** The rect every push is cut to, or `null`. `draw.ts` sets it as rect
145
- * clips enter and leave — see `batchClip.ts`. A push returns `false`, having
123
+ /** The rect every push is cut to, or `null`. A push returns `false`, having
146
124
  * staged nothing, for geometry it cannot cut exactly; see `clipQuad`. */
147
125
  clip: ClipRect | null;
148
126
  /** Polygon scratch for `clip`: a quad cut by four edges has at most eight
@@ -156,72 +134,54 @@ declare class DrawBatch {
156
134
  wouldOverflow(vertices: number): boolean;
157
135
  /**
158
136
  * Append one rect's four corners through `m`, all carrying `rgba` (straight
159
- * alpha). An affine maps a rect to a parallelogram, so two triangles still
160
- * cover it and the batch draws at `u_model` identity.
137
+ * alpha) and `P` in `a_texSlot`: the white texel, and the run's matrix.
161
138
  */
162
- pushRect(x: number, y: number, w: number, h: number, m: GlMat3, r: number, g: number, b: number, a: number): boolean;
139
+ pushRect(x: number, y: number, w: number, h: number, m: GlMat3, r: number, g: number, b: number, a: number, P: number): boolean;
163
140
  /**
164
141
  * Append one image quad: the destination rect `(x, y, w, h)` mapped through
165
142
  * `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `post` as the
166
- * after-the-color-matrix alpha factor.
143
+ * after-the-color-matrix alpha factor and `rgb` as the scale on its texel.
144
+ * `slot` is the texture unit the corners sample, and may carry the index of
145
+ * the run's matrix they are mapped by as well (`withMatrix`).
167
146
  *
168
- * Corners wind top-left, top-right, bottom-right, bottom-left with UVs
169
- * following — the same winding `pushRect` uses, which is what lets a run of
170
- * mixed rects and quads keep the canonical index pattern. The flips a command
171
- * asks for are already in the `u` / `v` the caller passes.
172
- *
173
- * `slot` is the texture unit the corners sample, which `draw.ts` assigns per
174
- * bitmap within the run.
147
+ * Corners wind top-left, top-right, bottom-right, bottom-left — the same
148
+ * winding `pushRect` uses, which is what lets a run of mixed rects and quads
149
+ * keep the canonical index pattern.
175
150
  */
176
- pushQuad(x: number, y: number, w: number, h: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, post: number, slot: number): boolean;
151
+ pushQuad(x: number, y: number, w: number, h: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, post: number, slot: number, r?: number, g?: number, b?: number): boolean;
177
152
  /**
178
153
  * Append one glyph quad: the box `(x0, y0)`-`(x1, y1)` mapped through `m`,
179
154
  * sampling `(u0, v0)`-`(u1, v1)` of the font atlas at `slot`, painted in
180
155
  * `rgba`.
181
156
  *
182
157
  * `mode` says which channels of that atlas carry the distance field, and
183
- * rides the vertices packed into the slot — so a run off a baked MSDF atlas
184
- * and one off the runtime canvas bake still share a draw. The synthetic-bold
185
- * threshold does not: it is `u_synthBold`, and `draw.ts` breaks the run when
186
- * it changes.
187
- *
188
- * **A synthetic oblique is sheared here rather than in the shader.** The old
189
- * text program carried the baseline per vertex and skewed against
190
- * `u_synthItalic`; the batch places its own corners, so the shear is one
191
- * multiply while they are being placed, and `tanItalic` is 0 for an upright
192
- * face. It has to happen before `m`, which is where the shader had it too.
158
+ * rides the vertices packed into the slot. `synthBold` is the shift on the
159
+ * field's threshold, in `a_post`: a glyph has no use for an alpha factor there.
193
160
  *
194
- * Corners wind top-left, top-right, bottom-right, bottom-left — `pushQuad`'s
195
- * winding, which is what lets a run of mixed rects, image quads and glyphs
196
- * keep the canonical index pattern.
161
+ * A synthetic oblique is sheared here, before `m`; `tanItalic` is 0 for an
162
+ * upright face. Corners wind as `pushQuad`'s do.
197
163
  */
198
- pushGlyph(x0: number, y0: number, x1: number, y1: number, baselineY: number, tanItalic: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, r: number, g: number, b: number, a: number, slot: number, mode: number): boolean;
164
+ pushGlyph(x0: number, y0: number, x1: number, y1: number, baselineY: number, tanItalic: number, m: GlMat3, u0: number, v0: number, u1: number, v1: number, r: number, g: number, b: number, a: number, slot: number, mode: number, synthBold: number): boolean;
199
165
  /**
200
166
  * Append one rect filled by a gradient: the corners of `(x, y, w, h)` mapped
201
167
  * through `m`, sampling the ramp atlas at `slot`.
202
168
  *
203
169
  * `uv` gives each channel of `a_uv` as an affine function of the coordinates
204
- * the corners arrive in, which is what lets a gradient ride the vertices at
205
- * all: a linear one's ramp position is affine in position outright, and a
206
- * radial or conic one's gradient-space *coordinate* is, even though the ramp
207
- * position it yields is not. Either way the rasterizer's interpolation across
208
- * a triangle is exact. `mode` says which of the two the fragment shader is
209
- * looking at, and `post` carries the atlas row for the modes that read it —
210
- * see `shaders/batchFill.ts`.
211
- *
212
- * Values outside 0..1 are the sampler's business; the atlas clamps to the
213
- * edge texel, which is what the gradient shader's own `clamp` did.
170
+ * the corners arrive in. `mode` says whether that is a ramp position or a
171
+ * gradient-space coordinate, and `post` carries the atlas row for the modes
172
+ * that read it — see `shaders/batchFill.ts`. Values outside 0..1 clamp to
173
+ * the atlas's edge texel.
214
174
  */
215
175
  pushGradientRect(x: number, y: number, w: number, h: number, m: GlMat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): boolean;
216
176
  /** `pushMesh` for a mesh filled by a gradient — see `pushGradientRect` for
217
177
  * what `uv`, `post` and `mode` carry. */
218
178
  pushGradientMesh(mesh: Mesh, m: GlMat3, uv: GradientUV, post: number, slot: number, mode: number, r: number, g: number, b: number, a: number): boolean;
219
179
  /**
220
- * Append a tessellated mesh through `m`, all vertices carrying `rgba`. The
221
- * mesh's own indices are rebased onto the staged vertices, which is why the
222
- * index buffer is uploaded per flush rather than written once.
180
+ * Append a tessellated mesh through `m`, all vertices carrying `rgba` and
181
+ * `P`, as `pushRect`'s do. The mesh's own indices are rebased onto the staged
182
+ * vertices, which is why the index buffer is uploaded per flush.
223
183
  */
224
- pushMesh(mesh: Mesh, m: GlMat3, r: number, g: number, b: number, a: number): boolean;
184
+ pushMesh(mesh: Mesh, m: GlMat3, r: number, g: number, b: number, a: number, P: number): boolean;
225
185
  /** Upload the staged geometry into the next set of buffers and bind its VAO.
226
186
  * Returns the index count for the caller's `drawElements`. */
227
187
  uploadAndBind(): number;
@@ -235,9 +195,7 @@ declare class DrawBatch {
235
195
  * subpixel grid the rasterizer snaps to, and the shortened edge then covers
236
196
  * different samples than the whole one did; along an axis the cut edge is
237
197
  * the same line exactly. So a slanted quad that crosses is rolled back and
238
- * refused, for `draw.ts` to clip through the stencil instead.
239
- *
240
- * A cut axis-aligned quad is still four corners, so the run stays pure.
198
+ * refused, for the caller to clip through the stencil instead.
241
199
  */
242
200
  private clipQuad;
243
201
  /** `clipQuad` for a mesh staged from `v0`. A mesh's edges are slanted in
@@ -256,8 +214,8 @@ declare class DrawBatch {
256
214
  }
257
215
 
258
216
  /**
259
- * `TilePatternSpec` → `TextureHandle`. The bridge between the serializable
260
- * half of a pattern paint and the GL texture that paints it.
217
+ * `TilePatternSpec` → `TextureHandle`. The bridge between a tile paint and the
218
+ * GL texture that paints it.
261
219
  *
262
220
  * Memoized on the spec's field values, so identical specs across nodes share
263
221
  * one texture and a re-render never re-rasterizes. The memo keeps the
@@ -273,34 +231,27 @@ declare function _resetPatternSpecCacheForTests(): void;
273
231
  * can't be rasterized — no `OffscreenCanvas`, same as `createTilePattern`.
274
232
  */
275
233
  declare function resolvePatternSpec(spec: TilePatternSpec): TextureHandle | null;
276
- /** Whether a pattern payload is a spec rather than an already-built handle. */
277
- declare function isPatternSpec(payload: TextureHandle | TilePatternSpec): payload is TilePatternSpec;
278
234
  /**
279
- * Swap a pattern paint's spec payload for the texture that paints it,
235
+ * Swap a tile paint for the `texture` paint that draws it, placement kept,
280
236
  * leaving every other fill untouched. The built-in painters run this
281
237
  * alongside `fillInPoseFrame`; a consumer emitting its own draw commands
282
238
  * runs it at the same place it runs that one.
283
239
  *
284
- * A spec that can't rasterize drops the fill rather than painting garbage.
240
+ * A tile that can't rasterize drops the fill rather than painting garbage.
285
241
  */
286
- declare function resolveFillPattern(fill: PosedFill): CommandFill | null;
287
- declare function resolveFillPattern(fill: FillStyle): FillStyle | null;
242
+ declare function resolveFillPattern(fill: PosedPaint): CommandPaint | null;
243
+ declare function resolveFillPattern(fill: Paint): Paint | null;
288
244
 
289
245
  /**
290
- * imageCache — the kit's per-`src` image loader + cache.
291
- *
292
- * The shape-painter chain (`kit:image` in `NodeShape.ts`) is synchronous, but
293
- * decoding an image is async. This module bridges the two: `getImageBitmap` is
294
- * a synchronous read that returns the decoded `ImageBitmap` when ready, and
295
- * otherwise returns `undefined` and lazily kicks off a de-duped async load.
296
- * When a load resolves (or errors), every `subscribeImageReady` listener fires
297
- * — `<SceneCanvas>` subscribes and calls `requestRedraw()`, so the painter
298
- * re-runs and emits the now-ready bitmap.
246
+ * The kit's per-`src` image loader + cache. Shape painters are synchronous
247
+ * and decoding an image is async, so `getImageBitmap` is a synchronous read
248
+ * that returns the decoded `ImageBitmap` when ready, and otherwise returns
249
+ * `undefined` and lazily kicks off a de-duped async load. When a load
250
+ * resolves (or errors), every `subscribeImageReady` listener fires.
299
251
  *
300
252
  * `src` is any browser-loadable image string: a remote URL, a `blob:` URL, or
301
- * a `data:image/…;base64,…` URI (the embedded-bytes path). The decoded bitmap
302
- * lives only here, keyed by `src` — never in node `data` — so `scene.toJSON()`
303
- * round-trips the (serializable) `src` string untouched.
253
+ * a `data:image/…;base64,…` URI. The decoded bitmap lives only here, keyed by
254
+ * `src` — never in node `data`.
304
255
  */
305
256
  /** Public shape of an image node's `data`. `src` round-trips through
306
257
  * serialization; the decoded bitmap is held in this cache, not on the node. */
@@ -338,6 +289,13 @@ type Loader = (src: string, size?: ImageRasterSize) => Promise<ImageBitmap>;
338
289
  * at; everything else decodes once. A `blob:` URL carries no type and counts
339
290
  * as raster. */
340
291
  declare function isVectorImageSrc(src: string): boolean;
292
+ /**
293
+ * Set how many bytes of decoded RGBA the cache may hold, and return the
294
+ * previous value. Default 256MB; `Infinity` never drops anything. Takes
295
+ * effect when the next image lands. A dropped image loads again on its next
296
+ * {@link getImageBitmap}, as one never requested does.
297
+ */
298
+ declare function setImageCacheBudget(bytes: number): number;
341
299
  /** Synchronous read. Returns the decoded bitmap when ready; otherwise returns
342
300
  * `undefined` and lazily starts a de-duped async load for `src`.
343
301
  *
@@ -369,4 +327,4 @@ declare function __setImageLoaderForTests(fn: Loader): void;
369
327
  * loader. Not part of the public barrel. */
370
328
  declare function _resetImageCacheForTests(): void;
371
329
 
372
- export { DrawBatch as D, FLOATS_PER_VERTEX as F, type ImageNodeData as I, type TextureEntry as T, __setImageLoaderForTests as _, type ImageRasterSize as a, type ImageStatus as b, isPatternSpec as c, isVectorImageSrc as d, releaseImage as e, resolveFillPattern as f, getImageBitmap as g, resolvePatternSpec as h, imageStatus as i, retryImage as j, _resetImageCacheForTests as k, _resetPatternSpecCacheForTests as l, _resetTextureRegistryForTests as m, registerTexture as r, subscribeImageReady as s, textureRegistry as t, unregisterTexture as u };
330
+ export { DrawBatch as D, FLOATS_PER_VERTEX as F, type ImageNodeData as I, type TextureEntry as T, __setImageLoaderForTests as _, type ImageRasterSize as a, type ImageStatus as b, isVectorImageSrc as c, releaseImage as d, resolveFillPattern as e, resolvePatternSpec as f, getImageBitmap as g, retryImage as h, imageStatus as i, subscribeImageReady as j, _resetImageCacheForTests as k, _resetPatternSpecCacheForTests as l, _resetTextureRegistryForTests as m, registerTexture as r, setImageCacheBudget as s, textureRegistry as t, unregisterTexture as u };