@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.
Files changed (74) hide show
  1. package/CHANGELOG.md +381 -0
  2. package/LICENSE +21 -0
  3. package/README.md +144 -0
  4. package/dist/DrawCommand-Dl0bXNfS.d.ts +500 -0
  5. package/dist/chunk-775XXAHR.js +216 -0
  6. package/dist/chunk-775XXAHR.js.map +1 -0
  7. package/dist/chunk-7V6JEOXE.js +27754 -0
  8. package/dist/chunk-7V6JEOXE.js.map +1 -0
  9. package/dist/chunk-AM6ARSPN.js +517 -0
  10. package/dist/chunk-AM6ARSPN.js.map +1 -0
  11. package/dist/chunk-BGGZ4CVF.js +248 -0
  12. package/dist/chunk-BGGZ4CVF.js.map +1 -0
  13. package/dist/chunk-BHVYVFGV.js +29 -0
  14. package/dist/chunk-BHVYVFGV.js.map +1 -0
  15. package/dist/chunk-CQNKCG34.js +831 -0
  16. package/dist/chunk-CQNKCG34.js.map +1 -0
  17. package/dist/chunk-GVCNT7UH.js +47 -0
  18. package/dist/chunk-GVCNT7UH.js.map +1 -0
  19. package/dist/chunk-PZ5AY32C.js +9 -0
  20. package/dist/chunk-PZ5AY32C.js.map +1 -0
  21. package/dist/chunk-UGFFCMQP.js +28 -0
  22. package/dist/chunk-UGFFCMQP.js.map +1 -0
  23. package/dist/chunk-VOVKONXA.js +103 -0
  24. package/dist/chunk-VOVKONXA.js.map +1 -0
  25. package/dist/chunk-Y52N27PF.js +39 -0
  26. package/dist/chunk-Y52N27PF.js.map +1 -0
  27. package/dist/clipboard.d.ts +91 -0
  28. package/dist/clipboard.js +6 -0
  29. package/dist/clipboard.js.map +1 -0
  30. package/dist/clone.d.ts +8 -0
  31. package/dist/clone.js +6 -0
  32. package/dist/clone.js.map +1 -0
  33. package/dist/fitViewToBounds-evGsnR8Q.d.ts +62 -0
  34. package/dist/grid-Cf87knjU.d.ts +153 -0
  35. package/dist/index-DZBYMsHI.d.ts +1555 -0
  36. package/dist/index.css +121 -0
  37. package/dist/index.css.map +1 -0
  38. package/dist/index.d.ts +10200 -0
  39. package/dist/index.js +13 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/insert.d.ts +33 -0
  42. package/dist/insert.js +81 -0
  43. package/dist/insert.js.map +1 -0
  44. package/dist/move.d.ts +69 -0
  45. package/dist/move.js +145 -0
  46. package/dist/move.js.map +1 -0
  47. package/dist/options-BPPBWMa7.d.ts +64 -0
  48. package/dist/patterns-builtin.d.ts +55 -0
  49. package/dist/patterns-builtin.js +100 -0
  50. package/dist/patterns-builtin.js.map +1 -0
  51. package/dist/pointSnapToGrid-D7s7QmOF.d.ts +185 -0
  52. package/dist/registerFont-CP-wCsrz.d.ts +109 -0
  53. package/dist/registerTexture-BzHTLhD9.d.ts +25 -0
  54. package/dist/renderer.css +121 -0
  55. package/dist/renderer.css.map +1 -0
  56. package/dist/renderer.d.ts +376 -0
  57. package/dist/renderer.js +13 -0
  58. package/dist/renderer.js.map +1 -0
  59. package/dist/resize.d.ts +78 -0
  60. package/dist/resize.js +5 -0
  61. package/dist/resize.js.map +1 -0
  62. package/dist/routing.css +35 -0
  63. package/dist/routing.css.map +1 -0
  64. package/dist/routing.d.ts +14 -0
  65. package/dist/routing.js +4 -0
  66. package/dist/routing.js.map +1 -0
  67. package/dist/types-B6MMiodD.d.ts +59 -0
  68. package/dist/types-BJ8_cyT7.d.ts +130 -0
  69. package/dist/types-B_-khFM0.d.ts +331 -0
  70. package/dist/types-BjUi2vA-.d.ts +355 -0
  71. package/dist/types-Cpb4hii1.d.ts +445 -0
  72. package/dist/types-D2tTKEU0.d.ts +18 -0
  73. package/dist/view-DSQgxBJB.d.ts +63 -0
  74. 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":[]}