@weasel-js/core 1.2.0 → 1.3.0-pre.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 (59) hide show
  1. package/CHANGELOG.md +1508 -0
  2. package/dist/{DrawCommand-uNkv5TjO.d.ts → DrawCommand-BnZyQaDc.d.ts} +6 -189
  3. package/dist/chunk-2KKYDDDD.js +121 -0
  4. package/dist/chunk-2KKYDDDD.js.map +1 -0
  5. package/dist/{chunk-J7LUY47N.js → chunk-3FB44DBC.js} +3 -3
  6. package/dist/{chunk-J7LUY47N.js.map → chunk-3FB44DBC.js.map} +1 -1
  7. package/dist/{chunk-CKADTCHK.js → chunk-3ZV53ZW2.js} +51 -14
  8. package/dist/chunk-3ZV53ZW2.js.map +1 -0
  9. package/dist/{chunk-ADWOB5K2.js → chunk-67KE7SDP.js} +4 -4
  10. package/dist/{chunk-ADWOB5K2.js.map → chunk-67KE7SDP.js.map} +1 -1
  11. package/dist/{chunk-CSMF654J.js → chunk-AQS4JGRA.js} +50 -7
  12. package/dist/chunk-AQS4JGRA.js.map +1 -0
  13. package/dist/{chunk-HGF5X6MZ.js → chunk-BJN5ZRIJ.js} +2 -2
  14. package/dist/chunk-BJN5ZRIJ.js.map +1 -0
  15. package/dist/{chunk-4Z6J4IVH.js → chunk-F74NVEHT.js} +14 -46
  16. package/dist/chunk-F74NVEHT.js.map +1 -0
  17. package/dist/{chunk-7KYLIC3E.js → chunk-IFOVTYAK.js} +16611 -15749
  18. package/dist/chunk-IFOVTYAK.js.map +1 -0
  19. package/dist/{chunk-UGFFCMQP.js → chunk-MXFSHJOM.js} +4 -4
  20. package/dist/{chunk-UGFFCMQP.js.map → chunk-MXFSHJOM.js.map} +1 -1
  21. package/dist/{chunk-BHVYVFGV.js → chunk-ZB7UYJVG.js} +3 -3
  22. package/dist/{chunk-BHVYVFGV.js.map → chunk-ZB7UYJVG.js.map} +1 -1
  23. package/dist/clipboard.d.ts +3 -3
  24. package/dist/clipboard.js +3 -3
  25. package/dist/clone.d.ts +2 -2
  26. package/dist/clone.js +3 -3
  27. package/dist/{geometry-C56YbnfD.d.ts → geometry-Dtt_k6Dq.d.ts} +1 -1
  28. package/dist/{grid-DqOi0Vgi.d.ts → grid-nnXU4VjN.d.ts} +1 -1
  29. package/dist/index.d.ts +1510 -1292
  30. package/dist/index.js +10 -10
  31. package/dist/insert.d.ts +3 -3
  32. package/dist/insert.js +1 -1
  33. package/dist/move.d.ts +4 -4
  34. package/dist/move.js +3 -3
  35. package/dist/{options-C6HYCKP7.d.ts → options-CdFl510T.d.ts} +1 -1
  36. package/dist/{path-B6MMiodD.d.ts → path-JEV2c5If.d.ts} +2 -13
  37. package/dist/patterns-builtin.d.ts +1 -1
  38. package/dist/patterns-builtin.js +1 -1
  39. package/dist/{pointSnapToGrid-BBtn5bus.d.ts → pointSnapToGrid-Dmthv94u.d.ts} +2 -2
  40. package/dist/{registry-l3JX0Z6b.d.ts → registry-BU1_3L_C.d.ts} +629 -34
  41. package/dist/renderer.d.ts +38 -37
  42. package/dist/renderer.js +10 -10
  43. package/dist/resize.d.ts +4 -4
  44. package/dist/resize.js +2 -2
  45. package/dist/routing.d.ts +35 -9
  46. package/dist/routing.js +1 -1
  47. package/dist/{stroke-DaxnQ-u7.d.ts → stroke-5pBwOm9s.d.ts} +41 -4
  48. package/dist/{types-C2R2bjxf.d.ts → types-DIQAisSG.d.ts} +99 -5
  49. package/dist/{types-DbysOO-2.d.ts → types-XBcDEp3Y.d.ts} +14 -9
  50. package/dist/{types-BhrifbZ1.d.ts → types-miXHGrZM.d.ts} +1 -1
  51. package/package.json +8 -6
  52. package/dist/chunk-4Z6J4IVH.js.map +0 -1
  53. package/dist/chunk-7KYLIC3E.js.map +0 -1
  54. package/dist/chunk-CKADTCHK.js.map +0 -1
  55. package/dist/chunk-CSMF654J.js.map +0 -1
  56. package/dist/chunk-GVCNT7UH.js +0 -47
  57. package/dist/chunk-GVCNT7UH.js.map +0 -1
  58. package/dist/chunk-HGF5X6MZ.js.map +0 -1
  59. package/dist/paint-types-1fUdZUaH.d.ts +0 -266
@@ -1,40 +1,12 @@
1
- import { M as Mesh, I as ImageMinification, G as GLImageCache } from './stroke-DaxnQ-u7.js';
2
- export { S as SpriteSheet, a as StrokeOptions, V as ViewLike, f as frameRect, t as tessellateStroke, v as viewToMat3 } from './stroke-DaxnQ-u7.js';
3
- import { G as GradStop } from './paint-types-1fUdZUaH.js';
4
- export { a as TextureHandle, r as registerTexture } from './paint-types-1fUdZUaH.js';
5
- import { M as Mat3, S as ShaderProgramHandle, D as DrawCommand } from './DrawCommand-uNkv5TjO.js';
6
- export { G as GroupDrawCommand, I as ImageDrawCommand, P as PathDrawCommand, a as ShaderDrawCommand, b as ShaderUniform, c as SolidPaint, T as TextDrawCommand, m as mat3, r as registerProgram } from './DrawCommand-uNkv5TjO.js';
7
- import { P as Path } from './path-B6MMiodD.js';
1
+ import { M as Mesh, S as ShaderProgram, I as ImageMinification, G as GLImageCache } from './stroke-5pBwOm9s.js';
2
+ export { a as ShaderCompileError, b as SpriteSheet, c as StrokeOptions, V as ViewLike, f as frameRect, t as tessellateStroke, v as viewToMat3 } from './stroke-5pBwOm9s.js';
3
+ import { GradStop, TextureHandle } from '@weasel-js/paint';
4
+ export { TextureHandle } from '@weasel-js/paint';
5
+ import { M as Mat3, S as ShaderProgramHandle, D as DrawCommand } from './DrawCommand-BnZyQaDc.js';
6
+ export { G as GroupDrawCommand, I as ImageDrawCommand, P as PathDrawCommand, a as ShaderDrawCommand, b as ShaderUniform, c as SolidPaint, T as TextDrawCommand, m as mat3, r as registerProgram } from './DrawCommand-BnZyQaDc.js';
7
+ import { P as Path } from './path-JEV2c5If.js';
8
8
  export { canQueryLocalFonts, enableLocalFontOutlines, hasFontOutlines, isCanvasFont, listFontOutlines, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, subscribeGlyphReady, unregisterCanvasFont, unregisterFontOutlines } from '@weasel-js/font';
9
-
10
- /**
11
- * Minimal compile/link/lookup wrapper for a GL program. Throws
12
- * `ShaderCompileError` on compile or link failure with the GL info log
13
- * embedded in the error message — never returns a half-initialized program.
14
- *
15
- * Designed so test code can stub `getShaderParameter` / `getProgramParameter`
16
- * via the recorder Proxy without further special-casing.
17
- */
18
- type Stage = 'vertex' | 'fragment' | 'link';
19
- /** Thrown when a shader fails to compile or link, carrying which stage failed
20
- * and the driver's log. */
21
- declare class ShaderCompileError extends Error {
22
- readonly stage: Stage;
23
- readonly log: string;
24
- constructor(stage: Stage, log: string);
25
- }
26
- declare class ShaderProgram {
27
- private readonly gl;
28
- readonly handle: WebGLProgram;
29
- private readonly uniforms;
30
- private readonly attributes;
31
- constructor(gl: WebGL2RenderingContext, vertSrc: string, fragSrc: string);
32
- private compile;
33
- lookupUniforms(names: readonly string[]): void;
34
- lookupAttributes(names: readonly string[]): void;
35
- uniform(name: string): WebGLUniformLocation | undefined;
36
- attribute(name: string): number | undefined;
37
- }
9
+ import '@weasel-js/text';
38
10
 
39
11
  interface GLMeshHandle {
40
12
  readonly vao: WebGLVertexArrayObject;
@@ -227,6 +199,28 @@ declare class GroupState {
227
199
  pop(): void;
228
200
  }
229
201
 
202
+ /**
203
+ * registerTexture — accepts an image source, assigns an opaque id, stores in
204
+ * a module-level registry. Actual GL upload happens lazily at draw time in
205
+ * drawShader() via GLTextureCache.upload (which is idempotent).
206
+ *
207
+ * Lifecycle: textures live for the renderer's lifetime. No unregister in v1.
208
+ *
209
+ * Convention §9: this registry stores image data only — no per-renderer state.
210
+ * Each WeaselRenderer's GLTextureCache does its own dedup via has(id).
211
+ */
212
+
213
+ /**
214
+ * Register an image for use as a shader texture uniform.
215
+ *
216
+ * Returns a TextureHandle whose `id` can be passed as a ShaderUniform value.
217
+ * The handle is valid for the lifetime of the renderer it will be used with.
218
+ *
219
+ * @param image The image to register. HTMLImageElement must be fully loaded.
220
+ * @returns Opaque TextureHandle.
221
+ */
222
+ declare function registerTexture(image: HTMLImageElement | ImageBitmap): TextureHandle;
223
+
230
224
  /**
231
225
  * Growable vertex staging for consecutive solid-fill geometry.
232
226
  *
@@ -373,6 +367,13 @@ declare class WeaselRenderer {
373
367
  * @experimental
374
368
  */
375
369
  registerProgram(handle: ShaderProgramHandle): void;
370
+ /**
371
+ * The compiled program for `id`, compiling it against this context on first
372
+ * use. Unlike {@link registerProgram} this neither throws on a missing
373
+ * source nor on a compile failure: a paint kind asking for a program it
374
+ * never registered must decline the paint, not take down the frame.
375
+ */
376
+ private ensureProgram;
376
377
  private applyViewport;
377
378
  isContextLost(): boolean;
378
379
  private onContextLost;
@@ -461,4 +462,4 @@ declare function tessellate(path: Path, opts?: TessellateOptions): Mesh;
461
462
  */
462
463
  declare const OUTLINE_MIN_SCREEN_PX = 48;
463
464
 
464
- export { DrawCommand, IDENTITY_COLOR_MATRIX, ImageMinification, Mat3, Mesh, OUTLINE_MIN_SCREEN_PX, ShaderCompileError, ShaderProgramHandle, type TessellateOptions, WeaselRenderer, type WeaselRendererOptions, buildGradientRamp, tessellate };
465
+ export { DrawCommand, IDENTITY_COLOR_MATRIX, ImageMinification, Mat3, Mesh, OUTLINE_MIN_SCREEN_PX, ShaderProgramHandle, type TessellateOptions, WeaselRenderer, type WeaselRendererOptions, buildGradientRamp, registerTexture, tessellate };
package/dist/renderer.js CHANGED
@@ -1,12 +1,12 @@
1
- export { IDENTITY_COLOR_MATRIX, OUTLINE_MIN_SCREEN_PX, ShaderCompileError, WeaselRenderer, buildGradientRamp, canQueryLocalFonts, enableLocalFontOutlines, frameRect, hasFontOutlines, isCanvasFont, listFontOutlines, mat3, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, registerProgram, subscribeGlyphReady, tessellate, tessellateStroke, unregisterCanvasFont, unregisterFontOutlines, viewToMat3 } from './chunk-7KYLIC3E.js';
2
- import './chunk-CKADTCHK.js';
3
- import './chunk-CSMF654J.js';
4
- import './chunk-J7LUY47N.js';
5
- import './chunk-4Z6J4IVH.js';
6
- import './chunk-ADWOB5K2.js';
7
- import './chunk-UGFFCMQP.js';
8
- import './chunk-BHVYVFGV.js';
9
- import './chunk-GVCNT7UH.js';
10
- export { registerTexture } from './chunk-HGF5X6MZ.js';
1
+ export { IDENTITY_COLOR_MATRIX, OUTLINE_MIN_SCREEN_PX, ShaderCompileError, WeaselRenderer, buildGradientRamp, canQueryLocalFonts, enableLocalFontOutlines, frameRect, hasFontOutlines, isCanvasFont, listFontOutlines, mat3, outlineStatus, registerCanvasFont, registerFont, registerFontOutlines, registerProgram, subscribeGlyphReady, tessellate, tessellateStroke, unregisterCanvasFont, unregisterFontOutlines, viewToMat3 } from './chunk-IFOVTYAK.js';
2
+ import './chunk-3ZV53ZW2.js';
3
+ import './chunk-AQS4JGRA.js';
4
+ import './chunk-3FB44DBC.js';
5
+ import './chunk-F74NVEHT.js';
6
+ import './chunk-67KE7SDP.js';
7
+ import './chunk-MXFSHJOM.js';
8
+ import './chunk-ZB7UYJVG.js';
9
+ import './chunk-2KKYDDDD.js';
10
+ export { registerTexture } from './chunk-BJN5ZRIJ.js';
11
11
  //# sourceMappingURL=renderer.js.map
12
12
  //# sourceMappingURL=renderer.js.map
package/dist/resize.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- export { C as CORNER_ANCHORS, a as CornerAnchor, b as CornerHandle, U as UseResizeOptions, c as cornerPoint, d as cornerResizeHandles, f as fixedCornerOf, h as hitCornerHandle, p as pointSnapToGrid } from './pointSnapToGrid-BBtn5bus.js';
2
- export { P as PoseProjection, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR } from './geometry-C56YbnfD.js';
3
- import { R as ResizePose, B as BoundsConstraint, M as ModifierState } from './types-BhrifbZ1.js';
1
+ export { C as CORNER_ANCHORS, a as CornerAnchor, b as CornerHandle, U as UseResizeOptions, c as cornerPoint, d as cornerResizeHandles, f as fixedCornerOf, h as hitCornerHandle, p as pointSnapToGrid } from './pointSnapToGrid-Dmthv94u.js';
2
+ export { P as PoseProjection, R as RECT_POSE_DESCRIPTOR, a as ROTATED_POSE_DESCRIPTOR } from './geometry-Dtt_k6Dq.js';
3
+ import { R as ResizePose, B as BoundsConstraint, M as ModifierState } from './types-miXHGrZM.js';
4
4
  import { G as Guide } from './types-D2tTKEU0.js';
5
5
  import { V as View } from './view-DSQgxBJB.js';
6
6
  import './types-BHK2dkMu.js';
7
7
  import '@weasel-js/history';
8
- import './types-DbysOO-2.js';
8
+ import './types-XBcDEp3Y.js';
9
9
 
10
10
  /** Resize constraint that stops a node shrinking past a minimum. The anchored
11
11
  * edge stays put, so clamping pushes the dragged edge back rather than moving
package/dist/resize.js CHANGED
@@ -1,4 +1,4 @@
1
- export { CORNER_ANCHORS, DEFAULT_RESIZE_BEHAVIORS, clampMinSize, cornerPoint, cornerResizeHandles, fixedCornerOf, hitCornerHandle, lockAspectWithModifier, pointSnapToGrid, snapToGrid, snapToGuides } from './chunk-J7LUY47N.js';
2
- export { RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR } from './chunk-4Z6J4IVH.js';
1
+ export { CORNER_ANCHORS, DEFAULT_RESIZE_BEHAVIORS, clampMinSize, cornerPoint, cornerResizeHandles, fixedCornerOf, hitCornerHandle, lockAspectWithModifier, pointSnapToGrid, snapToGrid, snapToGuides } from './chunk-3FB44DBC.js';
2
+ export { RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR } from './chunk-F74NVEHT.js';
3
3
  //# sourceMappingURL=resize.js.map
4
4
  //# sourceMappingURL=resize.js.map
package/dist/routing.d.ts CHANGED
@@ -1,17 +1,18 @@
1
1
  import { ParsedModifiers, GestureName, GestureSpec } from '@weasel-js/gestures';
2
2
  export { ChannelRef, DescribeRouteOptions, GESTURE_DESCRIPTORS, GestureArgSpec, GestureDescriptor, GestureName, ModRequirement, ModifierKey, ParsedModifiers, ParsedRoute, PhaseAtom, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, RouteDescriptionPart, RouteFieldName, RouteTermLabel, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute } from '@weasel-js/gestures';
3
- import { T as Tool } from './registry-l3JX0Z6b.js';
4
- import './types-C2R2bjxf.js';
3
+ import { T as Tool } from './registry-BU1_3L_C.js';
4
+ import './types-DIQAisSG.js';
5
5
  import '@weasel-js/history';
6
- import './path-B6MMiodD.js';
7
- import './types-BhrifbZ1.js';
8
- import './types-DbysOO-2.js';
6
+ import './path-JEV2c5If.js';
7
+ import './types-miXHGrZM.js';
8
+ import './types-XBcDEp3Y.js';
9
9
  import './view-DSQgxBJB.js';
10
10
  import '@weasel-js/modes';
11
11
  import 'react';
12
- import './geometry-C56YbnfD.js';
13
- import './paint-types-1fUdZUaH.js';
14
- import './DrawCommand-uNkv5TjO.js';
12
+ import './DrawCommand-BnZyQaDc.js';
13
+ import '@weasel-js/paint';
14
+ import '@weasel-js/text';
15
+ import './geometry-Dtt_k6Dq.js';
15
16
  import 'react/jsx-runtime';
16
17
  import './types-BHK2dkMu.js';
17
18
  import '@weasel-js/geom';
@@ -53,6 +54,16 @@ interface RegistryEntry {
53
54
  * than re-walking `Tool.bindings`. */
54
55
  spec: GestureSpec;
55
56
  }
57
+ /**
58
+ * Stand-in target for a `{ kindOf }` predicate spec.
59
+ *
60
+ * The route grammar can name target *classes* (`empty`, `selected-body`,
61
+ * `kind:rect`) but not arbitrary predicates, so three distinct select-tool
62
+ * bindings all render as this one token. Narrowing it would mean giving the
63
+ * grammar a way to describe a function, which is a real design question and
64
+ * not one this reflection layer should answer by inventing syntax.
65
+ */
66
+ declare const PREDICATE_TARGET = "predicate";
56
67
  /**
57
68
  * Flatten every tool's `bindings` into route-registry rows.
58
69
  *
@@ -65,6 +76,21 @@ interface RegistryEntry {
65
76
  * suggested otherwise.
66
77
  */
67
78
  declare function buildRouteRegistry(tools: readonly Tool<unknown>[]): RegistryEntry[];
79
+ /** The route-grammar gesture a `GestureSpec.kind` routes as, or `undefined`
80
+ * for kinds the grammar has no name for. */
81
+ declare function routeGestureForSpecKind(kind: GestureSpec['kind']): GestureName | undefined;
82
+ /**
83
+ * Every route string one `GestureSpec` declares, in route-grammar notation.
84
+ *
85
+ * One string per arg alternative — a spec bound to `['ArrowUp','ArrowDown']`
86
+ * yields two routes, because each is separately conflictable and separately
87
+ * readable. Returns `[]` for spec kinds the grammar can't name.
88
+ *
89
+ * This is the display counterpart to {@link buildRouteRegistry}: same
90
+ * projection of a spec onto the grammar, rendered as text instead of as a
91
+ * conflict-checkable row.
92
+ */
93
+ declare function routesForSpec(spec: GestureSpec): readonly string[];
68
94
 
69
95
  /** Two or more tools declare the same exact (phase, gesture, arg, target,
70
96
  * modifiers) tuple — the dispatcher's slot precedence picks one
@@ -112,4 +138,4 @@ interface Conflict {
112
138
  */
113
139
  declare function findConflicts(tools: readonly Tool<unknown>[]): Conflict[];
114
140
 
115
- export { type Conflict, type RegistryEntry, buildRouteRegistry, findConflicts };
141
+ export { type Conflict, PREDICATE_TARGET, type RegistryEntry, buildRouteRegistry, findConflicts, routeGestureForSpecKind, routesForSpec };
package/dist/routing.js CHANGED
@@ -1,3 +1,3 @@
1
- export { GESTURE_DESCRIPTORS, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, buildRouteRegistry, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, findConflicts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute } from './chunk-CKADTCHK.js';
1
+ export { GESTURE_DESCRIPTORS, PREDICATE_TARGET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, buildRouteRegistry, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, findConflicts, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, parseRoute, routeGestureForSpecKind, routesForSpec } from './chunk-3ZV53ZW2.js';
2
2
  //# sourceMappingURL=routing.js.map
3
3
  //# sourceMappingURL=routing.js.map
@@ -1,6 +1,35 @@
1
- import { M as Mat3 } from './DrawCommand-uNkv5TjO.js';
2
- import { P as Path } from './path-B6MMiodD.js';
3
- import { S as Stroke } from './paint-types-1fUdZUaH.js';
1
+ import { M as Mat3 } from './DrawCommand-BnZyQaDc.js';
2
+ import { P as Path } from './path-JEV2c5If.js';
3
+ import { Stroke } from '@weasel-js/paint';
4
+
5
+ /**
6
+ * Minimal compile/link/lookup wrapper for a GL program. Throws
7
+ * `ShaderCompileError` on compile or link failure with the GL info log
8
+ * embedded in the error message — never returns a half-initialized program.
9
+ *
10
+ * Designed so test code can stub `getShaderParameter` / `getProgramParameter`
11
+ * via the recorder Proxy without further special-casing.
12
+ */
13
+ type Stage = 'vertex' | 'fragment' | 'link';
14
+ /** Thrown when a shader fails to compile or link, carrying which stage failed
15
+ * and the driver's log. */
16
+ declare class ShaderCompileError extends Error {
17
+ readonly stage: Stage;
18
+ readonly log: string;
19
+ constructor(stage: Stage, log: string);
20
+ }
21
+ declare class ShaderProgram {
22
+ private readonly gl;
23
+ readonly handle: WebGLProgram;
24
+ private readonly uniforms;
25
+ private readonly attributes;
26
+ constructor(gl: WebGL2RenderingContext, vertSrc: string, fragSrc: string);
27
+ private compile;
28
+ lookupUniforms(names: readonly string[]): void;
29
+ lookupAttributes(names: readonly string[]): void;
30
+ uniform(name: string): WebGLUniformLocation | undefined;
31
+ attribute(name: string): number | undefined;
32
+ }
4
33
 
5
34
  /**
6
35
  * A tessellated representation of a Path, ready to upload to GL.
@@ -130,6 +159,14 @@ declare function viewToMat3(view: View): Mat3;
130
159
  /** Options for stroke tessellation. */
131
160
  interface StrokeOptions {
132
161
  flattenTolerance?: number;
162
+ /**
163
+ * Shorten each open subpath by this much at its start / end, in the same
164
+ * world units as the path. Stroke markers use this so a filled head is not
165
+ * speared by its own line; the caller resolves the distance, because this
166
+ * layer knows nothing about the marker registry.
167
+ */
168
+ startInset?: number;
169
+ endInset?: number;
133
170
  }
134
171
  /** Resolve a stroke width to world units. A number is already world units;
135
172
  * `{ px }` is screen pixels divided by the accumulated scale, so it holds its
@@ -150,4 +187,4 @@ declare function resolveStrokeWidth(width: number | {
150
187
  */
151
188
  declare function tessellateStroke(path: Path, stroke: Stroke, opts?: StrokeOptions): Mesh;
152
189
 
153
- export { GLImageCache as G, type ImageMinification as I, type Mesh as M, type SpriteSheet as S, type View as V, type StrokeOptions as a, frameRect as f, resolveStrokeWidth as r, tessellateStroke as t, viewToMat3 as v };
190
+ export { GLImageCache as G, type ImageMinification as I, type Mesh as M, ShaderProgram as S, type View as V, ShaderCompileError as a, type SpriteSheet as b, type StrokeOptions as c, frameRect as f, resolveStrokeWidth as r, tessellateStroke as t, viewToMat3 as v };
@@ -1,6 +1,6 @@
1
1
  import * as _weasel_js_history from '@weasel-js/history';
2
2
  import { Op, SerializedHistory } from '@weasel-js/history';
3
- import { P as Path } from './path-B6MMiodD.js';
3
+ import { P as Path } from './path-JEV2c5If.js';
4
4
 
5
5
  /**
6
6
  * Axis-aligned rectangle pose with optional rotation. The canonical pose
@@ -79,6 +79,20 @@ interface NodeBase<TData, TLayer extends string, TPose> {
79
79
  pose: TPose;
80
80
  data: TData;
81
81
  parent: NodeId | null;
82
+ /** Nodes whose poses this node's geometry is computed from. Fixed at add
83
+ * time. Absent or empty means the node's geometry is authored, which is the
84
+ * normal case. */
85
+ dependsOn?: readonly NodeId[];
86
+ /** Computes this node's path from its dependencies' poses, in `dependsOn`
87
+ * order. A dependency that has been removed arrives as `undefined`.
88
+ * Returning `null` means "nothing to draw right now". Re-evaluated when a
89
+ * dependency's world pose changes, never authored. Absolute-pose `Scene`
90
+ * makes that the dependency's own pose, and an ancestor's move reaches it as
91
+ * a `setPose` of its own from the container cascade.
92
+ * `node` is deliberately widened: naming `TData`/`TLayer` here puts them in
93
+ * a contravariant position, making `Scene` invariant in both and breaking
94
+ * assignment kit-wide. The cost is that a `derivePath` casts to read `node.data`. */
95
+ derivePath?: (node: Node<unknown, string, TPose>, deps: readonly (TPose | undefined)[]) => Path | null;
82
96
  }
83
97
  /** A node with no children — a shape, a label, an image. */
84
98
  interface LeafNode<TData, TLayer extends string, TPose = RectPose> extends NodeBase<TData, TLayer, TPose> {
@@ -133,6 +147,11 @@ interface AddNodeSpec<TData, TLayer extends string, TPose = RectPose> {
133
147
  /** Only meaningful when `kind === 'container'`. Attach a clip-path function
134
148
  * to the node; ignored for leaves. Mirrors `ContainerNode.clipFromPose`. */
135
149
  clipFromPose?: (pose: TPose) => Path | null;
150
+ /** Mirrors `SceneNode.dependsOn`. */
151
+ dependsOn?: readonly NodeId[];
152
+ /** Mirrors `SceneNode.derivePath`. Taken as a live function; its registry key is
153
+ * looked up from it, never passed in. */
154
+ derivePath?: (node: Node<unknown, string, TPose>, deps: readonly (TPose | undefined)[]) => Path | null;
136
155
  }
137
156
  /** A custom scene mutation registered with `Scene.registerOp`: how to apply
138
157
  * it and how to undo it. The pair is what makes it participate in history. */
@@ -180,6 +199,10 @@ interface SerializedNode<TData, TLayer extends string, TPose> {
180
199
  /** Registry key for the container's clip-path factory.
181
200
  * Containers only; omitted when the container has no clip. */
182
201
  clipFromPoseKey?: string;
202
+ /** Ids this node's geometry derives from. Omitted when it derives from nothing. */
203
+ dependsOn?: readonly string[];
204
+ /** Registry key for the node's `derivePath` function. Omitted when it has none. */
205
+ derivePathKey?: string;
183
206
  }
184
207
  /** Per-scene registry mapping string keys to live function references.
185
208
  * Passed to `createScene({ ..., registry })` and `sceneFromJSON(json, { registry })`.
@@ -187,6 +210,8 @@ interface SerializedNode<TData, TLayer extends string, TPose> {
187
210
  interface SceneRegistry<TPose> {
188
211
  /** Maps registry keys to `clipFromPose` factory functions for container nodes. */
189
212
  clipFromPose?: Readonly<Record<string, (pose: TPose) => Path | null>>;
213
+ /** Maps registry keys to `derivePath` functions for nodes with `dependsOn`. */
214
+ derivePath?: Readonly<Record<string, (node: Node<unknown, string, TPose>, deps: readonly (TPose | undefined)[]) => Path | null>>;
190
215
  }
191
216
  /** Options for `useScene` — the layers the scene has, what it starts out
192
217
  * holding, and how its history behaves. */
@@ -222,6 +247,58 @@ interface UseSceneOptions<TData, TLayer extends string, TPose = RectPose> {
222
247
  * mode machines that depend on `scene.history`), pass nothing here and
223
248
  * wire it after construction via `scene.setActiveJournalAccessor(fn)`. */
224
249
  getActiveJournal?: () => _weasel_js_history.Journal | null;
250
+ /** Re-render the host on every scene mutation. Default `true`. Set `false`
251
+ * when the scene is read by a frame loop rather than by a render — a game
252
+ * loop, a simulation — and nothing in the host's DOM derives from it.
253
+ * Read by `useScene`; `createScene` ignores it. */
254
+ subscribe?: boolean;
255
+ }
256
+ /**
257
+ * One node's ephemeral presentation override — what a frame loop wants to say
258
+ * about a node without saying it about the document.
259
+ *
260
+ * Not document content: never recorded in history, never in `toJSON`, and
261
+ * writing one does not bump `Scene.getVersion()`. Hoist one entry per node and
262
+ * mutate it in place on a frame loop; `PoseOverrides.commit()` is what makes a
263
+ * mutation visible.
264
+ */
265
+ interface PoseOverride<TPose> {
266
+ /** Replaces the node's document pose everywhere the render and hit-test
267
+ * paths read one, including the clip a container derives from its pose.
268
+ * Resolved by `effectivePose` — reading `node.pose` directly is how those
269
+ * paths came to disagree about where a node is. */
270
+ pose?: TPose;
271
+ /** Multiplied into the node's painted alpha, on top of any `alphaFor`. */
272
+ alpha?: number;
273
+ }
274
+ /**
275
+ * The scene's ephemeral per-node overrides — see {@link PoseOverride}.
276
+ *
277
+ * The intended shape of a frame is: `set` each node once, mutate the entries
278
+ * in place per frame, `commit()` once. `commit` is not optional bookkeeping —
279
+ * the painter memo keys on pose *reference*, so a mutation without a commit
280
+ * paints the previous frame with no error.
281
+ *
282
+ * To promote a frame to document state (dropping a drag, baking an animation),
283
+ * write it once through `Scene.setPose` and `clear` the override.
284
+ */
285
+ interface PoseOverrides<TPose> {
286
+ /** Store `entry` for `id` **by reference**; the caller keeps mutating it. */
287
+ set(id: NodeId, entry: PoseOverride<TPose>): void;
288
+ get(id: NodeId): PoseOverride<TPose> | undefined;
289
+ has(id: NodeId): boolean;
290
+ /** The overridden ids, as a snapshot array. */
291
+ ids(): readonly NodeId[];
292
+ clear(id: NodeId): void;
293
+ clearAll(): void;
294
+ /** Publish this frame's in-place mutations: invalidate the painter memo for
295
+ * every overridden node, then notify subscribers. */
296
+ commit(): void;
297
+ /** Notified after every write. The canvas uses this to repaint without a
298
+ * scene version bump. */
299
+ subscribe(fn: () => void): () => void;
300
+ /** Monotonic write counter. A snapshot for observers that poll. */
301
+ getGeneration(): number;
225
302
  }
226
303
  /**
227
304
  * The kit-owned scene tree: nodes, layers, and the undo history over both.
@@ -251,10 +328,19 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
251
328
  * not a live view, and not yours to mutate. */
252
329
  renderOrderNodes(): readonly Node<TData, TLayer, TPose>[];
253
330
  add(spec: AddNodeSpec<TData, TLayer, TPose>): NodeId;
254
- /** Delete `id` **and its entire subtree** every descendant is removed in
255
- * the same operation. Recorded as one undoable step; `undo()` restores the
256
- * whole subtree (root + descendants, child order intact). */
331
+ /** Delete `id`, its **entire subtree**, and **everything that derives from**
332
+ * any of those nodes a node listing one of them in `dependsOn` goes too,
333
+ * along with its own subtree, transitively. A dependent can live anywhere in
334
+ * the tree, so this deletes nodes the caller never named and may unlink
335
+ * several disjoint subtrees at once. Recorded as one undoable step; `undo()`
336
+ * restores every one of them where it was, child order intact. */
257
337
  remove(id: NodeId): void;
338
+ /** {@link remove} over several roots at once, as a **single** undoable step.
339
+ * Ids resolve against the tree as it stands at the call, so an id that
340
+ * another one would cascade away is absorbed rather than removed twice —
341
+ * which is what makes it safe to pass a whole selection. Throws if any id is
342
+ * not in the scene; an empty list does nothing and records no step. */
343
+ removeMany(ids: readonly NodeId[]): void;
258
344
  update(id: NodeId, patch: {
259
345
  data: TData;
260
346
  }): void;
@@ -290,6 +376,9 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
290
376
  setLayerVisible(layer: TLayer, visible: boolean): void;
291
377
  setLayerLocked(layer: TLayer, locked: boolean): void;
292
378
  addLayer(spec: AddLayerSpec<TLayer>): void;
379
+ /** Drop a user layer and every node tagged to it, as one undoable step.
380
+ * Removal cascades, so this also deletes nodes **on other layers** that
381
+ * derive from a node on this one. */
293
382
  removeLayer(layer: TLayer): void;
294
383
  renameLayer(layer: TLayer, name: string): void;
295
384
  moveLayer(layer: TLayer, index: number): void;
@@ -331,6 +420,11 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
331
420
  * undo step of its own. */
332
421
  getSelection(): readonly NodeId[];
333
422
  setSelection(ids: readonly NodeId[]): void;
423
+ /** Per-node pose / alpha overrides the render and hit-test paths read
424
+ * through. Like {@link Scene.getSelection} this is not document content:
425
+ * writes are never recorded, never serialized, and do not bump
426
+ * {@link Scene.getVersion}. See {@link PoseOverrides}. */
427
+ readonly overrides: PoseOverrides<TPose>;
334
428
  undo(): boolean;
335
429
  redo(): boolean;
336
430
  canUndo(): boolean;
@@ -396,4 +490,4 @@ interface Scene<TData, TLayer extends string, TPose = RectPose> {
396
490
  getVersion(): number;
397
491
  }
398
492
 
399
- export { type AddLayerSpec as A, type ContainerNode as C, type LayerRecord as L, type NodeId as N, type RectPose as R, type Scene as S, type UseSceneOptions as U, type Node as a, type SerializedScene as b, type SceneRegistry as c, type RegisteredOp as d, type AddNodeSpec as e, type LeafNode as f, type SerializedNode as g, type SystemLayerRecord as h, type SystemLayerSpec as i, type UserLayerRecord as j, asNodeId as k };
493
+ export { type AddLayerSpec as A, type ContainerNode as C, type LayerRecord as L, type NodeId as N, type PoseOverride as P, type RectPose as R, type Scene as S, type UseSceneOptions as U, type Node as a, type SerializedScene as b, type SceneRegistry as c, type RegisteredOp as d, type AddNodeSpec as e, type LeafNode as f, type PoseOverrides as g, type SerializedNode as h, type SystemLayerRecord as i, type SystemLayerSpec as j, type UserLayerRecord as k, asNodeId as l };
@@ -178,13 +178,17 @@ interface MoveAdapter<TNode extends {
178
178
  /** Optional: see SceneAdapter.applyOps. */
179
179
  applyOps?(ops: Op[], label: string): void;
180
180
  findSnapTarget?(draggedId: string, worldX: number, worldY: number): SnapTarget<TPose> | null;
181
- /** Optional: direct children of `id`. When present (alongside the
182
- * `cascadeWorldPose` option on `useMove`), dragging a node
183
- * auto-cascades its descendants in the live overlay so structurally-
184
- * grouped children visually follow the parent during the drag. No
185
- * additional ops are generated — children's local poses don't change
186
- * when the parent's local pose moves. */
187
- getChildren?(id: string): string[];
181
+ /** Optional: ordered children of `parentId`, `null` for the root siblings.
182
+ * One contract with {@link OrderedAdapter.getChildren} the two land on
183
+ * the same adapter object, and an implementation that answers only node
184
+ * ids returns `[]` for the root, which the ops read as "no siblings".
185
+ *
186
+ * When present (alongside the `cascadeWorldPose` option on `useMove`),
187
+ * dragging a node auto-cascades its descendants in the live overlay so
188
+ * structurally-grouped children visually follow the parent during the
189
+ * drag. No additional ops are generated — children's local poses don't
190
+ * change when the parent's local pose moves. */
191
+ getChildren?(parentId: string | null): string[];
188
192
  /** Optional: layout strategy attached to a container, or null if the
189
193
  * container uses absolute positioning (default behavior). When present,
190
194
  * `useMove` uses the strategy to compute drop targets, sibling reflow,
@@ -360,11 +364,12 @@ interface LayerEnumerableAdapter<TLayer extends string = string> {
360
364
  */
361
365
  interface OrderedAdapter {
362
366
  /** Ordered children of `parentId` (or root siblings if null), in z-order:
363
- * index 0 is bottom, last index is top. */
367
+ * index 0 is bottom, last index is top. The same contract
368
+ * {@link MoveAdapter.getChildren} declares — one method, two readers. */
364
369
  getChildren?(parentId: string | null): string[];
365
370
  /** Rewrite the order of `parentId`'s children. Length and contents must
366
371
  * match the existing children — reorder only, no add/remove. */
367
372
  setChildOrder?(parentId: string | null, ids: string[]): void;
368
373
  }
369
374
 
370
- export type { AreaSelectAdapter as A, ClipboardSnapshot as C, DropTarget as D, InsertAdapter as I, LayoutStrategy as L, MoveAdapter as M, OrderedAdapter as O, RotateAdapter as R, SnapTarget as S, LassoHitMode as a, LassoSelectAdapter as b, ResizeAdapter as c, SceneAdapter as d, LayerEnumerableAdapter as e, LayoutSnap as f, ContainerBounds as g, LayoutChild as h, LayoutContainer as i, LayoutDragged as j };
375
+ export type { AreaSelectAdapter as A, ClipboardSnapshot as C, DropTarget as D, InsertAdapter as I, LayoutStrategy as L, MoveAdapter as M, OrderedAdapter as O, RotateAdapter as R, SnapTarget as S, SceneAdapter as a, LassoHitMode as b, LassoSelectAdapter as c, ResizeAdapter as d, LayerEnumerableAdapter as e, LayoutSnap as f, ContainerBounds as g, LayoutChild as h, LayoutContainer as i, LayoutDragged as j };
@@ -1,5 +1,5 @@
1
1
  import { Op } from '@weasel-js/history';
2
- import { S as SnapTarget, M as MoveAdapter, I as InsertAdapter } from './types-DbysOO-2.js';
2
+ import { S as SnapTarget, M as MoveAdapter, I as InsertAdapter } from './types-XBcDEp3Y.js';
3
3
 
4
4
  /**
5
5
  * Snapshot of modifier-key state at gesture dispatch.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/core",
3
- "version": "1.2.0",
3
+ "version": "1.3.0-pre.0",
4
4
  "description": "Domain-agnostic 2D scene graph primitives for React: viewport math, drag/resize/insert/clone interactions, layered canvas rendering.",
5
5
  "license": "MIT",
6
6
  "author": "orochi235",
@@ -74,11 +74,13 @@
74
74
  "react": ">=18"
75
75
  },
76
76
  "dependencies": {
77
- "@weasel-js/font": "1.2.0",
78
- "@weasel-js/geom": "1.2.0",
79
- "@weasel-js/gestures": "1.2.0",
80
- "@weasel-js/history": "1.2.0",
81
- "@weasel-js/modes": "1.2.0",
77
+ "@weasel-js/font": "1.3.0-pre.0",
78
+ "@weasel-js/geom": "1.3.0-pre.0",
79
+ "@weasel-js/gestures": "1.3.0-pre.0",
80
+ "@weasel-js/history": "1.3.0-pre.0",
81
+ "@weasel-js/modes": "1.3.0-pre.0",
82
+ "@weasel-js/paint": "1.3.0-pre.0",
83
+ "@weasel-js/text": "1.3.0-pre.0",
82
84
  "earcut": "2.2.4",
83
85
  "polygon-clipping": "^0.15.7"
84
86
  },