@jamesyong42/infinite-canvas 1.0.0 → 1.2.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/README.md +170 -9
- package/dist/SelectionRenderer-CR2PBQwx.d.cts +105 -0
- package/dist/SelectionRenderer-CR2PBQwx.d.cts.map +1 -0
- package/dist/SelectionRenderer-DlsBstAq.d.mts +105 -0
- package/dist/SelectionRenderer-DlsBstAq.d.mts.map +1 -0
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs +3560 -0
- package/dist/WebGLWidgetLayer-BBMuwzHq.cjs.map +1 -0
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs +3375 -0
- package/dist/WebGLWidgetLayer-C3p1tnpm.mjs.map +1 -0
- package/dist/advanced.cjs +110 -165
- package/dist/advanced.cjs.map +1 -1
- package/dist/advanced.d.cts +58 -40
- package/dist/advanced.d.cts.map +1 -0
- package/dist/advanced.d.mts +99 -0
- package/dist/advanced.d.mts.map +1 -0
- package/dist/advanced.mjs +105 -0
- package/dist/advanced.mjs.map +1 -0
- package/dist/devtools.cjs +654 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.cts +23 -0
- package/dist/devtools.d.cts.map +1 -0
- package/dist/devtools.d.mts +23 -0
- package/dist/devtools.d.mts.map +1 -0
- package/dist/devtools.mjs +652 -0
- package/dist/devtools.mjs.map +1 -0
- package/dist/engine-BfbvWXSk.d.mts +982 -0
- package/dist/engine-BfbvWXSk.d.mts.map +1 -0
- package/dist/engine-CCjuFMC-.d.cts +982 -0
- package/dist/engine-CCjuFMC-.d.cts.map +1 -0
- package/dist/hooks-BwY7rRHg.mjs +425 -0
- package/dist/hooks-BwY7rRHg.mjs.map +1 -0
- package/dist/hooks-DHShH86C.cjs +707 -0
- package/dist/hooks-DHShH86C.cjs.map +1 -0
- package/dist/index.cjs +909 -803
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +199 -67
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +258 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +855 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +47 -15
- package/dist/SelectionRenderer-CeWSNZT8.d.cts +0 -891
- package/dist/SelectionRenderer-CeWSNZT8.d.ts +0 -891
- package/dist/advanced.d.ts +0 -81
- package/dist/advanced.js +0 -124
- package/dist/advanced.js.map +0 -1
- package/dist/chunk-VSHXWTJH.cjs +0 -3228
- package/dist/chunk-VSHXWTJH.cjs.map +0 -1
- package/dist/chunk-Z6JQQOWL.js +0 -3142
- package/dist/chunk-Z6JQQOWL.js.map +0 -1
- package/dist/index.d.ts +0 -126
- package/dist/index.js +0 -602
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,7 +17,9 @@ Build Figma-style infinite canvases in React -- drag, resize, snap, zoom, nested
|
|
|
17
17
|
- **Undo / redo** -- Command buffer with grouped operations (an entire drag is one undo step)
|
|
18
18
|
- **Hierarchical navigation** -- Enter and exit nested containers with camera state preservation
|
|
19
19
|
- **ECS architecture** -- Extensible via custom components, tags, and systems with topologically-sorted scheduling
|
|
20
|
+
- **Card widgets** -- iOS-style preset-sized tiles (small / medium / large / xl) with rounded corners, soft shadows, and lift-on-drag animation; DOM or R3F/PBR flavors via `createCardWidget` / `createGeometryCardWidget`
|
|
20
21
|
- **Performance** -- SDF shaders for grid and selection chrome, RBush spatial indexing, viewport culling, per-system profiling
|
|
22
|
+
- **Live ECS editor** -- Drop-in `<EcsDevtools>` panel for spawning, inspecting, and editing components and tags at runtime
|
|
21
23
|
- **Dark mode** -- Full dark mode support across canvas, widgets, and UI chrome
|
|
22
24
|
|
|
23
25
|
## Quick Start
|
|
@@ -68,12 +70,13 @@ Widgets declare a **schema** (any [Standard Schema v1](https://standardschema.de
|
|
|
68
70
|
|
|
69
71
|
## Package
|
|
70
72
|
|
|
71
|
-
Everything ships in a single package: **`@jamesyong42/infinite-canvas`**. It exposes
|
|
73
|
+
Everything ships in a single package: **`@jamesyong42/infinite-canvas`**. It exposes three entry points:
|
|
72
74
|
|
|
73
75
|
| Import | Purpose |
|
|
74
76
|
|--------|---------|
|
|
75
77
|
| `@jamesyong42/infinite-canvas` | Main API -- `<InfiniteCanvas>`, `createLayoutEngine`, hooks, built-in components |
|
|
76
78
|
| `@jamesyong42/infinite-canvas/advanced` | WebGL renderers, serialization, profiler, spatial index |
|
|
79
|
+
| `@jamesyong42/infinite-canvas/devtools` | `<EcsDevtools>` live ECS editor (see [Devtools](#devtools)) |
|
|
77
80
|
|
|
78
81
|
The underlying ECS primitives (`defineComponent`, `defineSystem`, `World`, `SystemScheduler`) live in a separate package: [**`@jamesyong42/reactive-ecs`**](https://github.com/jamesyong-42/reactive-ecs).
|
|
79
82
|
|
|
@@ -103,6 +106,11 @@ The underlying ECS primitives (`defineComponent`, `defineSystem`, `World`, `Syst
|
|
|
103
106
|
| `useQuery(...types)` | Entity IDs matching component/tag types |
|
|
104
107
|
| `useTaggedEntities(type)` | All entity IDs with a specific tag |
|
|
105
108
|
| `useResource<T>(type)` | Read an ECS resource reactively |
|
|
109
|
+
| `useAllEntities()` | Every live entity ID (reactive on create/destroy) |
|
|
110
|
+
| `useEntityComponents(entityId)` | `ComponentType[]` currently on an entity |
|
|
111
|
+
| `useEntityTags(entityId)` | `TagType[]` currently on an entity |
|
|
112
|
+
| `useRegisteredComponents()` | Every `ComponentType` the world has observed |
|
|
113
|
+
| `useRegisteredTags()` | Every `TagType` the world has observed |
|
|
106
114
|
| `useLayoutEngine()` | Access the `LayoutEngine` instance from context |
|
|
107
115
|
|
|
108
116
|
### InfiniteCanvas Props
|
|
@@ -208,6 +216,97 @@ Spawning is uniform: `engine.spawn(id, options)`. If `id` matches an archetype,
|
|
|
208
216
|
| `parent` | Parent entity id for nesting. |
|
|
209
217
|
| `rotation` | Initial rotation in radians. |
|
|
210
218
|
|
|
219
|
+
The `interactive` field on `Archetype` accepts a boolean or an object. Pass `{ selectable, draggable, resizable, selectionFrame }` (any subset) when you want finer control. Cards that move, select, but never resize and render their own chrome: `{ selectable: true, draggable: true, resizable: false, selectionFrame: false }`. Omitted keys default to `false`, except `selectionFrame` which follows `selectable` (an entity you can select gets a frame unless you opt out).
|
|
220
|
+
|
|
221
|
+
## Card Widgets
|
|
222
|
+
|
|
223
|
+
**Card widgets** are fixed-size, non-resizable widgets that sit on an iOS-style preset grid. They ship with rounded corners, a soft drop shadow, a hairline ring, and a subtle lift animation while dragging. Use them when you want dashboard-style tiles rather than free-form resizable surfaces.
|
|
224
|
+
|
|
225
|
+
```tsx
|
|
226
|
+
import { createCardWidget } from '@jamesyong42/infinite-canvas';
|
|
227
|
+
import { z } from 'zod';
|
|
228
|
+
|
|
229
|
+
const schema = z.object({ label: z.string().default('Hi') });
|
|
230
|
+
|
|
231
|
+
export const Greeting = createCardWidget<{ label: string }>({
|
|
232
|
+
type: 'greeting-card',
|
|
233
|
+
size: 'small', // 'small' | 'medium' | 'large' | 'xl'
|
|
234
|
+
schema,
|
|
235
|
+
defaultData: { label: 'Hi' },
|
|
236
|
+
render: ({ data }) => (
|
|
237
|
+
<div className="flex h-full w-full items-center justify-center bg-white">
|
|
238
|
+
{data.label}
|
|
239
|
+
</div>
|
|
240
|
+
),
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Register both the widget and the matching archetype.
|
|
244
|
+
const engine = createLayoutEngine({
|
|
245
|
+
widgets: [Greeting.widget],
|
|
246
|
+
archetypes: [Greeting.archetype],
|
|
247
|
+
});
|
|
248
|
+
engine.spawn('greeting-card', { at: { x: 50, y: 50 } });
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Preset sizes (default, matching iOS widget conventions on a 19 px grid):
|
|
252
|
+
|
|
253
|
+
| Preset | Width × Height |
|
|
254
|
+
|--------|----------------|
|
|
255
|
+
| `small` | 155 × 155 |
|
|
256
|
+
| `medium` | 329 × 155 |
|
|
257
|
+
| `large` | 329 × 345 |
|
|
258
|
+
| `xl` | 329 × 535 |
|
|
259
|
+
|
|
260
|
+
Override per-engine via `createLayoutEngine({ cardPresets: { presets: { small: { width: 200, height: 200 } }, gap: 24 } })`. Omitted presets keep their defaults.
|
|
261
|
+
|
|
262
|
+
Under the hood: the returned widget wraps your `render` in `<CardFrame>` (exported for manual composition), the archetype is non-resizable, and it bundles a `Card` component. A built-in `cardSystem` stamps `Transform2D.width/height` from `Card.preset` each tick — to change a card's size at runtime, update the preset: `engine.set(id, Card, { preset: 'large' })`. Reading the `Dragging` tag from the frame drives the lift affordance; you can read it elsewhere too via `useTag(entityId, Dragging)`.
|
|
263
|
+
|
|
264
|
+
Cards also opt out of the engine-drawn selection + hover outline (`selectionFrame: false` in their archetype) — the iOS rounded chrome in `<CardFrame>` is the card's visual contract, so the standard blue frame would fight it. If you need a selected/hover affordance inside a card, read `useIsSelected(entityId)` / `useTag(entityId, /* Hovered tag */)` from within `render` and style accordingly.
|
|
265
|
+
|
|
266
|
+
### 3D Card Widgets
|
|
267
|
+
|
|
268
|
+
`createGeometryCardWidget` is the R3F counterpart — same preset sizes, non-resizable archetype, and drag-lift behavior, but the widget body is a three.js scene instead of DOM content. The helper pairs cleanly with PBR materials.
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
import { createGeometryCardWidget } from '@jamesyong42/infinite-canvas';
|
|
272
|
+
import { useFrame } from '@react-three/fiber';
|
|
273
|
+
import { useRef } from 'react';
|
|
274
|
+
import type { Mesh } from 'three';
|
|
275
|
+
import { z } from 'zod';
|
|
276
|
+
|
|
277
|
+
const schema = z.object({ color: z.string().default('#F5B8D0') });
|
|
278
|
+
|
|
279
|
+
export const Sphere = createGeometryCardWidget<{ color: string }>({
|
|
280
|
+
type: 'sphere',
|
|
281
|
+
size: 'small',
|
|
282
|
+
schema,
|
|
283
|
+
defaultData: { color: '#F5B8D0' },
|
|
284
|
+
background: 'card', // or 'transparent' — the geometry floats over the canvas
|
|
285
|
+
geometry: ({ data, width }) => {
|
|
286
|
+
const ref = useRef<Mesh>(null);
|
|
287
|
+
useFrame((_, dt) => { if (ref.current) ref.current.rotation.y += dt * 0.3; });
|
|
288
|
+
return (
|
|
289
|
+
<group>
|
|
290
|
+
<pointLight position={[80, 80, 120]} intensity={160} distance={300} decay={1.4} />
|
|
291
|
+
<ambientLight intensity={0.3} />
|
|
292
|
+
<mesh ref={ref}>
|
|
293
|
+
<sphereGeometry args={[width * 0.32, 48, 48]} />
|
|
294
|
+
<meshStandardMaterial color={data.color} roughness={0.35} />
|
|
295
|
+
</mesh>
|
|
296
|
+
</group>
|
|
297
|
+
);
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`background` options:
|
|
303
|
+
|
|
304
|
+
- `'card'` (default) — a rounded iOS-style card mesh sits behind the geometry in the same widget group.
|
|
305
|
+
- `'transparent'` — no back plane; the geometry floats over whatever's behind the widget.
|
|
306
|
+
- `{ color, roughness?, metalness? }` — card back with custom PBR parameters for tinted or glossy variants.
|
|
307
|
+
|
|
308
|
+
**Lighting caveat.** All R3F widgets share a single `<Canvas>`, so lights and `envMap`s you declare inside one widget's render function affect every other 3D widget. Keep per-widget lights `pointLight`s with `distance` scoped to the widget's size, or add one shared `<Environment>` at the app level (if you control the R3F canvas). The helper itself adds no lights — declare what you need inside your `geometry` component.
|
|
309
|
+
|
|
211
310
|
## WebGL Widgets (R3F)
|
|
212
311
|
|
|
213
312
|
Define an `R3FWidget<T>` with `surface: 'webgl'` to render 3D content via React Three Fiber. R3F widget views receive `{ entityId, width, height }` and render in local coordinates (origin at widget centre):
|
|
@@ -333,6 +432,42 @@ deserializeWorld(engine.world, saved, componentTypes, tagTypes);
|
|
|
333
432
|
engine.markDirty();
|
|
334
433
|
```
|
|
335
434
|
|
|
435
|
+
## Devtools
|
|
436
|
+
|
|
437
|
+
A live ECS editor ships in `@jamesyong42/infinite-canvas/devtools`. Drop it in during development to spawn widgets, inspect entities, edit components, and toggle tags at runtime — FLECS Explorer-style, but driven by the live React tree.
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import { InfiniteCanvas } from '@jamesyong42/infinite-canvas';
|
|
441
|
+
import { EcsDevtools } from '@jamesyong42/infinite-canvas/devtools';
|
|
442
|
+
|
|
443
|
+
function App() {
|
|
444
|
+
const engine = useMemo(() => createLayoutEngine({ widgets: [MyWidget] }), []);
|
|
445
|
+
const [showDevtools, setShowDevtools] = useState(false);
|
|
446
|
+
|
|
447
|
+
return (
|
|
448
|
+
<>
|
|
449
|
+
<InfiniteCanvas engine={engine} />
|
|
450
|
+
{showDevtools && <EcsDevtools engine={engine} onClose={() => setShowDevtools(false)} />}
|
|
451
|
+
</>
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
What the panel does:
|
|
457
|
+
|
|
458
|
+
- **Spawn** any registered widget at the current viewport centre.
|
|
459
|
+
- **List** all widget entities (or all entities with `show all`).
|
|
460
|
+
- **Inspect** the canvas-selected entity: its components and tags.
|
|
461
|
+
- **Edit** component fields inline — primitive types get typed inputs, everything else falls back to a JSON input. `WidgetData.data` is edited field-by-field.
|
|
462
|
+
- **Add / remove** components and toggle tags without leaving the canvas.
|
|
463
|
+
- **Destroy** entities.
|
|
464
|
+
|
|
465
|
+
Pass `engine` as a prop when the devtools render outside the `<InfiniteCanvas>` subtree (the usual case, since the panel is typically absolute-positioned above the canvas). If rendered inside, the prop is optional — it reads from context.
|
|
466
|
+
|
|
467
|
+
Styling is self-contained (a single scoped `<style>` injected once, classnames prefixed `ic-ecs-`). Dark mode is auto via `prefers-color-scheme` or an ancestor `.dark` class. No stylesheet import required.
|
|
468
|
+
|
|
469
|
+
The devtools consume the same introspection primitives (`useAllEntities`, `useEntityComponents`, `useRegisteredComponents`, etc.) that are exported from the main entry point, so you can build your own inspector UI on top of them if you need something bespoke.
|
|
470
|
+
|
|
336
471
|
## Programmatic Control
|
|
337
472
|
|
|
338
473
|
### Camera
|
|
@@ -353,6 +488,27 @@ engine.redo();
|
|
|
353
488
|
engine.markDirty();
|
|
354
489
|
```
|
|
355
490
|
|
|
491
|
+
### Spawning & ECS mutation
|
|
492
|
+
|
|
493
|
+
Runtime spawning and component edits go through the engine so it can cascade handles and mark dirty in one step:
|
|
494
|
+
|
|
495
|
+
```tsx
|
|
496
|
+
// Spawn at the viewport centre (sized from the widget/archetype default)
|
|
497
|
+
const id = engine.spawnAtCameraCenter('my-widget');
|
|
498
|
+
|
|
499
|
+
// Component mutation
|
|
500
|
+
engine.addComponent(id, Container, { enterable: true });
|
|
501
|
+
engine.removeComponent(id, Container);
|
|
502
|
+
engine.set(id, Transform2D, { x: 200 }); // partial merge
|
|
503
|
+
engine.addTag(id, Selected);
|
|
504
|
+
engine.removeTag(id, Draggable);
|
|
505
|
+
|
|
506
|
+
// Widget-aware introspection
|
|
507
|
+
engine.getSchemaFor(id); // Standard Schema for the widget's data, if declared
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
All of these mark the engine dirty internally — no separate `markDirty` call needed.
|
|
511
|
+
|
|
356
512
|
### Imperative Handle
|
|
357
513
|
|
|
358
514
|
Use a ref on `<InfiniteCanvas>` for imperative control from outside:
|
|
@@ -461,20 +617,25 @@ z:3 UI chrome
|
|
|
461
617
|
| `InteractionRole` | Interaction behavior (drag, select, resize, etc.) |
|
|
462
618
|
| `HandleSet` | Child handle entity references |
|
|
463
619
|
| `CursorHint` | Cursor style on hover/active |
|
|
620
|
+
| `Card` | Marks an iOS-style card; carries the preset (`small`/`medium`/`large`/`xl`) |
|
|
464
621
|
|
|
465
622
|
### ECS Tags
|
|
466
623
|
|
|
467
|
-
`Selectable` `Draggable` `Resizable` `Locked` `Selected` `Active` `Visible`
|
|
624
|
+
`Selectable` `Draggable` `Resizable` `SelectionFrame` `Locked` `Selected` `Dragging` `Active` `Visible`
|
|
625
|
+
|
|
626
|
+
- `Dragging` — transient state tag (parallels `Selected`): added when the drag dead zone is crossed, removed on pointer up or cancel. Read via `useTag(entityId, Dragging)` to drive drag-time affordances.
|
|
627
|
+
- `SelectionFrame` — opts an entity into the engine-drawn selection + hover outline. Granted automatically to Selectable entities via the archetype's `interactive` caps; widgets that render their own chrome (e.g. cards) opt out.
|
|
468
628
|
|
|
469
629
|
### Systems (execution order)
|
|
470
630
|
|
|
471
|
-
1. `
|
|
472
|
-
2. `
|
|
473
|
-
3. `
|
|
474
|
-
4. `
|
|
475
|
-
5. `
|
|
476
|
-
6. `
|
|
477
|
-
7. `
|
|
631
|
+
1. `card` -- Stamp Transform2D size from Card preset
|
|
632
|
+
2. `transformPropagate` -- Propagate transforms down hierarchy, compute WorldBounds
|
|
633
|
+
3. `handleSync` -- Synchronize resize handle entities with parent widgets
|
|
634
|
+
4. `hitboxWorldBounds` -- Compute world-space hitbox bounds
|
|
635
|
+
5. `navigationFilter` -- Filter entities to active navigation layer
|
|
636
|
+
6. `cull` -- Mark viewport-visible entities
|
|
637
|
+
7. `breakpoint` -- Compute responsive breakpoints
|
|
638
|
+
8. `sort` -- Z-index ordering
|
|
478
639
|
|
|
479
640
|
## Performance Profiling
|
|
480
641
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { F as DomWidgetProps, L as R3FWidgetProps, b as EqualSpacingIndicator, n as LayoutEngine, x as SnapGuide } from "./engine-CCjuFMC-.cjs";
|
|
2
|
+
import { EntityId } from "@jamesyong42/reactive-ecs";
|
|
3
|
+
import * as _$react from "react";
|
|
4
|
+
import * as THREE from "three";
|
|
5
|
+
|
|
6
|
+
//#region src/react/context.d.ts
|
|
7
|
+
declare const EngineProvider: _$react.Provider<LayoutEngine | null>;
|
|
8
|
+
declare const ContainerRefProvider: _$react.Provider<_$react.RefObject<HTMLDivElement | null> | null>;
|
|
9
|
+
declare function useContainerRef(): React.RefObject<HTMLDivElement | null> | null;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the LayoutEngine instance from the nearest InfiniteCanvas context.
|
|
12
|
+
* Throws if used outside an InfiniteCanvas provider.
|
|
13
|
+
*/
|
|
14
|
+
declare function useLayoutEngine(): LayoutEngine;
|
|
15
|
+
/**
|
|
16
|
+
* Discriminated resolution of a widget by type. The surface determines which
|
|
17
|
+
* layer renders the component and with what prop shape.
|
|
18
|
+
*/
|
|
19
|
+
type ResolvedWidget = {
|
|
20
|
+
surface: 'dom';
|
|
21
|
+
component: React.ComponentType<DomWidgetProps>;
|
|
22
|
+
} | {
|
|
23
|
+
surface: 'webgl';
|
|
24
|
+
component: React.ComponentType<R3FWidgetProps>;
|
|
25
|
+
};
|
|
26
|
+
type WidgetResolver = (entityId: EntityId, widgetType: string) => ResolvedWidget | null;
|
|
27
|
+
declare const WidgetResolverProvider: _$react.Provider<WidgetResolver | null>;
|
|
28
|
+
declare function useWidgetResolver(): WidgetResolver | null;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/react/webgl/GridRenderer.d.ts
|
|
31
|
+
interface GridConfig {
|
|
32
|
+
/** World-unit spacings for up to 3 grid levels [fine, medium, coarse]. */
|
|
33
|
+
spacings: [number, number, number];
|
|
34
|
+
/** Dot RGB color as [r, g, b] in 0–1 range. */
|
|
35
|
+
dotColor: [number, number, number];
|
|
36
|
+
/** Base dot opacity multiplier (0–1). */
|
|
37
|
+
dotAlpha: number;
|
|
38
|
+
/** CSS-pixel range where a grid level fades in: [start, end]. */
|
|
39
|
+
fadeIn: [number, number];
|
|
40
|
+
/** CSS-pixel range where a grid level fades out: [start, end]. */
|
|
41
|
+
fadeOut: [number, number];
|
|
42
|
+
/** Dot radius range in CSS pixels [min, max]. Scaled by DPR internally. */
|
|
43
|
+
dotRadius: [number, number];
|
|
44
|
+
/** Per-level opacity weight: level i gets (base + i * step). */
|
|
45
|
+
levelWeight: [number, number];
|
|
46
|
+
}
|
|
47
|
+
declare const DEFAULT_GRID_CONFIG: GridConfig;
|
|
48
|
+
declare class GridRenderer {
|
|
49
|
+
private renderer;
|
|
50
|
+
private scene;
|
|
51
|
+
private camera;
|
|
52
|
+
private material;
|
|
53
|
+
private mesh;
|
|
54
|
+
constructor(canvas: HTMLCanvasElement);
|
|
55
|
+
/** Apply a (partial) grid config. Only provided fields are updated. */
|
|
56
|
+
setConfig(config: Partial<GridConfig>): void;
|
|
57
|
+
setSize(width: number, height: number, dpr?: number): void;
|
|
58
|
+
render(cameraX: number, cameraY: number, zoom: number): void;
|
|
59
|
+
dispose(): void;
|
|
60
|
+
/** Expose for future WebGL widget rendering */
|
|
61
|
+
getWebGLRenderer(): THREE.WebGLRenderer;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/react/webgl/SelectionRenderer.d.ts
|
|
65
|
+
interface SelectionConfig {
|
|
66
|
+
/** Selection outline color [r,g,b] 0-1. Default: Figma blue. */
|
|
67
|
+
outlineColor: [number, number, number];
|
|
68
|
+
/** Selection outline width in screen px. */
|
|
69
|
+
outlineWidth: number;
|
|
70
|
+
/** Hover outline color [r,g,b] 0-1. */
|
|
71
|
+
hoverColor: [number, number, number];
|
|
72
|
+
/** Hover outline width in screen px. */
|
|
73
|
+
hoverWidth: number;
|
|
74
|
+
/** Handle size in screen px. */
|
|
75
|
+
handleSize: number;
|
|
76
|
+
/** Handle fill color [r,g,b] 0-1 (white). */
|
|
77
|
+
handleFill: [number, number, number];
|
|
78
|
+
/** Handle border color [r,g,b] 0-1 (same as outline). */
|
|
79
|
+
handleBorder: [number, number, number];
|
|
80
|
+
/** Handle border width in screen px. */
|
|
81
|
+
handleBorderWidth: number;
|
|
82
|
+
/** Group bbox dash length in screen px (0 = solid). */
|
|
83
|
+
groupDash: number;
|
|
84
|
+
}
|
|
85
|
+
declare const DEFAULT_SELECTION_CONFIG: SelectionConfig;
|
|
86
|
+
interface SelectionBounds {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
}
|
|
92
|
+
declare class SelectionRenderer {
|
|
93
|
+
private material;
|
|
94
|
+
private mesh;
|
|
95
|
+
private scene;
|
|
96
|
+
private camera;
|
|
97
|
+
constructor();
|
|
98
|
+
setConfig(config: Partial<SelectionConfig>): void;
|
|
99
|
+
setSize(resolution: THREE.Vector2, dpr: number): void;
|
|
100
|
+
render(renderer: THREE.WebGLRenderer, cameraX: number, cameraY: number, zoom: number, selected: SelectionBounds[], hovered: SelectionBounds | null, guides?: SnapGuide[], spacings?: EqualSpacingIndicator[]): void;
|
|
101
|
+
dispose(): void;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { DEFAULT_GRID_CONFIG as a, ContainerRefProvider as c, WidgetResolverProvider as d, useContainerRef as f, SelectionRenderer as i, EngineProvider as l, useWidgetResolver as m, SelectionBounds as n, GridConfig as o, useLayoutEngine as p, SelectionConfig as r, GridRenderer as s, DEFAULT_SELECTION_CONFIG as t, ResolvedWidget as u };
|
|
105
|
+
//# sourceMappingURL=SelectionRenderer-CR2PBQwx.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionRenderer-CR2PBQwx.d.cts","names":[],"sources":["../src/react/context.ts","../src/react/webgl/GridRenderer.ts","../src/react/webgl/SelectionRenderer.ts"],"mappings":";;;;;;cASa,cAAA,EAAc,OAAA,CAAA,QAAA,CAAA,YAAA;AAAA,cAOd,oBAAA,EAAoB,OAAA,CAAA,QAAA,CAAA,OAAA,CAAA,SAAA,CAAA,cAAA;AAAA,iBAEjB,eAAA,CAAA,GAAmB,KAAA,CAAM,SAAA,CAAU,cAAA;AATnD;;;;AAAA,iBAiBgB,eAAA,CAAA,GAAmB,YAAA;;;;;KAgBvB,cAAA;EACP,OAAA;EAAgB,SAAA,EAAW,KAAA,CAAM,aAAA,CAAc,cAAA;AAAA;EAC/C,OAAA;EAAkB,SAAA,EAAW,KAAA,CAAM,aAAA,CAAc,cAAA;AAAA;AAAA,KAE1C,cAAA,IAAkB,QAAA,EAAU,QAAA,EAAU,UAAA,aAAuB,cAAA;AAAA,cAI5D,sBAAA,EAAsB,OAAA,CAAA,QAAA,CAAA,cAAA;AAAA,iBAEnB,iBAAA,CAAA,GAAqB,cAAA;;;UChDpB,UAAA;;EAEhB,QAAA;;EAEA,QAAA;EDCY;ECCZ,QAAA;;EAEA,MAAA;EDH0B;ECK1B,OAAA;EDE+D;ECA/D,SAAA;EDAgC;ECEhC,WAAA;AAAA;AAAA,cAGY,mBAAA,EAAqB,UAAA;AAAA,cAoFrB,YAAA;EAAA,QACJ,QAAA;EAAA,QACA,KAAA;EAAA,QACA,MAAA;EAAA,QACA,QAAA;EAAA,QACA,IAAA;cAEI,MAAA,EAAQ,iBAAA;ED9FU;EC8I9B,SAAA,CAAU,MAAA,EAAQ,OAAA,CAAQ,UAAA;EAW1B,OAAA,CAAQ,KAAA,UAAe,MAAA,UAAgB,GAAA;EAQvC,MAAA,CAAO,OAAA,UAAiB,OAAA,UAAiB,IAAA;EAOzC,OAAA,CAAA;EDxKkD;EC+KlD,gBAAA,CAAA,GAAoB,KAAA,CAAM,aAAA;AAAA;;;UC3LV,eAAA;;EAEhB,YAAA;;EAEA,YAAA;EFDmD;EEGnD,UAAA;EFH0B;EEK1B,UAAA;EFEY;EEAZ,UAAA;;EAEA,UAAA;EFFgC;EEIhC,YAAA;EFJgC;EEMhC,iBAAA;EFNgC;EEQhC,SAAA;AAAA;AAAA,cAGY,wBAAA,EAA0B,eAAA;AAAA,UActB,eAAA;EAChB,CAAA;EACA,CAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,cAoOY,iBAAA;EAAA,QACJ,QAAA;EAAA,QACA,IAAA;EAAA,QACA,KAAA;EAAA,QACA,MAAA;;EAsDR,SAAA,CAAU,MAAA,EAAQ,OAAA,CAAQ,eAAA;EAc1B,OAAA,CAAQ,UAAA,EAAY,KAAA,CAAM,OAAA,EAAS,GAAA;EAKnC,MAAA,CACC,QAAA,EAAU,KAAA,CAAM,aAAA,EAChB,OAAA,UACA,OAAA,UACA,IAAA,UACA,QAAA,EAAU,eAAA,IACV,OAAA,EAAS,eAAA,SACT,MAAA,GAAQ,SAAA,IACR,QAAA,GAAU,qBAAA;EAiFX,OAAA,CAAA;AAAA"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { F as DomWidgetProps, L as R3FWidgetProps, b as EqualSpacingIndicator, n as LayoutEngine, x as SnapGuide } from "./engine-BfbvWXSk.mjs";
|
|
2
|
+
import { EntityId } from "@jamesyong42/reactive-ecs";
|
|
3
|
+
import * as _$react from "react";
|
|
4
|
+
import * as THREE from "three";
|
|
5
|
+
|
|
6
|
+
//#region src/react/context.d.ts
|
|
7
|
+
declare const EngineProvider: _$react.Provider<LayoutEngine | null>;
|
|
8
|
+
declare const ContainerRefProvider: _$react.Provider<_$react.RefObject<HTMLDivElement | null> | null>;
|
|
9
|
+
declare function useContainerRef(): React.RefObject<HTMLDivElement | null> | null;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the LayoutEngine instance from the nearest InfiniteCanvas context.
|
|
12
|
+
* Throws if used outside an InfiniteCanvas provider.
|
|
13
|
+
*/
|
|
14
|
+
declare function useLayoutEngine(): LayoutEngine;
|
|
15
|
+
/**
|
|
16
|
+
* Discriminated resolution of a widget by type. The surface determines which
|
|
17
|
+
* layer renders the component and with what prop shape.
|
|
18
|
+
*/
|
|
19
|
+
type ResolvedWidget = {
|
|
20
|
+
surface: 'dom';
|
|
21
|
+
component: React.ComponentType<DomWidgetProps>;
|
|
22
|
+
} | {
|
|
23
|
+
surface: 'webgl';
|
|
24
|
+
component: React.ComponentType<R3FWidgetProps>;
|
|
25
|
+
};
|
|
26
|
+
type WidgetResolver = (entityId: EntityId, widgetType: string) => ResolvedWidget | null;
|
|
27
|
+
declare const WidgetResolverProvider: _$react.Provider<WidgetResolver | null>;
|
|
28
|
+
declare function useWidgetResolver(): WidgetResolver | null;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/react/webgl/GridRenderer.d.ts
|
|
31
|
+
interface GridConfig {
|
|
32
|
+
/** World-unit spacings for up to 3 grid levels [fine, medium, coarse]. */
|
|
33
|
+
spacings: [number, number, number];
|
|
34
|
+
/** Dot RGB color as [r, g, b] in 0–1 range. */
|
|
35
|
+
dotColor: [number, number, number];
|
|
36
|
+
/** Base dot opacity multiplier (0–1). */
|
|
37
|
+
dotAlpha: number;
|
|
38
|
+
/** CSS-pixel range where a grid level fades in: [start, end]. */
|
|
39
|
+
fadeIn: [number, number];
|
|
40
|
+
/** CSS-pixel range where a grid level fades out: [start, end]. */
|
|
41
|
+
fadeOut: [number, number];
|
|
42
|
+
/** Dot radius range in CSS pixels [min, max]. Scaled by DPR internally. */
|
|
43
|
+
dotRadius: [number, number];
|
|
44
|
+
/** Per-level opacity weight: level i gets (base + i * step). */
|
|
45
|
+
levelWeight: [number, number];
|
|
46
|
+
}
|
|
47
|
+
declare const DEFAULT_GRID_CONFIG: GridConfig;
|
|
48
|
+
declare class GridRenderer {
|
|
49
|
+
private renderer;
|
|
50
|
+
private scene;
|
|
51
|
+
private camera;
|
|
52
|
+
private material;
|
|
53
|
+
private mesh;
|
|
54
|
+
constructor(canvas: HTMLCanvasElement);
|
|
55
|
+
/** Apply a (partial) grid config. Only provided fields are updated. */
|
|
56
|
+
setConfig(config: Partial<GridConfig>): void;
|
|
57
|
+
setSize(width: number, height: number, dpr?: number): void;
|
|
58
|
+
render(cameraX: number, cameraY: number, zoom: number): void;
|
|
59
|
+
dispose(): void;
|
|
60
|
+
/** Expose for future WebGL widget rendering */
|
|
61
|
+
getWebGLRenderer(): THREE.WebGLRenderer;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/react/webgl/SelectionRenderer.d.ts
|
|
65
|
+
interface SelectionConfig {
|
|
66
|
+
/** Selection outline color [r,g,b] 0-1. Default: Figma blue. */
|
|
67
|
+
outlineColor: [number, number, number];
|
|
68
|
+
/** Selection outline width in screen px. */
|
|
69
|
+
outlineWidth: number;
|
|
70
|
+
/** Hover outline color [r,g,b] 0-1. */
|
|
71
|
+
hoverColor: [number, number, number];
|
|
72
|
+
/** Hover outline width in screen px. */
|
|
73
|
+
hoverWidth: number;
|
|
74
|
+
/** Handle size in screen px. */
|
|
75
|
+
handleSize: number;
|
|
76
|
+
/** Handle fill color [r,g,b] 0-1 (white). */
|
|
77
|
+
handleFill: [number, number, number];
|
|
78
|
+
/** Handle border color [r,g,b] 0-1 (same as outline). */
|
|
79
|
+
handleBorder: [number, number, number];
|
|
80
|
+
/** Handle border width in screen px. */
|
|
81
|
+
handleBorderWidth: number;
|
|
82
|
+
/** Group bbox dash length in screen px (0 = solid). */
|
|
83
|
+
groupDash: number;
|
|
84
|
+
}
|
|
85
|
+
declare const DEFAULT_SELECTION_CONFIG: SelectionConfig;
|
|
86
|
+
interface SelectionBounds {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
width: number;
|
|
90
|
+
height: number;
|
|
91
|
+
}
|
|
92
|
+
declare class SelectionRenderer {
|
|
93
|
+
private material;
|
|
94
|
+
private mesh;
|
|
95
|
+
private scene;
|
|
96
|
+
private camera;
|
|
97
|
+
constructor();
|
|
98
|
+
setConfig(config: Partial<SelectionConfig>): void;
|
|
99
|
+
setSize(resolution: THREE.Vector2, dpr: number): void;
|
|
100
|
+
render(renderer: THREE.WebGLRenderer, cameraX: number, cameraY: number, zoom: number, selected: SelectionBounds[], hovered: SelectionBounds | null, guides?: SnapGuide[], spacings?: EqualSpacingIndicator[]): void;
|
|
101
|
+
dispose(): void;
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { DEFAULT_GRID_CONFIG as a, ContainerRefProvider as c, WidgetResolverProvider as d, useContainerRef as f, SelectionRenderer as i, EngineProvider as l, useWidgetResolver as m, SelectionBounds as n, GridConfig as o, useLayoutEngine as p, SelectionConfig as r, GridRenderer as s, DEFAULT_SELECTION_CONFIG as t, ResolvedWidget as u };
|
|
105
|
+
//# sourceMappingURL=SelectionRenderer-DlsBstAq.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionRenderer-DlsBstAq.d.mts","names":[],"sources":["../src/react/context.ts","../src/react/webgl/GridRenderer.ts","../src/react/webgl/SelectionRenderer.ts"],"mappings":";;;;;;cASa,cAAA,EAAc,OAAA,CAAA,QAAA,CAAA,YAAA;AAAA,cAOd,oBAAA,EAAoB,OAAA,CAAA,QAAA,CAAA,OAAA,CAAA,SAAA,CAAA,cAAA;AAAA,iBAEjB,eAAA,CAAA,GAAmB,KAAA,CAAM,SAAA,CAAU,cAAA;AATnD;;;;AAAA,iBAiBgB,eAAA,CAAA,GAAmB,YAAA;;;;;KAgBvB,cAAA;EACP,OAAA;EAAgB,SAAA,EAAW,KAAA,CAAM,aAAA,CAAc,cAAA;AAAA;EAC/C,OAAA;EAAkB,SAAA,EAAW,KAAA,CAAM,aAAA,CAAc,cAAA;AAAA;AAAA,KAE1C,cAAA,IAAkB,QAAA,EAAU,QAAA,EAAU,UAAA,aAAuB,cAAA;AAAA,cAI5D,sBAAA,EAAsB,OAAA,CAAA,QAAA,CAAA,cAAA;AAAA,iBAEnB,iBAAA,CAAA,GAAqB,cAAA;;;UChDpB,UAAA;;EAEhB,QAAA;;EAEA,QAAA;EDCY;ECCZ,QAAA;;EAEA,MAAA;EDH0B;ECK1B,OAAA;EDE+D;ECA/D,SAAA;EDAgC;ECEhC,WAAA;AAAA;AAAA,cAGY,mBAAA,EAAqB,UAAA;AAAA,cAoFrB,YAAA;EAAA,QACJ,QAAA;EAAA,QACA,KAAA;EAAA,QACA,MAAA;EAAA,QACA,QAAA;EAAA,QACA,IAAA;cAEI,MAAA,EAAQ,iBAAA;ED9FU;EC8I9B,SAAA,CAAU,MAAA,EAAQ,OAAA,CAAQ,UAAA;EAW1B,OAAA,CAAQ,KAAA,UAAe,MAAA,UAAgB,GAAA;EAQvC,MAAA,CAAO,OAAA,UAAiB,OAAA,UAAiB,IAAA;EAOzC,OAAA,CAAA;EDxKkD;EC+KlD,gBAAA,CAAA,GAAoB,KAAA,CAAM,aAAA;AAAA;;;UC3LV,eAAA;;EAEhB,YAAA;;EAEA,YAAA;EFDmD;EEGnD,UAAA;EFH0B;EEK1B,UAAA;EFEY;EEAZ,UAAA;;EAEA,UAAA;EFFgC;EEIhC,YAAA;EFJgC;EEMhC,iBAAA;EFNgC;EEQhC,SAAA;AAAA;AAAA,cAGY,wBAAA,EAA0B,eAAA;AAAA,UActB,eAAA;EAChB,CAAA;EACA,CAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,cAoOY,iBAAA;EAAA,QACJ,QAAA;EAAA,QACA,IAAA;EAAA,QACA,KAAA;EAAA,QACA,MAAA;;EAsDR,SAAA,CAAU,MAAA,EAAQ,OAAA,CAAQ,eAAA;EAc1B,OAAA,CAAQ,UAAA,EAAY,KAAA,CAAM,OAAA,EAAS,GAAA;EAKnC,MAAA,CACC,QAAA,EAAU,KAAA,CAAM,aAAA,EAChB,OAAA,UACA,OAAA,UACA,IAAA,UACA,QAAA,EAAU,eAAA,IACV,OAAA,EAAS,eAAA,SACT,MAAA,GAAQ,SAAA,IACR,QAAA,GAAU,qBAAA;EAiFX,OAAA,CAAA;AAAA"}
|