@weasel-js/core 0.5.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.
- package/CHANGELOG.md +381 -0
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/dist/DrawCommand-Dl0bXNfS.d.ts +500 -0
- package/dist/chunk-775XXAHR.js +216 -0
- package/dist/chunk-775XXAHR.js.map +1 -0
- package/dist/chunk-7V6JEOXE.js +27754 -0
- package/dist/chunk-7V6JEOXE.js.map +1 -0
- package/dist/chunk-AM6ARSPN.js +517 -0
- package/dist/chunk-AM6ARSPN.js.map +1 -0
- package/dist/chunk-BGGZ4CVF.js +248 -0
- package/dist/chunk-BGGZ4CVF.js.map +1 -0
- package/dist/chunk-BHVYVFGV.js +29 -0
- package/dist/chunk-BHVYVFGV.js.map +1 -0
- package/dist/chunk-CQNKCG34.js +831 -0
- package/dist/chunk-CQNKCG34.js.map +1 -0
- package/dist/chunk-GVCNT7UH.js +47 -0
- package/dist/chunk-GVCNT7UH.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-UGFFCMQP.js +28 -0
- package/dist/chunk-UGFFCMQP.js.map +1 -0
- package/dist/chunk-VOVKONXA.js +103 -0
- package/dist/chunk-VOVKONXA.js.map +1 -0
- package/dist/chunk-Y52N27PF.js +39 -0
- package/dist/chunk-Y52N27PF.js.map +1 -0
- package/dist/clipboard.d.ts +91 -0
- package/dist/clipboard.js +6 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/clone.d.ts +8 -0
- package/dist/clone.js +6 -0
- package/dist/clone.js.map +1 -0
- package/dist/fitViewToBounds-evGsnR8Q.d.ts +62 -0
- package/dist/grid-Cf87knjU.d.ts +153 -0
- package/dist/index-DZBYMsHI.d.ts +1555 -0
- package/dist/index.css +121 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +10200 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/insert.d.ts +33 -0
- package/dist/insert.js +81 -0
- package/dist/insert.js.map +1 -0
- package/dist/move.d.ts +69 -0
- package/dist/move.js +145 -0
- package/dist/move.js.map +1 -0
- package/dist/options-BPPBWMa7.d.ts +64 -0
- package/dist/patterns-builtin.d.ts +55 -0
- package/dist/patterns-builtin.js +100 -0
- package/dist/patterns-builtin.js.map +1 -0
- package/dist/pointSnapToGrid-D7s7QmOF.d.ts +185 -0
- package/dist/registerFont-CP-wCsrz.d.ts +109 -0
- package/dist/registerTexture-BzHTLhD9.d.ts +25 -0
- package/dist/renderer.css +121 -0
- package/dist/renderer.css.map +1 -0
- package/dist/renderer.d.ts +376 -0
- package/dist/renderer.js +13 -0
- package/dist/renderer.js.map +1 -0
- package/dist/resize.d.ts +78 -0
- package/dist/resize.js +5 -0
- package/dist/resize.js.map +1 -0
- package/dist/routing.css +35 -0
- package/dist/routing.css.map +1 -0
- package/dist/routing.d.ts +14 -0
- package/dist/routing.js +4 -0
- package/dist/routing.js.map +1 -0
- package/dist/types-B6MMiodD.d.ts +59 -0
- package/dist/types-BJ8_cyT7.d.ts +130 -0
- package/dist/types-B_-khFM0.d.ts +331 -0
- package/dist/types-BjUi2vA-.d.ts +355 -0
- package/dist/types-Cpb4hii1.d.ts +445 -0
- package/dist/types-D2tTKEU0.d.ts +18 -0
- package/dist/view-DSQgxBJB.d.ts +63 -0
- package/package.json +96 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { R as ResizePose, b as RotatedPose, c as ResizeAnchor, B as BoundsConstraint, P as PointSnapBehavior, d as PointSnapFrame, M as ModifierState } from './types-BjUi2vA-.js';
|
|
2
|
+
import { B as Bounds } from './fitViewToBounds-evGsnR8Q.js';
|
|
3
|
+
import { D as DebugSink } from './types-BJ8_cyT7.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Bridges arbitrary `TPose` shapes into the resize hook's bounds-driven math.
|
|
7
|
+
* The hook reads bounds via `getBounds`, runs anchor-relative math on those
|
|
8
|
+
* bounds, then asks `remapBounds` to project the result back into TPose.
|
|
9
|
+
*
|
|
10
|
+
* `remapBounds(pose, src, dst)` is a single operation that subsumes both
|
|
11
|
+
* "set my own AABB to dst" (single-leaf resize) and "scale me as a leaf
|
|
12
|
+
* inside parent's src→dst rect" (group resize) — they're the same affine
|
|
13
|
+
* map. For rect-shaped poses the default geometry interprets the pose as
|
|
14
|
+
* its own bounds; for Path or polygon poses the consumer supplies a
|
|
15
|
+
* projection that knows how to read and rewrite the underlying geometry.
|
|
16
|
+
*/
|
|
17
|
+
interface PoseProjection<TPose> {
|
|
18
|
+
getBounds(pose: TPose): ResizePose;
|
|
19
|
+
remapBounds(pose: TPose, src: ResizePose, dst: ResizePose): TPose;
|
|
20
|
+
/** Translate the pose by (dx, dy). Optional — when omitted, callers fall
|
|
21
|
+
* back to a translation derived from `remapBounds` (origin shifted, no
|
|
22
|
+
* scale). Path-shaped poses should provide this for performance. */
|
|
23
|
+
translate?(pose: TPose, dx: number, dy: number): TPose;
|
|
24
|
+
/** True iff any portion of the pose's geometry intersects `rect`. Optional
|
|
25
|
+
* — when omitted, area-select and similar callers test against `getBounds`
|
|
26
|
+
* AABB (looser, but correct for axis-aligned rect poses). */
|
|
27
|
+
intersectsRect?(pose: TPose, rect: ResizePose): boolean;
|
|
28
|
+
/** Interpolate between two poses. Optional — animation helpers fall back to
|
|
29
|
+
* rect-shape lerp when omitted (which fails for non-rect poses). */
|
|
30
|
+
lerp?(a: TPose, b: TPose, t: number): TPose;
|
|
31
|
+
/** Read the pose's rotation in radians. Pivot is the AABB center
|
|
32
|
+
* (`getBounds(pose)` center). Default 0 when omitted — descriptor
|
|
33
|
+
* declares "this pose has no rotation." When supplied and non-zero,
|
|
34
|
+
* `useResize` projects the drag delta into the leaf's local frame,
|
|
35
|
+
* runs anchor math there, and translates the resulting pose so the
|
|
36
|
+
* diagonally opposite world-space corner is pinned. */
|
|
37
|
+
getRotation?(pose: TPose): number;
|
|
38
|
+
/** True iff this pose shape can carry a rotation. Consulted by the
|
|
39
|
+
* rotation affordance to decide whether to render the rotate cursor /
|
|
40
|
+
* drag-band over a selection. When omitted, the kit assumes `true` for
|
|
41
|
+
* back-compat — descriptors whose poses lack `x/y/width/height/rotation`
|
|
42
|
+
* fields (e.g. polygon Paths) should return `false` so the affordance
|
|
43
|
+
* hides instead of exposing a non-functional rotate cursor. */
|
|
44
|
+
supportsRotation?(pose: TPose): boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Identity geometry for `TPose extends ResizePose`. Treats the pose as its
|
|
47
|
+
* own bounds and remaps via affine scale against `src`/`dst`. */
|
|
48
|
+
declare const RECT_POSE_DESCRIPTOR: PoseProjection<ResizePose>;
|
|
49
|
+
/** Identity geometry for `RotatedPose`. Inherits rect-shape projection
|
|
50
|
+
* from `RECT_POSE_DESCRIPTOR` (the `RotatedPose extends ResizePose`
|
|
51
|
+
* subtype lets the rect descriptor's methods apply directly; `remapBounds`
|
|
52
|
+
* preserves the `rotation` field via `...p` spread). Adds `getRotation` so
|
|
53
|
+
* `useResize` knows to take the rotation-aware math path. */
|
|
54
|
+
declare const ROTATED_POSE_DESCRIPTOR: PoseProjection<RotatedPose>;
|
|
55
|
+
|
|
56
|
+
/** Corner resize-handle: world-space center plus the anchor that pins the opposite corner during resize. */
|
|
57
|
+
interface CornerHandle {
|
|
58
|
+
cx: number;
|
|
59
|
+
cy: number;
|
|
60
|
+
anchor: ResizeAnchor;
|
|
61
|
+
}
|
|
62
|
+
/** Which AABB edge a corner sits on, per axis. `'min'` = the x/y origin
|
|
63
|
+
* edge; `'max'` = the origin + extent edge. */
|
|
64
|
+
type CornerEdge = 'min' | 'max';
|
|
65
|
+
/** One entry of the canonical 4-corner resize layout. The single source of
|
|
66
|
+
* truth for "which corner maps to which anchor / handle-kind". */
|
|
67
|
+
interface CornerAnchor {
|
|
68
|
+
/** Which x-edge the corner sits on (`'min'` = left, `'max'` = right). */
|
|
69
|
+
xEdge: CornerEdge;
|
|
70
|
+
/** Which y-edge the corner sits on (`'min'` = top, `'max'` = bottom). */
|
|
71
|
+
yEdge: CornerEdge;
|
|
72
|
+
/** Anchor that pins the diagonally-opposite (fixed) corner. Always the
|
|
73
|
+
* axis-wise opposite of `{xEdge, yEdge}`. */
|
|
74
|
+
anchor: ResizeAnchor;
|
|
75
|
+
/** Affordance/handle discriminator string for this corner. */
|
|
76
|
+
kind: string;
|
|
77
|
+
/** Short positional tag (`'<xEdge>-<yEdge>'`), e.g. `'min-max'`. */
|
|
78
|
+
tag: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The single ordered corner→anchor table. Order is **load-bearing**: every
|
|
82
|
+
* consumer iterates it in this sequence (TL, TR, BL, BR) so positional
|
|
83
|
+
* meaning (the i-th handle / `kind` / `tag`) stays consistent across the
|
|
84
|
+
* resize-handle affordance, the affordance-hit classifier, and
|
|
85
|
+
* `cornerResizeHandles`. Each corner's `anchor` names the diagonally
|
|
86
|
+
* opposite corner, so dragging the corner scales the box from that fixed
|
|
87
|
+
* point.
|
|
88
|
+
*/
|
|
89
|
+
declare const CORNER_ANCHORS: readonly CornerAnchor[];
|
|
90
|
+
/** Resolve a corner's world-space position for the given bounds. `xEdge`
|
|
91
|
+
* `'max'` → `x + width`; `yEdge` `'max'` → `y + height`. */
|
|
92
|
+
declare function cornerPoint(bounds: Bounds, entry: Pick<CornerAnchor, 'xEdge' | 'yEdge'>): {
|
|
93
|
+
x: number;
|
|
94
|
+
y: number;
|
|
95
|
+
};
|
|
96
|
+
/** Standard 4-corner resize-handle layout: each corner pins the opposite
|
|
97
|
+
* corner via an anchor of `{x: 'min'|'max', y: 'min'|'max'}` so dragging it
|
|
98
|
+
* scales the box from the fixed opposite corner. Decodes {@link CORNER_ANCHORS}
|
|
99
|
+
* against `bounds`. */
|
|
100
|
+
declare function cornerResizeHandles(bounds: Bounds): CornerHandle[];
|
|
101
|
+
/** Square hit-test for a handle: returns true if `(px, py)` is within
|
|
102
|
+
* `radius` of the handle center on both axes. */
|
|
103
|
+
declare function hitCornerHandle(handle: CornerHandle, px: number, py: number, radius: number): boolean;
|
|
104
|
+
/** The corner that does NOT move under a resize gesture with the given
|
|
105
|
+
* anchor. Used by the rotated-resize math to pin a world-space invariant.
|
|
106
|
+
*
|
|
107
|
+
* Convention: `anchor.x === 'min'` means the min-x (left) edge is the
|
|
108
|
+
* fixed anchor, so the fixed corner sits at `x = bounds.x` (min-x).
|
|
109
|
+
* `anchor.x === 'max'` means the max-x (right) edge is fixed, so the
|
|
110
|
+
* fixed corner sits at `x = bounds.x + bounds.width`. `'free'` on an
|
|
111
|
+
* axis means that axis doesn't move; the fixed coord is the bounds
|
|
112
|
+
* origin on that axis. */
|
|
113
|
+
declare function fixedCornerOf(bounds: Bounds, anchor: ResizeAnchor): {
|
|
114
|
+
x: number;
|
|
115
|
+
y: number;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Option surface for the `resize` action.
|
|
119
|
+
*
|
|
120
|
+
* Lives in a sibling file (not `resize.ts`) so the type contract stays stable
|
|
121
|
+
* even after the legacy `useResize` hook is gone.
|
|
122
|
+
* Consumers should import from here directly; `resize.ts` re-exports the
|
|
123
|
+
* same symbol for back-compat. */
|
|
124
|
+
|
|
125
|
+
interface UseResizeOptions<TPose> {
|
|
126
|
+
/** Behaviors are rect-typed: they read/write `{x,y,width,height}`. When
|
|
127
|
+
* `TPose` is non-rect, pass `geometry` to project pose↔bounds; behaviors
|
|
128
|
+
* in that case are typed `never` because none in the kit's library would
|
|
129
|
+
* understand the pose shape. */
|
|
130
|
+
behaviors?: TPose extends ResizePose ? BoundsConstraint<TPose>[] : never;
|
|
131
|
+
resizeLabel?: string;
|
|
132
|
+
/** Reserved; resize is never transient in practice. Ignored. */
|
|
133
|
+
transient?: boolean;
|
|
134
|
+
onGestureStart?: (id: string) => void;
|
|
135
|
+
onGestureEnd?: (committed: boolean) => void;
|
|
136
|
+
/** Optional: expand the incoming id into leaf ids before pose lookups.
|
|
137
|
+
* Mirrors `useMove`'s `expandIds`. Used for group expansion: when the
|
|
138
|
+
* gesture is started against a group id, the kit
|
|
139
|
+
* resizes by computing the union AABB of the leaves' origin bounds,
|
|
140
|
+
* running the compute pipeline on that union rect (group bounds), and
|
|
141
|
+
* remapping each leaf via `geometry.remapBounds(leaf, originGroupBounds,
|
|
142
|
+
* proposedGroupBounds)`.
|
|
143
|
+
*
|
|
144
|
+
* When `expandIds` is omitted or returns the original single id, the
|
|
145
|
+
* gesture takes the single-leaf path (the leaf's own bounds become both
|
|
146
|
+
* the origin and the target of the same `remapBounds` call).
|
|
147
|
+
*
|
|
148
|
+
* Called once at `start()`. Returning `[]` aborts the gesture cleanly. */
|
|
149
|
+
expandIds?: (ids: string[]) => string[];
|
|
150
|
+
/** Projection from `TPose` to bounds and back. Defaults to rect identity
|
|
151
|
+
* when `TPose extends ResizePose`. Required for non-rect TPose (Path,
|
|
152
|
+
* polygon, etc.). */
|
|
153
|
+
geometry?: PoseProjection<TPose>;
|
|
154
|
+
/** Behaviors that operate on world-space anchor points. Fire after
|
|
155
|
+
* `behaviors[]` (bounds-frame). Each behavior receives a `PointSnapContext`
|
|
156
|
+
* with world-space frame points and returns at most one `PointSnapResult`;
|
|
157
|
+
* the hook back-solves the local pose so the chosen frame's world point
|
|
158
|
+
* lands on the snap target. First non-null result wins. */
|
|
159
|
+
pointSnapBehaviors?: TPose extends ResizePose ? PointSnapBehavior<TPose>[] : never;
|
|
160
|
+
/** Optional debug sink. When supplied, records corner-handle positions +
|
|
161
|
+
* circular hitboxes when the gesture starts (covers the on-screen
|
|
162
|
+
* handles for the resized target). Tree-shakes via optional-chain
|
|
163
|
+
* when omitted. */
|
|
164
|
+
debug?: DebugSink;
|
|
165
|
+
/** Hit-test radius for corner handles, in screen pixels. Used purely for
|
|
166
|
+
* the recorded debug hitbox circle radius — does not affect actual hit
|
|
167
|
+
* math (which lives in `usePointerGestures`). Default `8`. */
|
|
168
|
+
handleHitRadius?: number;
|
|
169
|
+
/** Per-node resizability predicate. Returns `false` for nodes that should
|
|
170
|
+
* never show resize handles (and thus can't start a resize gesture) — e.g.
|
|
171
|
+
* fixed-footprint icons, locked layers. `<SceneCanvas>` folds this over the
|
|
172
|
+
* current selection into the `selectionResizable` rule-ctx flag, so the
|
|
173
|
+
* default `selection.resize-handles` chrome rule hides handles whenever any
|
|
174
|
+
* selected node is non-resizable (which also disables the affordance, since
|
|
175
|
+
* visible==hittable). Default: every node resizable. */
|
|
176
|
+
resizable?: (id: string) => boolean;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
declare function pointSnapToGrid<TPose extends ResizePose>(args: {
|
|
180
|
+
spacing: number;
|
|
181
|
+
frame?: PointSnapFrame;
|
|
182
|
+
bypassKey?: keyof ModifierState;
|
|
183
|
+
}): PointSnapBehavior<TPose>;
|
|
184
|
+
|
|
185
|
+
export { CORNER_ANCHORS as C, type PoseProjection as P, RECT_POSE_DESCRIPTOR as R, type UseResizeOptions as U, type CornerAnchor as a, type CornerHandle as b, ROTATED_POSE_DESCRIPTOR as c, cornerPoint as d, cornerResizeHandles as e, fixedCornerOf as f, type CornerEdge as g, hitCornerHandle as h, pointSnapToGrid as p };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { M as Mat3 } from './DrawCommand-Dl0bXNfS.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GL texture upload cache for ImageBitmap objects.
|
|
5
|
+
*
|
|
6
|
+
* Key: ImageBitmap (or pattern source object) identity (WeakMap) — lets GC
|
|
7
|
+
* reclaim unreferenced bitmaps. The GL textures are NOT freed when the source
|
|
8
|
+
* is gc'd; deferred to v2.
|
|
9
|
+
*
|
|
10
|
+
* Wrapping is set once at upload time per the `repetition` parameter:
|
|
11
|
+
* - undefined / 'no-repeat' → CLAMP_TO_EDGE
|
|
12
|
+
* - 'repeat' → REPEAT (both axes)
|
|
13
|
+
* - 'repeat-x' → REPEAT on S, CLAMP on T
|
|
14
|
+
* - 'repeat-y' → CLAMP on S, REPEAT on T
|
|
15
|
+
*
|
|
16
|
+
* Convention §2: texels stored straight; shader premultiplies.
|
|
17
|
+
*/
|
|
18
|
+
type PatternRepetition = 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat';
|
|
19
|
+
/** MIN_FILTER strategy for uploaded textures. */
|
|
20
|
+
type ImageMinification = 'linear' | 'mipmap';
|
|
21
|
+
type TexSource = ImageBitmap | ImageData | HTMLCanvasElement | HTMLImageElement;
|
|
22
|
+
declare class GLImageCache {
|
|
23
|
+
private readonly gl;
|
|
24
|
+
private readonly minification;
|
|
25
|
+
private readonly map;
|
|
26
|
+
/** `minification` selects the MIN_FILTER strategy for uploaded textures.
|
|
27
|
+
* `'linear'` (default) is the screen path's existing behavior. `'mipmap'`
|
|
28
|
+
* generates mipmaps and filters LINEAR_MIPMAP_LINEAR — required for
|
|
29
|
+
* quality minification when a large source bitmap is drawn small (the
|
|
30
|
+
* headless print/export path); bilinear-only minification undersamples
|
|
31
|
+
* and produces moiré. */
|
|
32
|
+
constructor(gl: WebGL2RenderingContext, minification?: ImageMinification);
|
|
33
|
+
upload(key: object, source: TexSource, repetition?: PatternRepetition): WebGLTexture;
|
|
34
|
+
bind(key: object, unit: number): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* View → Mat3 helper for layer `draw` implementations on world-space layers.
|
|
39
|
+
*
|
|
40
|
+
* The kit's main package ships a `View` type at
|
|
41
|
+
* `src/core/viewport/view.ts`; we re-declare a structurally compatible
|
|
42
|
+
* shape here to avoid a runtime cross-package import. Exported as
|
|
43
|
+
* `ViewLike` from the package barrel.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
/** A weasel View — `{x, y, scale: {x, y}}`. Local type to avoid a cross-package import. */
|
|
47
|
+
interface View {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
scale: {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the world→screen transform matrix for a `View`.
|
|
57
|
+
* Use as the `transform` field of a `kind: 'group'` DrawCommand to wrap
|
|
58
|
+
* world-space content emitted from a layer `draw` implementation.
|
|
59
|
+
*
|
|
60
|
+
* Mapping: `screen = (world − {view.x, view.y}) × {view.scale.x, view.scale.y}`.
|
|
61
|
+
*
|
|
62
|
+
* Column-major layout (matches `mat3.identity()`):
|
|
63
|
+
* `[scale.x, 0, 0, 0, scale.y, 0, -view.x*scale.x, -view.y*scale.y, 1]`.
|
|
64
|
+
*/
|
|
65
|
+
declare function viewToMat3(view: View): Mat3;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* DynamicGlyphAtlas — runtime single-channel SDF glyphs for canvas-sourced
|
|
69
|
+
* (installed machine) fonts. TinySDF technique: canvas fillText at 48 px →
|
|
70
|
+
* Euclidean distance transform → shelf-packed R8 pages (1024², max 4).
|
|
71
|
+
*
|
|
72
|
+
* Baked MSDF atlases always win: this tier only serves families registered
|
|
73
|
+
* via `registerCanvasFont` that have no baked entry (see resolveFontVariant).
|
|
74
|
+
*
|
|
75
|
+
* Faces expose a BmFont-shaped `font` whose charMap grows as glyphs are
|
|
76
|
+
* requested, so `layoutRuns` consumes them through the same code path as
|
|
77
|
+
* baked atlases. A char's advance is valid immediately (measureText); its
|
|
78
|
+
* atlas rect fills in when the bake lands (width 0 / page -1 until then, so
|
|
79
|
+
* layout advances the pen but emits no quad).
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/** Mark `family` as canvas-sourced: when no baked atlas covers it,
|
|
83
|
+
* resolveFontVariant serves it from this dynamic atlas. */
|
|
84
|
+
declare function registerCanvasFont(family: string): void;
|
|
85
|
+
declare function isCanvasFont(family: string): boolean;
|
|
86
|
+
/** Remove a canvas family. Its faces are dropped; already-baked glyph
|
|
87
|
+
* pixels stay in their pages (no eviction in v1). */
|
|
88
|
+
declare function unregisterCanvasFont(family: string): void;
|
|
89
|
+
/** Subscribe to deferred-bake completion (fires after each flush batch).
|
|
90
|
+
* `<SceneCanvas>` subscribes and requests a redraw, mirroring
|
|
91
|
+
* `subscribeImageReady`. Returns an unsubscribe. */
|
|
92
|
+
declare function subscribeGlyphReady(cb: () => void): () => void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* FontRegistry and registerFont() public API.
|
|
96
|
+
*
|
|
97
|
+
* Variants are keyed by (family, weight, style). registerFont() takes a
|
|
98
|
+
* FontVariant alongside the family and the two URLs; the registry stores
|
|
99
|
+
* entries in a two-level Map so resolveFontVariant() can iterate a family's
|
|
100
|
+
* variants for the fallback chain.
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
interface FontVariant {
|
|
104
|
+
weight?: number;
|
|
105
|
+
style?: 'normal' | 'italic';
|
|
106
|
+
}
|
|
107
|
+
declare function registerFont(family: string, variant: FontVariant, metricsUrl: string, atlasUrl: string): Promise<void>;
|
|
108
|
+
|
|
109
|
+
export { type FontVariant as F, GLImageCache as G, type ImageMinification as I, type View as V, registerFont as a, isCanvasFont as i, registerCanvasFont as r, subscribeGlyphReady as s, unregisterCanvasFont as u, viewToMat3 as v };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registerTexture — accepts an image source, assigns an opaque id, stores in
|
|
3
|
+
* a module-level registry. Actual GL upload happens lazily at draw time in
|
|
4
|
+
* drawShader() via GLTextureCache.upload (which is idempotent).
|
|
5
|
+
*
|
|
6
|
+
* Lifecycle: textures live for the renderer's lifetime. No unregister in v1.
|
|
7
|
+
*
|
|
8
|
+
* Convention §9: this registry stores image data only — no per-renderer state.
|
|
9
|
+
* Each WeaselRenderer's GLTextureCache does its own dedup via has(id).
|
|
10
|
+
*/
|
|
11
|
+
interface TextureHandle {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Register an image for use as a shader texture uniform.
|
|
16
|
+
*
|
|
17
|
+
* Returns a TextureHandle whose `id` can be passed as a ShaderUniform value.
|
|
18
|
+
* The handle is valid for the lifetime of the renderer it will be used with.
|
|
19
|
+
*
|
|
20
|
+
* @param image The image to register. HTMLImageElement must be fully loaded.
|
|
21
|
+
* @returns Opaque TextureHandle.
|
|
22
|
+
*/
|
|
23
|
+
declare function registerTexture(image: HTMLImageElement | ImageBitmap): TextureHandle;
|
|
24
|
+
|
|
25
|
+
export { type TextureHandle as T, registerTexture as r };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/* src/tools/routing/reflection/ToolDebugOverlay.module.css */
|
|
2
|
+
.overlay {
|
|
3
|
+
position: absolute;
|
|
4
|
+
bottom: 12px;
|
|
5
|
+
right: 12px;
|
|
6
|
+
min-width: 180px;
|
|
7
|
+
padding: 8px 10px;
|
|
8
|
+
background: rgba(20, 20, 24, 0.86);
|
|
9
|
+
color: #eaeaea;
|
|
10
|
+
font:
|
|
11
|
+
11px/1.4 ui-monospace,
|
|
12
|
+
"SF Mono",
|
|
13
|
+
Menlo,
|
|
14
|
+
monospace;
|
|
15
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
16
|
+
border-radius: 4px;
|
|
17
|
+
pointer-events: none;
|
|
18
|
+
user-select: none;
|
|
19
|
+
}
|
|
20
|
+
.row {
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: space-between;
|
|
23
|
+
gap: 12px;
|
|
24
|
+
}
|
|
25
|
+
.label {
|
|
26
|
+
color: #888;
|
|
27
|
+
}
|
|
28
|
+
.value {
|
|
29
|
+
color: #f5f5f5;
|
|
30
|
+
}
|
|
31
|
+
.empty {
|
|
32
|
+
color: #888;
|
|
33
|
+
font-style: italic;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* src/canvas/PickHud.module.css */
|
|
37
|
+
.hud {
|
|
38
|
+
position: fixed;
|
|
39
|
+
z-index: 10000;
|
|
40
|
+
background: rgba(0, 0, 0, 0.7);
|
|
41
|
+
color: #e8e8e8;
|
|
42
|
+
font:
|
|
43
|
+
11px ui-monospace,
|
|
44
|
+
SFMono-Regular,
|
|
45
|
+
Menlo,
|
|
46
|
+
monospace;
|
|
47
|
+
padding: 6px 8px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
line-height: 1.4;
|
|
51
|
+
text-align: right;
|
|
52
|
+
min-width: 120px;
|
|
53
|
+
max-width: 260px;
|
|
54
|
+
}
|
|
55
|
+
.header {
|
|
56
|
+
color: #888;
|
|
57
|
+
margin-bottom: 2px;
|
|
58
|
+
}
|
|
59
|
+
.empty {
|
|
60
|
+
color: #888;
|
|
61
|
+
font-style: italic;
|
|
62
|
+
}
|
|
63
|
+
.list {
|
|
64
|
+
list-style: none;
|
|
65
|
+
margin: 0;
|
|
66
|
+
padding: 0;
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: 1px;
|
|
70
|
+
}
|
|
71
|
+
.item {
|
|
72
|
+
white-space: nowrap;
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
text-overflow: ellipsis;
|
|
75
|
+
}
|
|
76
|
+
.itemBest {
|
|
77
|
+
font-weight: 700;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* src/canvas/ModalityHud.module.css */
|
|
81
|
+
.hud {
|
|
82
|
+
position: fixed;
|
|
83
|
+
z-index: 10000;
|
|
84
|
+
background: rgba(0, 0, 0, 0.7);
|
|
85
|
+
color: #e8e8e8;
|
|
86
|
+
font:
|
|
87
|
+
11px ui-monospace,
|
|
88
|
+
SFMono-Regular,
|
|
89
|
+
Menlo,
|
|
90
|
+
monospace;
|
|
91
|
+
padding: 6px 8px;
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
pointer-events: none;
|
|
94
|
+
line-height: 1.4;
|
|
95
|
+
text-align: right;
|
|
96
|
+
min-width: 120px;
|
|
97
|
+
max-width: 260px;
|
|
98
|
+
}
|
|
99
|
+
.row {
|
|
100
|
+
display: flex;
|
|
101
|
+
gap: 8px;
|
|
102
|
+
justify-content: flex-end;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
}
|
|
105
|
+
.label {
|
|
106
|
+
color: #888;
|
|
107
|
+
}
|
|
108
|
+
.value {
|
|
109
|
+
color: #e8e8e8;
|
|
110
|
+
}
|
|
111
|
+
.valueMuted {
|
|
112
|
+
color: #888;
|
|
113
|
+
font-style: italic;
|
|
114
|
+
}
|
|
115
|
+
.stack {
|
|
116
|
+
display: flex;
|
|
117
|
+
flex-direction: column;
|
|
118
|
+
gap: 0;
|
|
119
|
+
align-items: flex-end;
|
|
120
|
+
}
|
|
121
|
+
/*# sourceMappingURL=renderer.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/routing/reflection/ToolDebugOverlay.module.css","../src/canvas/PickHud.module.css","../src/canvas/ModalityHud.module.css"],"sourcesContent":["/* src/tools/routing/reflection/ToolDebugOverlay.module.css */\n.overlay {\n position: absolute;\n bottom: 12px;\n right: 12px;\n min-width: 180px;\n padding: 8px 10px;\n background: rgba(20, 20, 24, 0.86);\n color: #eaeaea;\n font: 11px/1.4 ui-monospace, \"SF Mono\", Menlo, monospace;\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n pointer-events: none;\n user-select: none;\n}\n\n.row {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n}\n\n.label {\n color: #888;\n}\n\n.value {\n color: #f5f5f5;\n}\n\n.empty {\n color: #888;\n font-style: italic;\n}\n",".hud {\n position: fixed;\n z-index: 10000;\n background: rgba(0, 0, 0, 0.7);\n color: #e8e8e8;\n font: 11px ui-monospace, SFMono-Regular, Menlo, monospace;\n padding: 6px 8px;\n border-radius: 4px;\n pointer-events: none;\n line-height: 1.4;\n text-align: right;\n min-width: 120px;\n max-width: 260px;\n}\n\n.header {\n color: #888;\n margin-bottom: 2px;\n}\n\n.empty {\n color: #888;\n font-style: italic;\n}\n\n.list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 1px;\n}\n\n.item {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.itemBest {\n font-weight: 700;\n}\n",".hud {\n position: fixed;\n z-index: 10000;\n background: rgba(0, 0, 0, 0.7);\n color: #e8e8e8;\n font: 11px ui-monospace, SFMono-Regular, Menlo, monospace;\n padding: 6px 8px;\n border-radius: 4px;\n pointer-events: none;\n line-height: 1.4;\n text-align: right;\n min-width: 120px;\n max-width: 260px;\n}\n\n.row {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n white-space: nowrap;\n}\n\n.label {\n color: #888;\n}\n\n.value {\n color: #e8e8e8;\n}\n\n.valueMuted {\n color: #888;\n font-style: italic;\n}\n\n.stack {\n display: flex;\n flex-direction: column;\n gap: 0;\n align-items: flex-end;\n}\n"],"mappings":";AACA,CAAC;AACC,YAAU;AACV,UAAQ;AACR,SAAO;AACP,aAAW;AACX,WAAS,IAAI;AACb,cAAY,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;AAC7B,SAAO;AACP;AAAA,IAAM,IAAI,CAAC,IAAI,YAAY;AAAA,IAAE,SAAS;AAAA,IAAE,KAAK;AAAA,IAAE;AAC/C,UAAQ,IAAI,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AACtC,iBAAe;AACf,kBAAgB;AAChB,eAAa;AACf;AAEA,CAAC;AACC,WAAS;AACT,mBAAiB;AACjB,OAAK;AACP;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACP,cAAY;AACd;;;ACjCA,CAAC;AACC,YAAU;AACV,WAAS;AACT,cAAY,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1B,SAAO;AACP;AAAA,IAAM,KAAK,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,KAAK;AAAA,IAAE;AAChD,WAAS,IAAI;AACb,iBAAe;AACf,kBAAgB;AAChB,eAAa;AACb,cAAY;AACZ,aAAW;AACX,aAAW;AACb;AAEA,CAAC;AACC,SAAO;AACP,iBAAe;AACjB;AAEA,CAAC;AACC,SAAO;AACP,cAAY;AACd;AAEA,CAAC;AACC,cAAY;AACZ,UAAQ;AACR,WAAS;AACT,WAAS;AACT,kBAAgB;AAChB,OAAK;AACP;AAEA,CAAC;AACC,eAAa;AACb,YAAU;AACV,iBAAe;AACjB;AAEA,CAAC;AACC,eAAa;AACf;;;AC1CA,CAAC;AACC,YAAU;AACV,WAAS;AACT,cAAY,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1B,SAAO;AACP;AAAA,IAAM,KAAK,YAAY;AAAA,IAAE,cAAc;AAAA,IAAE,KAAK;AAAA,IAAE;AAChD,WAAS,IAAI;AACb,iBAAe;AACf,kBAAgB;AAChB,eAAa;AACb,cAAY;AACZ,aAAW;AACX,aAAW;AACb;AAEA,CAAC;AACC,WAAS;AACT,OAAK;AACL,mBAAiB;AACjB,eAAa;AACf;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACP,cAAY;AACd;AAEA,CAAC;AACC,WAAS;AACT,kBAAgB;AAChB,OAAK;AACL,eAAa;AACf;","names":[]}
|