@vibecook/ice 0.1.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/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/chunk-5S7GSXJG.js +6003 -0
- package/dist/chunk-5S7GSXJG.js.map +1 -0
- package/dist/chunk-BCJ47SX7.js +550 -0
- package/dist/chunk-BCJ47SX7.js.map +1 -0
- package/dist/chunk-FIAXPNNY.js +1446 -0
- package/dist/chunk-FIAXPNNY.js.map +1 -0
- package/dist/devtools.js +417 -0
- package/dist/devtools.js.map +1 -0
- package/dist/dom.js +41 -0
- package/dist/dom.js.map +1 -0
- package/dist/index.js +450 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel.js +63 -0
- package/dist/kernel.js.map +1 -0
- package/dist/r3f.js +1101 -0
- package/dist/r3f.js.map +1 -0
- package/dist/react.js +440 -0
- package/dist/react.js.map +1 -0
- package/dist/types/packages/core/src/boot/hmr.d.ts +12 -0
- package/dist/types/packages/core/src/catalog/camera-derived.d.ts +144 -0
- package/dist/types/packages/core/src/catalog/gesture.d.ts +254 -0
- package/dist/types/packages/core/src/catalog/graph.d.ts +55 -0
- package/dist/types/packages/core/src/catalog/index.d.ts +32 -0
- package/dist/types/packages/core/src/catalog/pointer.d.ts +111 -0
- package/dist/types/packages/core/src/catalog/scene.d.ts +34 -0
- package/dist/types/packages/core/src/catalog/selection-presence.d.ts +53 -0
- package/dist/types/packages/core/src/catalog/settings-resources.d.ts +46 -0
- package/dist/types/packages/core/src/doc/autosave.d.ts +69 -0
- package/dist/types/packages/core/src/doc/bootstrap.d.ts +74 -0
- package/dist/types/packages/core/src/doc/broadcast-relay.d.ts +52 -0
- package/dist/types/packages/core/src/doc/channels.d.ts +49 -0
- package/dist/types/packages/core/src/doc/doc-commit-sink.d.ts +22 -0
- package/dist/types/packages/core/src/doc/doc-kit.d.ts +50 -0
- package/dist/types/packages/core/src/doc/envelope.d.ts +36 -0
- package/dist/types/packages/core/src/doc/migrate.d.ts +69 -0
- package/dist/types/packages/core/src/doc/version-gate.d.ts +49 -0
- package/dist/types/packages/core/src/engine/commit-sink.d.ts +61 -0
- package/dist/types/packages/core/src/engine/engine.d.ts +62 -0
- package/dist/types/packages/core/src/engine/frame-info.d.ts +16 -0
- package/dist/types/packages/core/src/engine/instantiate.d.ts +45 -0
- package/dist/types/packages/core/src/engine/pipeline.d.ts +17 -0
- package/dist/types/packages/core/src/engine/reflectors.d.ts +56 -0
- package/dist/types/packages/core/src/facade/create-canvas-engine.d.ts +120 -0
- package/dist/types/packages/core/src/guards/dev.d.ts +2 -0
- package/dist/types/packages/core/src/guards/guarded-tx.d.ts +51 -0
- package/dist/types/packages/core/src/guards/live-writer.d.ts +33 -0
- package/dist/types/packages/core/src/guards/resource-writer.d.ts +17 -0
- package/dist/types/packages/core/src/helpers/phase-set.d.ts +70 -0
- package/dist/types/packages/core/src/helpers/version-stamps.d.ts +55 -0
- package/dist/types/packages/core/src/index.d.ts +63 -0
- package/dist/types/packages/core/src/input/measure-queue.d.ts +30 -0
- package/dist/types/packages/core/src/input/queue.d.ts +60 -0
- package/dist/types/packages/core/src/interaction/install.d.ts +58 -0
- package/dist/types/packages/core/src/nav/nested-canvas.d.ts +62 -0
- package/dist/types/packages/core/src/ops/cascade.d.ts +18 -0
- package/dist/types/packages/core/src/ops/claims.d.ts +15 -0
- package/dist/types/packages/core/src/ops/gestures.d.ts +10 -0
- package/dist/types/packages/core/src/ops/point-pick.d.ts +42 -0
- package/dist/types/packages/core/src/ops/port-geometry.d.ts +17 -0
- package/dist/types/packages/core/src/ops/selection.d.ts +14 -0
- package/dist/types/packages/core/src/presence/index.d.ts +7 -0
- package/dist/types/packages/core/src/presence/presence-kit.d.ts +39 -0
- package/dist/types/packages/core/src/presence/publish.d.ts +14 -0
- package/dist/types/packages/core/src/presence/remote-cursors.d.ts +18 -0
- package/dist/types/packages/core/src/schema/meta.d.ts +43 -0
- package/dist/types/packages/core/src/schema/prefab.d.ts +69 -0
- package/dist/types/packages/core/src/settings/defaults.d.ts +56 -0
- package/dist/types/packages/core/src/systems/camera-sim.d.ts +19 -0
- package/dist/types/packages/core/src/systems/chrome.d.ts +48 -0
- package/dist/types/packages/core/src/systems/cleanup.d.ts +19 -0
- package/dist/types/packages/core/src/systems/l0-input.d.ts +31 -0
- package/dist/types/packages/core/src/systems/l1-pick.d.ts +44 -0
- package/dist/types/packages/core/src/systems/l1-wires.d.ts +30 -0
- package/dist/types/packages/core/src/systems/l2-arbitrate.d.ts +40 -0
- package/dist/types/packages/core/src/systems/l2-recognize.d.ts +45 -0
- package/dist/types/packages/core/src/systems/l3-behave.d.ts +24 -0
- package/dist/types/packages/core/src/systems/l3-claim.d.ts +26 -0
- package/dist/types/packages/core/src/systems/l3-connect.d.ts +57 -0
- package/dist/types/packages/core/src/systems/l3-draw.d.ts +21 -0
- package/dist/types/packages/core/src/systems/l3-drop.d.ts +21 -0
- package/dist/types/packages/core/src/systems/l3-marquee.d.ts +35 -0
- package/dist/types/packages/core/src/systems/l3-ports.d.ts +30 -0
- package/dist/types/packages/core/src/systems/l3-resize.d.ts +17 -0
- package/dist/types/packages/core/src/systems/l3-snap.d.ts +19 -0
- package/dist/types/packages/core/src/systems/l4-cursor.d.ts +24 -0
- package/dist/types/packages/core/src/systems/measure-ingest.d.ts +26 -0
- package/dist/types/packages/core/src/tools/define-tool.d.ts +79 -0
- package/dist/types/packages/core/src/widget/define-widget.d.ts +124 -0
- package/dist/types/packages/core/src/widget/equip.d.ts +14 -0
- package/dist/types/packages/core/src/widget/mount-store.d.ts +47 -0
- package/dist/types/packages/core/src/widget/props.d.ts +98 -0
- package/dist/types/packages/core/src/widget/spawn.d.ts +30 -0
- package/dist/types/packages/devtools/src/index.d.ts +8 -0
- package/dist/types/packages/devtools/src/panel.d.ts +48 -0
- package/dist/types/packages/dom/src/host.d.ts +24 -0
- package/dist/types/packages/dom/src/index.d.ts +19 -0
- package/dist/types/packages/dom/src/loop.d.ts +11 -0
- package/dist/types/packages/dom/src/measure-adapter.d.ts +31 -0
- package/dist/types/packages/dom/src/measure-wiring.d.ts +49 -0
- package/dist/types/packages/dom/src/planes.d.ts +33 -0
- package/dist/types/packages/dom/src/pointer-adapter.d.ts +48 -0
- package/dist/types/packages/dom/src/reflectors/chrome.d.ts +33 -0
- package/dist/types/packages/dom/src/reflectors/cursor.d.ts +21 -0
- package/dist/types/packages/dom/src/reflectors/dom-widgets.d.ts +54 -0
- package/dist/types/packages/dom/src/reflectors/graybox.d.ts +31 -0
- package/dist/types/packages/dom/src/reflectors/grid.d.ts +63 -0
- package/dist/types/packages/dom/src/reflectors/plane-transform.d.ts +38 -0
- package/dist/types/packages/dom/src/reflectors/remote-cursors.d.ts +20 -0
- package/dist/types/packages/dom/src/reflectors/wires.d.ts +88 -0
- package/dist/types/packages/ice/src/devtools.d.ts +1 -0
- package/dist/types/packages/ice/src/dom.d.ts +1 -0
- package/dist/types/packages/ice/src/index.d.ts +1 -0
- package/dist/types/packages/ice/src/kernel.d.ts +1 -0
- package/dist/types/packages/ice/src/r3f.d.ts +1 -0
- package/dist/types/packages/ice/src/react.d.ts +1 -0
- package/dist/types/packages/kernel/src/anchors.d.ts +18 -0
- package/dist/types/packages/kernel/src/bezier.d.ts +38 -0
- package/dist/types/packages/kernel/src/coords.d.ts +67 -0
- package/dist/types/packages/kernel/src/eviction.d.ts +23 -0
- package/dist/types/packages/kernel/src/index.d.ts +13 -0
- package/dist/types/packages/kernel/src/shapes.d.ts +22 -0
- package/dist/types/packages/kernel/src/snap.d.ts +44 -0
- package/dist/types/packages/kernel/src/spatial-index.d.ts +16 -0
- package/dist/types/packages/kernel/src/zoom-bands.d.ts +19 -0
- package/dist/types/packages/r3f/src/bridge.d.ts +68 -0
- package/dist/types/packages/r3f/src/composite-material.d.ts +17 -0
- package/dist/types/packages/r3f/src/compositor-pass.d.ts +83 -0
- package/dist/types/packages/r3f/src/dev-write-trap.d.ts +30 -0
- package/dist/types/packages/r3f/src/gl-root.d.ts +21 -0
- package/dist/types/packages/r3f/src/gl-router.d.ts +60 -0
- package/dist/types/packages/r3f/src/index.d.ts +16 -0
- package/dist/types/packages/r3f/src/island-state.d.ts +68 -0
- package/dist/types/packages/r3f/src/island.d.ts +13 -0
- package/dist/types/packages/r3f/src/pool.d.ts +56 -0
- package/dist/types/packages/r3f/src/resource-registry.d.ts +30 -0
- package/dist/types/packages/r3f/src/use-island-frame.d.ts +24 -0
- package/dist/types/packages/react/src/engine-context.d.ts +31 -0
- package/dist/types/packages/react/src/hooks.d.ts +40 -0
- package/dist/types/packages/react/src/index.d.ts +14 -0
- package/dist/types/packages/react/src/infinite-canvas.d.ts +71 -0
- package/dist/types/packages/react/src/keymap.d.ts +42 -0
- package/dist/types/packages/react/src/use-commit.d.ts +35 -0
- package/dist/types/packages/react/src/use-presence.d.ts +23 -0
- package/dist/types/packages/react/src/use-tool.d.ts +4 -0
- package/dist/types/packages/react/src/widget-root.d.ts +33 -0
- package/package.json +112 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The real L0 pointer adapter (design-003 §2–§3; replaces the M3 demo-input scaffold).
|
|
3
|
+
*
|
|
4
|
+
* Translates DOM pointer / wheel / keyboard events into normalized `InputEvent`s
|
|
5
|
+
* and ONLY enqueues them (Law 2: adapters enqueue, they never touch the world —
|
|
6
|
+
* this file imports no ECS state and writes nothing). `pointerIngest` drains the
|
|
7
|
+
* queue once per tick and turns the facts into world state.
|
|
8
|
+
*
|
|
9
|
+
* Details that matter:
|
|
10
|
+
* - stable pointer ids: `"mouse"` for the one mouse, `"touch:<pointerId>"` per
|
|
11
|
+
* contact, `"pen"` — ingest keys pointer entities off these (design-003 §2);
|
|
12
|
+
* - container-relative CSS px (the kernel screen space) via getBoundingClientRect;
|
|
13
|
+
* - `setPointerCapture` on down so a drag keeps delivering outside the element;
|
|
14
|
+
* - Space is the pan modifier (design-003 §4.4): tracked here and threaded onto
|
|
15
|
+
* every event's `mods.space`; keydown/keyup emit a `key` fact only when the
|
|
16
|
+
* modifier tuple actually changes, and Space `preventDefault`s to stop page scroll;
|
|
17
|
+
* - wheel `preventDefault`s: a ctrl-wheel / trackpad pinch becomes `wheel.pinch`
|
|
18
|
+
* (the zoom signal), a plain wheel becomes dx/dy (deltaMode lines → px ×16);
|
|
19
|
+
* - window blur enqueues a synthetic `cancel` for every pointer still down
|
|
20
|
+
* (design-003 §8) — the browser will not send the pointerups.
|
|
21
|
+
*
|
|
22
|
+
* Widget opt-out (the pinned widget-event contract, design-002 §8 / design-004 §4):
|
|
23
|
+
* on `pointerdown` ONLY, if the event's target chain (up to the container) crosses
|
|
24
|
+
* a native interactive (input/textarea/select/button/a[href]/contenteditable/
|
|
25
|
+
* media[controls]) or an explicit `[data-canvas-interactive]`, the down fact is
|
|
26
|
+
* flagged `surfaceHandled: true` — the fact still lands (the one input path is
|
|
27
|
+
* absolute), but recognizer-spawn/arbitration skip it (`HandledByWidget` flows
|
|
28
|
+
* through L0). `stopPropagation()` inside widget content is the OTHER boundary:
|
|
29
|
+
* a stopped event never reaches the container listener, so it never becomes a
|
|
30
|
+
* canvas fact at all — that is the design, not a gap.
|
|
31
|
+
*/
|
|
32
|
+
import { type InputQueue } from "@ice/core";
|
|
33
|
+
import type { CanvasHost } from "./host";
|
|
34
|
+
/**
|
|
35
|
+
* The router GL path's adapter seam (design-004 §4). The GL plane is
|
|
36
|
+
* `pointer-events: none` — its events land HERE, and the injected router
|
|
37
|
+
* (built by @ice/r3f; the adapter stays ECS-free) performs the synchronous
|
|
38
|
+
* point-pick + island raycast + synthetic dispatch at event time. Returning
|
|
39
|
+
* `true` means island content claimed the event (stopPropagation'd or held
|
|
40
|
+
* under island capture): the fact still lands — flagged `surfaceHandled`, so
|
|
41
|
+
* recognizers skip it via `HandledByWidget` — the same contract as the
|
|
42
|
+
* native-interactive opt-out.
|
|
43
|
+
*/
|
|
44
|
+
export type GLRoute = (kind: "down" | "move" | "up" | "cancel", screenX: number, screenY: number, native: PointerEvent) => boolean;
|
|
45
|
+
export interface PointerAdapterOpts {
|
|
46
|
+
readonly glRoute?: GLRoute;
|
|
47
|
+
}
|
|
48
|
+
export declare function attachPointerAdapter(host: CanvasHost, queue: InputQueue, opts?: PointerAdapterOpts): () => void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The chrome reflector (design-004 §5 chrome plane P4; post-notify, SCREEN-space).
|
|
3
|
+
*
|
|
4
|
+
* Draws the engine's pooled chrome entities plus the out-of-ECS marquee buffer
|
|
5
|
+
* into a dedicated, non-transformed overlay plane above the content plane:
|
|
6
|
+
* - each `SelectionBox` entity → a 1px outline rect (its world x,y,w,h mapped to
|
|
7
|
+
* screen via `worldToScreen` × zoom);
|
|
8
|
+
* - each `HandleSpec` entity → an 8×8 screen-px square CENTERED on the handle's
|
|
9
|
+
* world AABB center (the handle's world size is zoom-scaled for picking; the
|
|
10
|
+
* drawn size is screen-constant);
|
|
11
|
+
* - the `marqueeBuffer.rect` (world) → a rect while non-null.
|
|
12
|
+
*
|
|
13
|
+
* P4 is screen-space by design (design-004 §2 rescope): unlike the content plane
|
|
14
|
+
* (one camera transform), chrome is recomputed per camera change — small N. This
|
|
15
|
+
* reflector therefore reads the `Camera` resource directly (an acknowledged
|
|
16
|
+
* small-N screen-space camera consumer).
|
|
17
|
+
*
|
|
18
|
+
* `always: true`, not observer-driven: the marquee buffer has no ECS stamp to
|
|
19
|
+
* observe, so the reflector must get a chance every frame. A cheap early-out
|
|
20
|
+
* keeps it idle-free — it returns immediately when there is nothing to draw AND
|
|
21
|
+
* nothing was drawn last frame (so a cleared selection still gets one flush to
|
|
22
|
+
* remove its nodes). Style writes are change-only (per-node geometry cache) and
|
|
23
|
+
* counted by `writes()` — the churn instrument, mirroring the other reflectors.
|
|
24
|
+
*
|
|
25
|
+
* Law 10: reflectors write output only, never read layout or write ECS — this
|
|
26
|
+
* flush touches only the overlay plane's node styles.
|
|
27
|
+
*/
|
|
28
|
+
import { type MarqueeBuffer, type ReflectorDef, type World } from "@ice/core";
|
|
29
|
+
import type { CanvasHost } from "../host";
|
|
30
|
+
export declare function createChromeReflector(host: CanvasHost, _world: World, marqueeBuffer: MarqueeBuffer): ReflectorDef & {
|
|
31
|
+
writes(): number;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cursor reflector (design-003 §7 L4 cursor projection; v1 approach:
|
|
3
|
+
* local cursor = OS cursor via one `style.cursor` write).
|
|
4
|
+
*
|
|
5
|
+
* `createCursorSync` resolves the cursor string into closure state every
|
|
6
|
+
* `derive` tick with no observable ECS stamp (a plain string, not a
|
|
7
|
+
* component/resource write), so there is nothing for `observe` to watch —
|
|
8
|
+
* hence `always: true` with an internal last-value cache, mirroring the
|
|
9
|
+
* "cheap-overlay style" carve-out `ReflectorDef.always` exists for. The cache
|
|
10
|
+
* is what keeps the write ONE-per-change: `flush` runs every frame, but
|
|
11
|
+
* `host.container.style.cursor` is only touched when `readCursor()` differs
|
|
12
|
+
* from the last-applied value.
|
|
13
|
+
*
|
|
14
|
+
* Law 10: reflectors run post-notify, write output only, never read layout
|
|
15
|
+
* or write ECS — this flush touches only `host.container.style`.
|
|
16
|
+
*/
|
|
17
|
+
import type { ReflectorDef } from "@ice/core";
|
|
18
|
+
import type { CanvasHost } from "../host";
|
|
19
|
+
export declare function createCursorReflector(host: CanvasHost, readCursor: () => string): ReflectorDef & {
|
|
20
|
+
writes(): number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The DOM widget HOST reflector (design-004 §2 host pipeline; design-002 §5
|
|
3
|
+
* `domWidgets`).
|
|
4
|
+
*
|
|
5
|
+
* This is the reflector-owned HALF of the widget runtime: it reconciles a host
|
|
6
|
+
* `<div>` per mounted widget against the engine's mount store and paints its
|
|
7
|
+
* world-unit geometry. The OTHER half — the React portal list — is owned by a
|
|
8
|
+
* hook subscribed to the SAME store (design-004 §2, decision 3); this file never
|
|
9
|
+
* touches React. Each host carries an inner `data-ice-content` element that the
|
|
10
|
+
* portal targets, so the two halves meet only at that node.
|
|
11
|
+
*
|
|
12
|
+
* Store, not query: membership (enter/exit) and the culled-but-kept-mounted
|
|
13
|
+
* `hidden` flag are ENGINE-side decisions (cull + keep-mounted LRU, mount-store.ts)
|
|
14
|
+
* published through a `useSyncExternalStore` snapshot. That store has NO ECS stamp
|
|
15
|
+
* for a reflector `observe` to watch, so — like the cursor reflector — this one is
|
|
16
|
+
* `always: true` and does its own cheap dirt detection:
|
|
17
|
+
* - **membership**: `store.getSnapshot()` identity is O(1); the snapshot changes
|
|
18
|
+
* IFF membership or a hidden flag changed, so an unchanged snapshot skips the
|
|
19
|
+
* reconcile entirely;
|
|
20
|
+
* - **geometry**: a private observer on `[Position, Size]` sets a dirty flag, so
|
|
21
|
+
* the (change-only) geometry pass runs only when a widget actually moved/resized
|
|
22
|
+
* — a still scene touches no DOM. Effective size is `MeasuredSize` where present
|
|
23
|
+
* and non-zero, else `Size` (design-004 §2). (MeasuredSize changes ride a
|
|
24
|
+
* dedicated observer; the note below is historical:
|
|
25
|
+
* picked up on the next Position/Size stamp or membership change; the ResizeObserver
|
|
26
|
+
* measurement path — a later slice — will arm its own dirt.)
|
|
27
|
+
* - **drag-promote** (P3): a private observer on `[Grab]` membership sets a dirty
|
|
28
|
+
* flag; a host whose entity holds `Grab` re-parents content→lifted plane and back
|
|
29
|
+
* on release. Re-parenting MOVES the host node (with its content child), which
|
|
30
|
+
* PRESERVES the React portal — the portal targets the content node, and moving a
|
|
31
|
+
* portal's container node does not remount it, so widget React state survives the
|
|
32
|
+
* lift. While ANY host is lifted, every host's content element is inerted
|
|
33
|
+
* (`pointer-events: none`, the pinned inert-during-drag contract, design-004 §4).
|
|
34
|
+
*
|
|
35
|
+
* Law 10: reflectors run post-notify, write output only, never read layout or
|
|
36
|
+
* write ECS — this flush touches only host `<div>` style/attributes/parentage.
|
|
37
|
+
*/
|
|
38
|
+
import { type Entity, type ReflectorDef, type WidgetMountStore, type World } from "@ice/core";
|
|
39
|
+
/** The two planes a host can live in (design-004 §1: P1 content, P3 lifted). */
|
|
40
|
+
export interface DomWidgetsHost {
|
|
41
|
+
readonly contentPlane: HTMLElement;
|
|
42
|
+
readonly liftedPlane: HTMLElement;
|
|
43
|
+
}
|
|
44
|
+
export interface DomWidgetsReflector extends ReflectorDef {
|
|
45
|
+
/** The entity's content element (the `data-ice-content` portal target), or undefined if not hosted. */
|
|
46
|
+
hostFor(entity: Entity): HTMLElement | undefined;
|
|
47
|
+
/** Live host count (= mounted widgets, visible + kept-mounted). */
|
|
48
|
+
hostCount(): number;
|
|
49
|
+
/** Geometry writes so far — one per enter, one per changed host, zero for unchanged (churn instrument). */
|
|
50
|
+
geometryWrites(): number;
|
|
51
|
+
/** Tear down the private observers (call when unregistering the reflector before the world dies). */
|
|
52
|
+
dispose(): void;
|
|
53
|
+
}
|
|
54
|
+
export declare function createDomWidgetsReflector(host: DomWidgetsHost, world: World, store: WidgetMountStore): DomWidgetsReflector;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gray-box reflector (design-002 §5 reflector doctrine; M3 exit gate).
|
|
3
|
+
*
|
|
4
|
+
* A minimal enter/update/exit reconciler: it mirrors every `Position` + `Size`
|
|
5
|
+
* entity to an absolutely-positioned div inside the content plane, laying each
|
|
6
|
+
* out in WORLD units (`left/top/width/height` in world coordinates) — the
|
|
7
|
+
* plane's single camera transform (see plane-transform.ts) does the screen
|
|
8
|
+
* mapping, so this reflector never touches the camera and never reads layout
|
|
9
|
+
* (Law 10). It is the stand-in for real widget rendering until the widget
|
|
10
|
+
* runtime lands (M4+); "gray box" = deterministic per-entity fill, no content.
|
|
11
|
+
*
|
|
12
|
+
* Reconciliation, dirty-driven on the `Position`/`Size` query (design-002 §5):
|
|
13
|
+
* - enter: create a div (fill hashed from the entity handle), write geometry,
|
|
14
|
+
* stage it in a DocumentFragment (one plane append per flush — 10k mounts do
|
|
15
|
+
* not thrash layout);
|
|
16
|
+
* - update: compare against a per-entity geometry cache and rewrite ONLY the
|
|
17
|
+
* entities whose world geometry actually changed;
|
|
18
|
+
* - exit: remove divs for entities absent from this flush.
|
|
19
|
+
*
|
|
20
|
+
* `styleWrites()` counts entities whose geometry was (re)written this flush (one
|
|
21
|
+
* per enter, one per changed entity, zero for unchanged) — the churn instrument
|
|
22
|
+
* the M3 tests assert: change one entity ⇒ exactly one style write. `nodeCount()`
|
|
23
|
+
* is the live div count. Because the reflector is dirty-driven, a static frame
|
|
24
|
+
* does not flush at all, so neither counter moves.
|
|
25
|
+
*/
|
|
26
|
+
import { type ReflectorDef } from "@ice/core";
|
|
27
|
+
import type { CanvasHost } from "../host";
|
|
28
|
+
export declare function createGrayboxReflector(host: CanvasHost): ReflectorDef & {
|
|
29
|
+
styleWrites(): number;
|
|
30
|
+
nodeCount(): number;
|
|
31
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The grid reflector (design-004 §1 P0 ground plane; M6).
|
|
3
|
+
*
|
|
4
|
+
* Ports v1's dot-grid shader VERBATIM from
|
|
5
|
+
* `../../../infinite-canvas/packages/infinite-canvas/src/webgl/renderers/GridRenderer.ts`:
|
|
6
|
+
* the fragment shader body (world reconstruction from `gl_FragCoord`, three
|
|
7
|
+
* fade-staged spacing levels, max-composited anti-aliased dots) is copied
|
|
8
|
+
* unchanged from GridRenderer.ts:45-115, and `DEFAULT_GRID_CONFIG` from
|
|
9
|
+
* GridRenderer.ts:27-35. v1 drove this through three.js (`ShaderMaterial` +
|
|
10
|
+
* `WebGLRenderer`), but `@ice/dom` may not import three (the `dom-only-core-
|
|
11
|
+
* kernel` cruiser rule: core + kernel only) — so this reflector talks to a raw
|
|
12
|
+
* WebGL2/WebGL1 context directly. Same GLSL, same uniforms, same math; only the
|
|
13
|
+
* plumbing that fed them (three's abstractions) is gone. The vertex shader is
|
|
14
|
+
* simplified from a vec3 attribute (three's default) to vec2 — geometry only,
|
|
15
|
+
* no shading logic, so "verbatim" is unaffected.
|
|
16
|
+
*
|
|
17
|
+
* P0 is a WebGL `<canvas>` mounted as the FIRST child of the host container
|
|
18
|
+
* (design-004 §1: "ground" sits under P1's content-DOM). It is sized to the
|
|
19
|
+
* container's CSS box × devicePixelRatio via a ResizeObserver — its own,
|
|
20
|
+
* independent hit-path; the reflector's `flush` never reads layout (Law 10),
|
|
21
|
+
* only the RO callback does, and only in response to the browser's own resize
|
|
22
|
+
* notification. Camera uniforms (world top-left + zoom) come from the `Camera`
|
|
23
|
+
* RESOURCE, mirroring plane-transform.ts's `observe` pattern; unlike P1's
|
|
24
|
+
* single CSS transform, this plane recomputes per-pixel in the shader — the
|
|
25
|
+
* world is regenerated from `gl_FragCoord` every draw, so there are no seams
|
|
26
|
+
* at any zoom/pan.
|
|
27
|
+
*
|
|
28
|
+
* Fault isolation, locally too: `getContext` returns `null` in headless/happy-
|
|
29
|
+
* dom (jsdom/happy-dom implement `<canvas>` but not WebGL) — `available()`
|
|
30
|
+
* reports that, and `flush()` is a permanent, silent no-op. GL setup and every
|
|
31
|
+
* draw call are wrapped so a driver/context-loss failure degrades to
|
|
32
|
+
* `available() === false` rather than a throwing reflector (the registry has
|
|
33
|
+
* its own fault isolation — a skipped frame on throw — but a reflector that
|
|
34
|
+
* throws every single frame is still noise, design-002 §5).
|
|
35
|
+
*/
|
|
36
|
+
import { type ReflectorDef } from "@ice/core";
|
|
37
|
+
export interface GridConfig {
|
|
38
|
+
/** World-unit spacings for up to 3 grid levels [fine, medium, coarse]. */
|
|
39
|
+
spacings: [number, number, number];
|
|
40
|
+
/** Dot RGB color as [r, g, b] in 0-1 range. */
|
|
41
|
+
dotColor: [number, number, number];
|
|
42
|
+
/** Base dot opacity multiplier (0-1). */
|
|
43
|
+
dotAlpha: number;
|
|
44
|
+
/** CSS-pixel range where a grid level fades in: [start, end]. */
|
|
45
|
+
fadeIn: [number, number];
|
|
46
|
+
/** CSS-pixel range where a grid level fades out: [start, end]. */
|
|
47
|
+
fadeOut: [number, number];
|
|
48
|
+
/** Dot radius range in CSS pixels [min, max]. Scaled by DPR internally. */
|
|
49
|
+
dotRadius: [number, number];
|
|
50
|
+
/** Per-level opacity weight: level i gets (base + i * step). */
|
|
51
|
+
levelWeight: [number, number];
|
|
52
|
+
}
|
|
53
|
+
/** Verbatim from GridRenderer.ts:27-35 (tuned to match Apple Freeform / FigJam). */
|
|
54
|
+
export declare const DEFAULT_GRID_CONFIG: GridConfig;
|
|
55
|
+
interface GridHost {
|
|
56
|
+
readonly container: HTMLElement;
|
|
57
|
+
}
|
|
58
|
+
export declare function createGridReflector(host: GridHost, opts?: Partial<GridConfig>): ReflectorDef & {
|
|
59
|
+
available(): boolean;
|
|
60
|
+
dispose(): void;
|
|
61
|
+
configure(next: Partial<GridConfig>): void;
|
|
62
|
+
};
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plane-transform reflector (design-002 §5 `planeTransform`; M3 exit gate,
|
|
3
|
+
* widened for the M6 lifted plane).
|
|
4
|
+
*
|
|
5
|
+
* Observes the `Camera` RESOURCE and nothing else. Each flush reads the camera,
|
|
6
|
+
* derives the ONE per-plane CSS transform via kernel `planeCssTransform` (the
|
|
7
|
+
* sole owner of that math — Law 13), and writes it to EVERY camera-transformed
|
|
8
|
+
* DOM plane in a SINGLE `style.transform` assignment each. Panning the whole
|
|
9
|
+
* canvas is therefore O(1) in the DOM: one transform write per plane per moving
|
|
10
|
+
* frame, independent of node count — the property that makes an infinite canvas
|
|
11
|
+
* of 10k gray boxes pan at frame rate.
|
|
12
|
+
*
|
|
13
|
+
* The input is widened to `{ contentPlane; liftedPlane? }` (design-004 §1: P1 +
|
|
14
|
+
* P3 share the one camera). A `CanvasHost` still satisfies it structurally, so
|
|
15
|
+
* M3 callers are unchanged; M6 passes both planes and the lifted plane (P3)
|
|
16
|
+
* tracks the content plane (P1) exactly, so a promoted widget keeps its world
|
|
17
|
+
* position across the content→lifted re-parent.
|
|
18
|
+
*
|
|
19
|
+
* `transformWrites()` is the M3 instrument: because the reflector is dirty-
|
|
20
|
+
* driven on the Camera resource (equality-suppressed — design-002 §5), a static
|
|
21
|
+
* camera flushes zero times and the counter stays flat; every distinct camera
|
|
22
|
+
* value bumps it exactly once. The frame-contract tests assert both halves.
|
|
23
|
+
*
|
|
24
|
+
* Law 10: reflectors run post-notify, write output only, and NEVER read layout
|
|
25
|
+
* or write ECS — this flush touches only `host.contentPlane.style`.
|
|
26
|
+
*/
|
|
27
|
+
import { type ReflectorDef } from "@ice/core";
|
|
28
|
+
/**
|
|
29
|
+
* The camera-transformed DOM plane(s). A `CanvasHost` satisfies this
|
|
30
|
+
* structurally (M3 backward compat); M6 passes `liftedPlane` too so P3 tracks P1.
|
|
31
|
+
*/
|
|
32
|
+
export interface CameraPlanes {
|
|
33
|
+
readonly contentPlane: HTMLElement;
|
|
34
|
+
readonly liftedPlane?: HTMLElement;
|
|
35
|
+
}
|
|
36
|
+
export declare function createPlaneTransformReflector(host: CameraPlanes): ReflectorDef & {
|
|
37
|
+
transformWrites(): number;
|
|
38
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* P5 — remote cursors (design-004 §1: screen-space DOM, "remote cursors are
|
|
3
|
+
* always custom nodes"; design-003 §7).
|
|
4
|
+
*
|
|
5
|
+
* Renders one pooled node per REMOTE cursor entity (`CursorVisual` kind
|
|
6
|
+
* "remote" + world `Position`, derived by core's remote-cursors system from
|
|
7
|
+
* presence peers; `Follows` names the peer whose `PresenceInfo` supplies
|
|
8
|
+
* color + label). Screen-space by design: an acknowledged small-N
|
|
9
|
+
* camera→position consumer (design-002 §5 rescope), recomputed on camera or
|
|
10
|
+
* cursor dirt only. The plane mounts LAST in the container, above chrome;
|
|
11
|
+
* `pointer-events: none` throughout — cursors are never hit-testable.
|
|
12
|
+
*/
|
|
13
|
+
import { type ReflectorDef, type World } from "@ice/core";
|
|
14
|
+
import type { CanvasHost } from "../host";
|
|
15
|
+
export interface RemoteCursorsReflector {
|
|
16
|
+
readonly reflector: ReflectorDef;
|
|
17
|
+
/** Remove the plane + pool (doc close / HMR). */
|
|
18
|
+
destroy(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createRemoteCursorsReflector(host: CanvasHost, world: World): RemoteCursorsReflector;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wires reflector (design-004 §1 P0 "WIRES" pass; design-001 §5.3).
|
|
3
|
+
*
|
|
4
|
+
* P0 is the ground stratum: the grid canvas paints first, the wires canvas next
|
|
5
|
+
* (this file), the content plane on top. Wires therefore render UNDER widget
|
|
6
|
+
* content — a node graph's edges sit behind its nodes — with no z-index
|
|
7
|
+
* bookkeeping: the wires canvas is inserted immediately before the content plane
|
|
8
|
+
* (after the grid canvas), so DOM order is the strata order (§1: stacking is
|
|
9
|
+
* stratified). Like the grid, it is a SCREEN-space canvas covering the full
|
|
10
|
+
* viewport; the camera is applied per-draw via the kernel `worldToScreen` seam
|
|
11
|
+
* rather than by a CSS plane transform, so panning re-strokes the curves at any
|
|
12
|
+
* zoom with no seams.
|
|
13
|
+
*
|
|
14
|
+
* Wire geometry NEVER reads a port ENTITY (design-001 §5.3): endpoints resolve
|
|
15
|
+
* from the wire's `WireFrom`/`WireTo` widgets (durable `Position`/`Size`) and the
|
|
16
|
+
* two `WirePorts` ids looked up against the widget type's static port schema
|
|
17
|
+
* (`PrefabId` -> `widgets.get(type).ports`); the kernel `portAnchor` places each
|
|
18
|
+
* anchor on the widget rect and `wireCubic` builds the curve. Because that path
|
|
19
|
+
* touches only durable geometry + the type registry — never a runtime port
|
|
20
|
+
* entity — a wire whose endpoint is CULLED (off-viewport, no DOM host, no
|
|
21
|
+
* materialized port) still draws by construction. This mirrors core's audited
|
|
22
|
+
* `systems/l1-wires.ts` endpoint resolver, so pick and render agree. The connect-
|
|
23
|
+
* drag preview and the materialized port dots share this one canvas.
|
|
24
|
+
*
|
|
25
|
+
* Change-only (design-002 §5): the reflector is `always: true` (the connect
|
|
26
|
+
* preview is an out-of-ECS buffer with no ECS stamp, exactly like the marquee
|
|
27
|
+
* buffer the chrome reflector consumes), but a full re-stroke happens only when
|
|
28
|
+
* something visible changed — private observers on Camera / [Position,Size] /
|
|
29
|
+
* [Wire] / [Selected] / ports / [RoutedConnect] arm a dirty flag, and the preview
|
|
30
|
+
* buffer is diffed by value each frame. A static scene with an idle preview
|
|
31
|
+
* re-strokes zero times after first paint.
|
|
32
|
+
*
|
|
33
|
+
* Fault isolation mirrors the grid: `getContext("2d")` returns `null` in happy-
|
|
34
|
+
* dom (and on context loss), so `available()` reports false and `flush` is a
|
|
35
|
+
* permanent silent no-op; every draw is wrapped so a driver failure degrades to
|
|
36
|
+
* unavailable rather than a throwing reflector (design-002 §5).
|
|
37
|
+
*
|
|
38
|
+
* Law 10: reflectors run post-notify, write output only, never read layout or
|
|
39
|
+
* write ECS — this flush touches only the wires canvas 2D context.
|
|
40
|
+
*/
|
|
41
|
+
import { type ReflectorDef, type World } from "@ice/core";
|
|
42
|
+
import type { CanvasHost } from "../host";
|
|
43
|
+
/**
|
|
44
|
+
* The connect-drag preview buffer (structural mirror of the core
|
|
45
|
+
* `WirePreviewBuffer` the graph-systems slice produces in
|
|
46
|
+
* `core/src/systems/l3-connect.ts`, exposed on `installInteractionStack` as
|
|
47
|
+
* `wirePreview`). Coords are WORLD-space; `active` gates drawing; `compatible`
|
|
48
|
+
* picks solid (snapped to a compatible port) vs dashed (free / incompatible).
|
|
49
|
+
*
|
|
50
|
+
* TODO(integration): once core exports its buffer type, import it here and drop
|
|
51
|
+
* this local — the lead reconciles field names if they diverge.
|
|
52
|
+
*/
|
|
53
|
+
export interface WirePreview {
|
|
54
|
+
/** Source anchor (world). */
|
|
55
|
+
sx: number;
|
|
56
|
+
sy: number;
|
|
57
|
+
/** Target / cursor (world). */
|
|
58
|
+
tx: number;
|
|
59
|
+
ty: number;
|
|
60
|
+
active: boolean;
|
|
61
|
+
compatible: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** Minimal-neutral wire styling (design-004 §6 chrome is subdued; wires defer to content). */
|
|
64
|
+
export interface WiresConfig {
|
|
65
|
+
/** Default wire stroke (CSS color). */
|
|
66
|
+
wireColor: string;
|
|
67
|
+
/** Accent stroke for a Selected wire. */
|
|
68
|
+
selectedColor: string;
|
|
69
|
+
wireWidth: number;
|
|
70
|
+
selectedWidth: number;
|
|
71
|
+
/** Materialized-port dot radius (CSS px) + colors (idle vs during a connect drag). */
|
|
72
|
+
portRadius: number;
|
|
73
|
+
portColor: string;
|
|
74
|
+
portActiveColor: string;
|
|
75
|
+
}
|
|
76
|
+
export declare const DEFAULT_WIRES_CONFIG: WiresConfig;
|
|
77
|
+
export interface WiresReflector extends ReflectorDef {
|
|
78
|
+
/** False under happy-dom / on context loss — flush is then a silent no-op. */
|
|
79
|
+
available(): boolean;
|
|
80
|
+
/** Full re-stroke count (the churn instrument): one per frame that actually redrew, zero on a static idle scene. */
|
|
81
|
+
redraws(): number;
|
|
82
|
+
/** Detach the canvas + tear down the private observers and ResizeObserver. */
|
|
83
|
+
dispose(): void;
|
|
84
|
+
}
|
|
85
|
+
export declare function createWiresReflector(host: CanvasHost, world: World, opts?: {
|
|
86
|
+
readPreview?: () => WirePreview;
|
|
87
|
+
config?: Partial<WiresConfig>;
|
|
88
|
+
}): WiresReflector;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../devtools/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../dom/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../core/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../kernel/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../r3f/src/index";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "../../react/src/index";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port-anchor math (design-001 §5.3): wire geometry NEVER reads port entities —
|
|
3
|
+
* anchors are pure functions over the widget rect + the port declaration, so
|
|
4
|
+
* culled endpoints work by construction.
|
|
5
|
+
*/
|
|
6
|
+
import type { Rect, Vec2 } from "./shapes";
|
|
7
|
+
export type PortSide = "n" | "e" | "s" | "w";
|
|
8
|
+
export interface PortSlot {
|
|
9
|
+
side: PortSide;
|
|
10
|
+
/** 0-based position among the ports sharing this side. */
|
|
11
|
+
index: number;
|
|
12
|
+
/** Total ports on this side. */
|
|
13
|
+
count: number;
|
|
14
|
+
}
|
|
15
|
+
/** World-space anchor point: ports distribute evenly along their side. */
|
|
16
|
+
export declare function portAnchor(widget: Rect, slot: PortSlot): Vec2;
|
|
17
|
+
/** Outward unit direction of a side (wire tangent stubs, Y-down world). */
|
|
18
|
+
export declare function sideDirection(side: PortSide): Vec2;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cubic-bezier wire geometry: construction from port anchors, conservative
|
|
3
|
+
* AABB (for the spatial index), and sampled distance (for picking — wires rank
|
|
4
|
+
* below widgets, design-003 §3).
|
|
5
|
+
*/
|
|
6
|
+
import { type PortSide } from "./anchors";
|
|
7
|
+
import type { AABB, Vec2 } from "./shapes";
|
|
8
|
+
export interface Cubic {
|
|
9
|
+
x0: number;
|
|
10
|
+
y0: number;
|
|
11
|
+
x1: number;
|
|
12
|
+
y1: number;
|
|
13
|
+
x2: number;
|
|
14
|
+
y2: number;
|
|
15
|
+
x3: number;
|
|
16
|
+
y3: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Wire curve between two anchors: tangent stubs leave each port along its
|
|
20
|
+
* side's outward direction, scaled with distance (min stub keeps short wires
|
|
21
|
+
* readable).
|
|
22
|
+
*/
|
|
23
|
+
export declare function wireCubic(from: Vec2, fromSide: PortSide, to: Vec2, toSide: PortSide, stubScale?: number, minStub?: number): Cubic;
|
|
24
|
+
/** Point on the curve at t ∈ [0, 1] (Bernstein form). */
|
|
25
|
+
export declare function cubicPoint(c: Cubic, t: number): Vec2;
|
|
26
|
+
/**
|
|
27
|
+
* Conservative bounds: the control-point hull contains the curve (convex-hull
|
|
28
|
+
* property). Cheap and index-friendly; exact extrema are unnecessary for
|
|
29
|
+
* culling/picking prefilters.
|
|
30
|
+
*/
|
|
31
|
+
export declare function cubicAABB(c: Cubic): AABB;
|
|
32
|
+
/** Distance from a point to a line segment. */
|
|
33
|
+
export declare function distanceToSegment(px: number, py: number, ax: number, ay: number, bx: number, by: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Min distance from a point to the curve via polyline sampling. 32 samples is
|
|
36
|
+
* ample for hit thresholds of a few px; error shrinks with curve flatness.
|
|
37
|
+
*/
|
|
38
|
+
export declare function distanceToCubic(px: number, py: number, c: Cubic, samples?: number): number;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE coordinate seam (Law 13): every conversion between screen, world, and
|
|
3
|
+
* island (widget-local GL) space lives here — including the ONE Y-flip.
|
|
4
|
+
* v1 duplicated this math in three places; nothing outside this module may
|
|
5
|
+
* re-derive it.
|
|
6
|
+
*
|
|
7
|
+
* Conventions:
|
|
8
|
+
* - screen: CSS px, canvas-container-relative, Y-down. DPR never enters world
|
|
9
|
+
* math (it exists only in GL uniforms / FBO sizing — see zoom-bands).
|
|
10
|
+
* - world: world units, Y-down. `Camera.{x,y}` is the WORLD point at the
|
|
11
|
+
* viewport's top-left; `zoom` is screen px per world unit.
|
|
12
|
+
* - island: widget-local GL space — CENTER origin, Y-UP, world-unit scale.
|
|
13
|
+
* (v1 VirtualWidget convention; the only Y-flip in the codebase.)
|
|
14
|
+
*/
|
|
15
|
+
import type { Rect, Vec2 } from "./shapes";
|
|
16
|
+
export interface CameraState {
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
zoom: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function screenToWorld(screenX: number, screenY: number, camera: CameraState): Vec2;
|
|
22
|
+
export declare function worldToScreen(worldX: number, worldY: number, camera: CameraState): Vec2;
|
|
23
|
+
/**
|
|
24
|
+
* Zoom about a fixed screen point (v1 `zoomAtPoint`): the world point under
|
|
25
|
+
* `(screenX, screenY)` stays under it after the zoom change.
|
|
26
|
+
* Returns the new camera (does not mutate). Clamping is the caller's policy.
|
|
27
|
+
*/
|
|
28
|
+
export declare function zoomAtPoint(camera: CameraState, screenX: number, screenY: number, newZoom: number): CameraState;
|
|
29
|
+
/**
|
|
30
|
+
* Camera → the ONE per-plane CSS transform (design-002 §5 `planeTransform`).
|
|
31
|
+
* Children are laid out in WORLD units inside the plane (left/top = world x/y),
|
|
32
|
+
* the plane carries `transform: translate(tx px, ty px) scale(scale)` with
|
|
33
|
+
* `transform-origin: 0 0` — so a child at world point p lands at
|
|
34
|
+
* `p·zoom + t = (p − camera)·zoom`, i.e. exactly `worldToScreen(p)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function planeCssTransform(camera: CameraState): {
|
|
37
|
+
tx: number;
|
|
38
|
+
ty: number;
|
|
39
|
+
scale: number;
|
|
40
|
+
};
|
|
41
|
+
/** World → island (center-origin, Y-up). THE Y-flip, direction one. */
|
|
42
|
+
export declare function worldToIsland(worldX: number, worldY: number, widget: Rect): Vec2;
|
|
43
|
+
/** Island → world. THE Y-flip, direction two. */
|
|
44
|
+
export declare function islandToWorld(islandX: number, islandY: number, widget: Rect): Vec2;
|
|
45
|
+
/**
|
|
46
|
+
* Camera → the P2 composite ortho frustum + camera position (world units,
|
|
47
|
+
* Y-up scene). `left/top` pin the viewport's top-left to `Camera.{x,y}`
|
|
48
|
+
* exactly like `planeCssTransform` does for the DOM planes: the frustum spans
|
|
49
|
+
* `viewport / zoom` world units and the camera sits at the world origin
|
|
50
|
+
* offset, so a quad at `worldRectToComposite(rect)` lands on the same screen
|
|
51
|
+
* pixels as a DOM host at `rect` under the plane transform.
|
|
52
|
+
*/
|
|
53
|
+
export declare function compositeCameraFrustum(camera: CameraState, viewportW: number, viewportH: number): {
|
|
54
|
+
left: number;
|
|
55
|
+
right: number;
|
|
56
|
+
top: number;
|
|
57
|
+
bottom: number;
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
};
|
|
61
|
+
/** World rect → composite-quad center + scale in the Y-up P2 scene. */
|
|
62
|
+
export declare function worldRectToComposite(rect: Rect): {
|
|
63
|
+
x: number;
|
|
64
|
+
y: number;
|
|
65
|
+
sx: number;
|
|
66
|
+
sy: number;
|
|
67
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FBO-pool eviction policy — ported from v1 `eviction.ts` (pure part of the
|
|
3
|
+
* pool). Priority: Cold(0) < Warm(1) < Dormant(2); LRU within a phase;
|
|
4
|
+
* Hot/Waking are never evicted even under an impossible budget.
|
|
5
|
+
*/
|
|
6
|
+
export type IslandPhase = "Hot" | "Warm" | "Waking" | "Cold" | "Dormant";
|
|
7
|
+
export interface EvictionCandidate<Id> {
|
|
8
|
+
id: Id;
|
|
9
|
+
phase: IslandPhase;
|
|
10
|
+
bytes: number;
|
|
11
|
+
lastUsedMs: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The island phase truth table (design-004 §3; v1 `computePhase` verbatim —
|
|
15
|
+
* RFC-002 pinned it with tests). `active` is the nested-canvas membership
|
|
16
|
+
* signal (always true until M8); `hasFbo` splits Warm (retained texture,
|
|
17
|
+
* composite-ready) from Waking (must paint before compositing) — after an
|
|
18
|
+
* eviction a re-entering island comes back as Waking, after a plain cull
|
|
19
|
+
* round-trip it comes back Warm from the retained texture.
|
|
20
|
+
*/
|
|
21
|
+
export declare function computeIslandPhase(active: boolean, visible: boolean, animating: boolean, hasFbo: boolean): IslandPhase;
|
|
22
|
+
/** Ordered ids to release so total bytes ≤ budget. Pure. */
|
|
23
|
+
export declare function selectEvictions<Id>(candidates: EvictionCandidate<Id>[], totalBytes: number, maxBytes: number): Id[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ice/kernel — pure math. Plain structs in, plain structs out.
|
|
3
|
+
* Import wall: nothing but `rbush` (named exception — zero-dep R-tree).
|
|
4
|
+
*/
|
|
5
|
+
export declare const KERNEL_VERSION = "0.0.0";
|
|
6
|
+
export * from "./shapes";
|
|
7
|
+
export * from "./coords";
|
|
8
|
+
export * from "./snap";
|
|
9
|
+
export * from "./spatial-index";
|
|
10
|
+
export * from "./zoom-bands";
|
|
11
|
+
export * from "./eviction";
|
|
12
|
+
export * from "./anchors";
|
|
13
|
+
export * from "./bezier";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Plain geometric structs shared across the kernel. Ported from v1 `ecs/math.ts`. */
|
|
2
|
+
export interface Vec2 {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Rect {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
}
|
|
12
|
+
export interface AABB {
|
|
13
|
+
minX: number;
|
|
14
|
+
minY: number;
|
|
15
|
+
maxX: number;
|
|
16
|
+
maxY: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function rectToAABB(r: Rect): AABB;
|
|
19
|
+
export declare function aabbToRect(a: AABB): Rect;
|
|
20
|
+
export declare function intersectsAABB(a: AABB, b: AABB): boolean;
|
|
21
|
+
export declare function pointInAABB(px: number, py: number, a: AABB): boolean;
|
|
22
|
+
export declare function clamp(value: number, min: number, max: number): number;
|