@modernrelay/orbit-engine-cosmos 0.13.5 → 0.14.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 +33 -34
- package/dist/index.d.ts +85 -82
- package/dist/index.js +52 -45
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,10 +5,12 @@ Cosmos engine adapter for Orbit.
|
|
|
5
5
|
## Tested engine range
|
|
6
6
|
|
|
7
7
|
This adapter is developed and probed against exactly **`@cosmos.gl/graph@3.4.0`**
|
|
8
|
-
(exact pin, no range).
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
(exact pin, no range). In the repository, `pnpm cosmos:pin-check` verifies that
|
|
9
|
+
the adapter and `apps/spike` declare the same exact version. Any pin bump must
|
|
10
|
+
update both manifests, pass that check and `pnpm probe:node`, then be exercised
|
|
11
|
+
locally with the headful `pnpm probe` suite on a real GPU before the new version
|
|
12
|
+
is considered supported. The 3.3.0 → 3.4.0 bump was re-probed on 2026-08-10;
|
|
13
|
+
upstream on-demand rendering made the quiescence probe pass.
|
|
12
14
|
|
|
13
15
|
## Capability profile
|
|
14
16
|
|
|
@@ -18,29 +20,26 @@ Node-verifiable facts (measured by `pnpm probe:node`, re-checked in CI):
|
|
|
18
20
|
| --- | --- | --- |
|
|
19
21
|
| `rangeUpdates` | `[]` | Every buffer setter in `dist/index.d.ts` (`setPointPositions`, `setPointColors`, `setLinks`, …) takes a full array; no offset/count variants exist. Whole-buffer re-upload is the only update path. |
|
|
20
22
|
| `postDrawFrames` | `false` | The `config.d.ts` callback inventory has no draw/render-phase hook — only simulation (`onSimulationTick/Start/End/Pause/Unpause`), transition, zoom, drag and pointer callbacks. Post-draw work must be scheduled externally. Since v0.13 this is a REAL `EngineCapabilities` field, not just prose. |
|
|
21
|
-
| `idleFrames` | `'stops'` | cosmos ≥3.4 on-demand rendering idle-stops the engine loop, and the adapter's gated activity clock stops with it — measured 0 idle frames and 0 rAF registrations per 750 ms at rest
|
|
23
|
+
| `idleFrames` | `'stops'` | cosmos ≥3.4 on-demand rendering idle-stops the engine loop, and the adapter's gated activity clock stops with it — measured 0 idle frames and 0 rAF registrations per 750 ms at rest by the quiescence probe below. |
|
|
22
24
|
| `node-import-safe` | `true` | `await import('@cosmos.gl/graph')` succeeds in plain Node (module scope guards `typeof window`), so SSR and test imports never crash. |
|
|
23
25
|
|
|
24
|
-
GPU-probed capabilities (measured 2026-
|
|
25
|
-
Chromium
|
|
26
|
+
GPU-probed capabilities (re-measured 2026-08-10 on Apple M5 Pro, ANGLE Metal, headful
|
|
27
|
+
Chromium):
|
|
26
28
|
|
|
27
29
|
| Capability | Result | Finding |
|
|
28
30
|
| --- | --- | --- |
|
|
29
31
|
| `atomic-commit` | ✅ pass | Multi-channel commit (positions+colors+links) applied mid-simulation shows zero mixed frames — a monotonic A→B switch one frame after commit. Visibly atomic commits are real. |
|
|
30
32
|
| `point-picking` | ✅ pass | `onPointClick` delivers the exact index at `spaceToScreenPosition` coords; misses report `undefined`. |
|
|
31
|
-
| `link-picking` | ✅ pass | Native `onLinkClick`/`onLinkMouseOver` deliver correct link indices; ~4 px perpendicular tolerance on a 2 px link. **Flipped
|
|
33
|
+
| `link-picking` | ✅ pass | Native `onLinkClick`/`onLinkMouseOver` deliver correct link indices; ~4 px perpendicular tolerance on a 2 px link. **Flipped:** the adapter now reports `capabilities.linkPicking: true` and wires `onLinkClick`/`onLinkMouseOver`/`onLinkMouseOut` to the host events, backed by the headful probe. |
|
|
32
34
|
| `nan-tombstones` | ✅ pass | NaN'd points escape hit-testing, incident links vanish, `fitView` ignores tombstoned slots. |
|
|
33
35
|
| `native-pinning` | ✅ pass | `setPinnedPoints` excludes points from force integration; `[]`/repeat calls are idempotent. |
|
|
34
|
-
| `tracked-positions` | ⚠️ fail (budget) | Semantics correct (packing order, last-call-replaces), but each `getTrackedPointPositionsArray` read stalls ~8.7 ms p50 on 3.4.0 (was ~18 ms on 3.3) **regardless of k** — a sync pipeline flush, not payload cost. Per-frame tracked readback stays non-viable; DOM-label positioning reads at settle/idle cadence
|
|
36
|
+
| `tracked-positions` | ⚠️ fail (budget) | Semantics correct (packing order, last-call-replaces), but each `getTrackedPointPositionsArray` read stalls ~8.7 ms p50 on 3.4.0 (was ~18 ms on 3.3) **regardless of k** — a sync pipeline flush, not payload cost. Per-frame tracked readback stays non-viable; DOM-label positioning reads at settle/idle cadence. |
|
|
35
37
|
| `quiescence` | ✅ pass (3.4.0) | On-demand rendering: 0 idle frames AND 0 rAF registrations per 750 ms at rest (was 91 on 3.3.0). Settle lands ~5 s after `onSimulationEnd` (trailing transitions). Picking stays index-truthful at rest, drag release renders its final frame, and a `render()` + same-tick capture reads valid pixels (the stale-wake micro-cases). |
|
|
36
|
-
| `context-loss` | ⚠️ fail (by design) | `lost`/`restored` events surface, but no combination of buffer/config replay revives rendering after `restoreContext()` — only a full `Graph` destroy + re-create recovers
|
|
38
|
+
| `context-loss` | ⚠️ fail (by design) | `lost`/`restored` events surface, but no combination of buffer/config replay revives rendering after `restoreContext()` — only a full `Graph` destroy + re-create recovers. This validates the adapter's recreate-on-restore protocol: `CosmosEngine` rebuilds the Graph in the same container and the core replays the scene. |
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
`resource-estimates`) lives at [docs/m0-conformance.md](../../docs/m0-conformance.md).
|
|
40
|
+
## Interaction surface
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Coordinate-space facts verified against the 3.3.0 dist (see the
|
|
42
|
+
Coordinate-space facts verified against the exact-pin 3.4.0 dist (see the
|
|
44
43
|
`CosmosEngine.ts` module header for the exact evidence):
|
|
45
44
|
|
|
46
45
|
- `pointsInPolygon(screenPolygon)` — cosmos' `findPointsInPolygon` takes
|
|
@@ -56,24 +55,24 @@ Coordinate-space facts verified against the 3.3.0 dist (see the
|
|
|
56
55
|
- `setPinnedIndices` maps to `setPinnedPoints` (full-set replace; `null`/`[]`
|
|
57
56
|
unpin all). Re-applying pins after context-loss recovery is core-owned.
|
|
58
57
|
|
|
59
|
-
## Overlay & toolbar surface
|
|
58
|
+
## Overlay & toolbar surface
|
|
60
59
|
|
|
61
60
|
| Capability | Behavior | Basis / degradation |
|
|
62
61
|
| --- | --- | --- |
|
|
63
|
-
| `onFrame` GATED activity clock | The adapter owns the single `requestAnimationFrame` loop, GATED to match cosmos ≥3.4's on-demand rendering
|
|
62
|
+
| `onFrame` GATED activity clock | The adapter owns the single `requestAnimationFrame` loop, GATED to match cosmos ≥3.4's on-demand rendering: it free-runs only under a held run reason (sim hot, drag gesture, cosmos transition) and otherwise burns a one-shot tick budget that every visual write re-arms (commits, highlight/focus/pin setters, camera moves, hover; animated camera moves self-sustain via per-step `onZoom` bursts). Every reason release grants ONE trailing tick (the final GPU write lands after the current draw pass). Stopped on context loss/`destroy()`, re-armed on recovery; the callback is skipped while `document.hidden`. **At rest: zero rAF registrations** (`idleFrames: 'stops'`). | **Documented degradation:** cosmos still exposes no draw/render-phase hook (`postDrawFrames: false`), so this is an *activity* clock, not a post-draw hook — DOM overlays may lag the canvas by one frame. Reported once at mount via `engine:overlay-activity-clock`; `showFPSMonitor` via the config escape hatch keeps cosmos rendering and is diagnosed once (`engine:fps-monitor-defeats-quiescence`). |
|
|
64
63
|
| `onContextMenu` | cosmos' unified `onContextMenu(index \| undefined, pos, event)` config callback → host `onContextMenu(index \| null, [containerX, containerY])` (container-relative CSS px from the event's `clientX/Y`). Covers desktop right-click and touch long-press (cosmos synthesizes the latter). The native event is `preventDefault`-ed only when the host registered `onContextMenu` (Orbit's core always does — it owns the typed `contextMenu` event). | Only the unified callback is wired: the per-target `onPointContextMenu`/`onLinkContextMenu`/`onBackgroundContextMenu` callbacks fire *additionally* for the same gesture and would double-report. A context menu over a link arrives with `index === undefined` and is reported as background. |
|
|
65
|
-
| `pointsInRect(screenRect)` | `[x0, y0, x1, y1]` → cosmos `findPointsInRect([[left, top], [right, bottom]])` (corners normalized to min/max so any opposite-corner pair works). Lifecycle-guarded: `[]` pre-mount / while lost / after destroy. | Same **screen** coordinate space as `findPointsInPolygon` (0 to canvas width/height per the
|
|
66
|
-
| `captureScreenshot()` | Resolves a PNG `Blob` of the current frame, or `null` when unsupported, not ready, lost, or on any capture failure. | The
|
|
64
|
+
| `pointsInRect(screenRect)` | `[x0, y0, x1, y1]` → cosmos `findPointsInRect([[left, top], [right, bottom]])` (corners normalized to min/max so any opposite-corner pair works). Lifecycle-guarded: `[]` pre-mount / while lost / after destroy. | Same **screen** coordinate space as `findPointsInPolygon` (0 to canvas width/height per the exact-pin d.ts; the dist flips Y assuming ordered corners) — no conversion. |
|
|
65
|
+
| `captureScreenshot()` | Resolves a PNG `Blob` of the current frame, or `null` when unsupported, not ready, lost, or on any capture failure. | The same-tick capture method (`apps/spike/src/instrument.ts`): cosmos renders with a non-preserved drawing buffer, so the WebGL canvas is only readable via a synchronous `drawImage` onto an offscreen 2D canvas inside the same rAF tick. Under on-demand rendering an idle scene draws nothing (blank buffer), so the adapter first calls `graph.render()` — a visual mutator that schedules the frame the capture rAF then samples. |
|
|
67
66
|
|
|
68
|
-
## Styling channels
|
|
67
|
+
## Styling channels
|
|
69
68
|
|
|
70
|
-
Facts verified against the 3.
|
|
69
|
+
Facts verified against the exact-pin 3.4.0 dist typings (`config.d.ts` / `index.d.ts`):
|
|
71
70
|
|
|
72
71
|
| Capability | Value | Mechanism / basis |
|
|
73
72
|
| --- | --- | --- |
|
|
74
73
|
| `edgeArrows` | `true` | Commit `config.linkArrows` maps to cosmos' `linkDefaultArrows` config key (config.d.ts, default `false`) via `setConfigPartial` — instanced arrowheads toggle atomically within the commit's single `render()`. No per-link `setLinkArrows(boolean[])` buffer is used (Orbit's toggle is scene-wide). |
|
|
75
|
-
| `pointImages` | `true` | cosmos 3.
|
|
76
|
-
| `renderLinks` toggle | config-only | cosmos 3.
|
|
74
|
+
| `pointImages` | `true` | cosmos 3.4.0 exposes `setImageData(ImageData[])` + `setPointImageIndices(Float32Array)` (index.d.ts). The adapter maintains a slot→`ImageData` mirror of the atlas: commit upserts transcode each `ImageBitmap` through an offscreen 2D canvas (`drawImage` + `getImageData`), `removeSlots` blanks entries with a 1×1 transparent `ImageData` (slot indices stay stable), and any atlas change re-uploads the FULL array (cosmos has no partial image update — consistent with `rangeUpdates: []`). The mirror is CPU-side, so it survives context loss; post-restore atlas commits re-upload everything to the fresh graph. **Degradation:** where no 2D context exists (jsdom without the canvas package), the image channel no-ops — never throws — and reports the `engine:image-channel-unavailable` warning diagnostic exactly once. |
|
|
75
|
+
| `renderLinks` toggle | config-only | cosmos 3.4.0 has a first-class `renderLinks: boolean` config key (config.d.ts, default `true`), so commit `config.renderLinks` is a pure `setConfigPartial` toggle — **zero buffer setters**, no `linkOpacity` workaround, no link-buffer rebuild. |
|
|
77
76
|
| Theme default colors | config-only | Commit `config.defaultPointColor`/`config.defaultLinkColor` map to cosmos' `pointDefaultColor`/`linkDefaultColor` config keys (CSS color strings accepted natively). |
|
|
78
77
|
|
|
79
78
|
While pre-mount, context-lost, or terminally failed, resources fold into the
|
|
@@ -81,11 +80,11 @@ pending-commit per-channel merge like every other channel: image upserts union
|
|
|
81
80
|
per slot (latest bitmap wins; a later remove drops an earlier pending upsert of
|
|
82
81
|
the same slot), and the latest `pointImageIndex` replaces wholesale.
|
|
83
82
|
|
|
84
|
-
## Cluster force
|
|
83
|
+
## Cluster force
|
|
85
84
|
|
|
86
85
|
| Capability | Value | Mechanism / basis |
|
|
87
86
|
| --- | --- | --- |
|
|
88
|
-
| `clusterForce` | `true` | **Dist investigation (3.
|
|
87
|
+
| `clusterForce` | `true` | **Dist investigation (3.4.0, the exact pin):** `dist/index.d.ts` exposes `setPointClusters((number \| undefined)[])`, `setClusterPositions((number \| undefined)[])`, `setPointClusterStrength(Float32Array)` and `getClusterPositions()`; `dist/config.d.ts` exposes the `simulationCluster` coefficient (default `0.1`); `dist/modules/Clusters/index.d.ts` is the GPU module implementing it (centermass FBO + force application pass). The capability is therefore declared honestly, not faked. **Evidence class: Node-verifiable (dist typing scan), like `rangeUpdates`/`postDrawFrames` — the API surface is present and wired, but the visible force behavior still requires a headful probe (see the GPU evidence policy below).** |
|
|
89
88
|
|
|
90
89
|
Contract mapping applied inside the single atomic commit (staged after the
|
|
91
90
|
roster, before the one `render()`):
|
|
@@ -105,20 +104,20 @@ roster, before the one `render()`):
|
|
|
105
104
|
membership array of the **current roster length** plus empty cluster
|
|
106
105
|
positions, so the mapping length never lags the roster (I2).
|
|
107
106
|
|
|
108
|
-
## Camera surface
|
|
107
|
+
## Camera surface
|
|
109
108
|
|
|
110
109
|
| Capability | Behavior | Basis / formula |
|
|
111
110
|
| --- | --- | --- |
|
|
112
|
-
| `setViewport({x, y, zoom})` — **real pan** | Centers space point `(x, y)` at exactly the requested (or current) zoom in one call; a follow-up `getViewport()` returns the same `{x, y, zoom}` (modulo cosmos' d3 `scaleExtent` clamp). A missing `x` or `y` is filled from the current viewport; zoom-only calls keep the `setZoomLevel` path (d3 `scaleTo` preserves the center). Instant unless `durationMs` is given. | **The former zoom-only limitation is LIFTED.**
|
|
113
|
-
|
|
|
111
|
+
| `setViewport({x, y, zoom})` — **real pan** | Centers space point `(x, y)` at exactly the requested (or current) zoom in one call; a follow-up `getViewport()` returns the same `{x, y, zoom}` (modulo cosmos' d3 `scaleExtent` clamp). A missing `x` or `y` is filled from the current viewport; zoom-only calls keep the `setZoomLevel` path (d3 `scaleTo` preserves the center). Instant unless `durationMs` is given. | **The former zoom-only limitation is LIFTED.** The exact-pin API has no pan-to method, but `setZoomTransformByPointPositions(positions, duration, scale, padding)` is an exact center+zoom when `scale` is explicit — verified in the 3.4.0 dist (`zoomInstance.getTransform`): `store.scaleX/scaleY` are linear slope-±1 space→screen maps, a single-point bbox is widened ±0.5 *symmetrically* (center preserved), and an explicit `scale` bypasses the fit math and `padding` entirely, yielding `translate(w/2 − scaleX(x)·k, h/2 − scaleY(y)·k).scale(k)` with `k = scale`. The adapter calls `setZoomTransformByPointPositions(Float32Array.of(x, y), durationMs ?? 0, zoom ?? getZoomLevel())`. |
|
|
112
|
+
| viewport restore | Context-loss recovery now restores the full camera: the core replays the last stored `{x, y, zoom}` through `setViewport` after the scene commit, and the pan lands (previously only `zoom` was honored). | Supersedes the earlier zoom-only restore behavior. |
|
|
114
113
|
|
|
115
114
|
## GPU evidence policy
|
|
116
115
|
|
|
117
116
|
GPU probe records are produced locally by running the probe suite headful on a
|
|
118
117
|
real GPU (`pnpm probe`, which sets `PROBE_HEADFUL=1`; set `PROBE_GPU` to
|
|
119
|
-
describe the hardware). CI
|
|
120
|
-
|
|
121
|
-
(`pnpm
|
|
122
|
-
software rasterizer are not accepted as
|
|
123
|
-
are permitted solely as a harness smoke test and their records
|
|
124
|
-
committed.
|
|
118
|
+
describe the hardware). CI verifies the exact dependency pins with
|
|
119
|
+
`pnpm cosmos:pin-check` and re-runs the Node-safe probes
|
|
120
|
+
(`pnpm probe:node`); it never produces GPU evidence. Results rendered through
|
|
121
|
+
SwiftShader or any other software rasterizer are not accepted as GPU evidence.
|
|
122
|
+
Headless runs are permitted solely as a harness smoke test and their records
|
|
123
|
+
must not be committed.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { GraphEngine, EngineCapabilities, EngineHostEvents, EngineCommit, FitViewOptions } from '@modernrelay/orbit-core/engine';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* CosmosEngine — GraphEngine adapter over @cosmos.gl/graph
|
|
4
|
+
* CosmosEngine — GraphEngine adapter over @cosmos.gl/graph.
|
|
5
5
|
*
|
|
6
|
-
* Node-safe module: cosmos is loaded lazily via `await import
|
|
7
|
-
* `mount
|
|
6
|
+
* Node-safe module: cosmos is loaded lazily via `await import` inside
|
|
7
|
+
* `mount`; module scope carries only type-only imports (erased at
|
|
8
8
|
* runtime) and never touches the DOM.
|
|
9
9
|
*
|
|
10
10
|
* Color scale note: the EngineCommit contract carries RGBA floats in [0,1],
|
|
@@ -13,47 +13,47 @@ import { GraphEngine, EngineCapabilities, EngineHostEvents, EngineCommit, FitVie
|
|
|
13
13
|
* input is fed to GPU buffers untouched) — so color buffers pass through.
|
|
14
14
|
*
|
|
15
15
|
* Interaction notes (verified against the 3.3.0 dist):
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
16
|
+
* - Link picking is native: setting any onLink* config callback flips
|
|
17
|
+
* cosmos' internal `isLinkHoveringEnabled` on, so wiring the callbacks in
|
|
18
|
+
* `buildInitialConfig` is sufficient (no extra config flag exists).
|
|
19
|
+
* - `findPointsInPolygon` takes SCREEN coordinates ("from 0 to the
|
|
20
|
+
* width/height of the canvas" per dist/index.d.ts), so `pointsInPolygon`
|
|
21
|
+
* passes the host's screen polygon through without conversion.
|
|
22
|
+
* - `findPointsInRect` uses the SAME screen space and expects ordered
|
|
23
|
+
* corners `[[left, top], [right, bottom]]` (the dist flips Y assuming that
|
|
24
|
+
* ordering), so `pointsInRect` normalizes the host's [x0,y0,x1,y1] rect to
|
|
25
|
+
* min/max corners and passes it through without conversion.
|
|
26
|
+
* - Camera pan (the earlier zoom-only limitation is LIFTED): cosmos 3.3 has no
|
|
27
|
+
* pan-to API, but `setZoomTransformByPointPositions(positions, duration,
|
|
28
|
+
* scale, padding)` (dist/index.d.ts) is an exact center+zoom when `scale`
|
|
29
|
+
* is explicit. Derivation from the dist (`zoomInstance.getTransform`):
|
|
30
|
+
* space→screen-at-k=1 goes through `store.scaleX/scaleY`, which are LINEAR
|
|
31
|
+
* with slope ±1 (scaleX(x) = x + (w−S)/2; scaleY(y) = (S−y) + (h−S)/2,
|
|
32
|
+
* S = adjustedSpaceSize, w/h = canvas size); a single-point bbox is widened
|
|
33
|
+
* ±0.5 SYMMETRICALLY (center preserved); an explicit `scale` bypasses the
|
|
34
|
+
* fit math and `padding` entirely — k = clamp(scale, d3 scaleExtent) and
|
|
35
|
+
* the result is translate(w/2 − scaleX(x)·k, h/2 − scaleY(y)·k).scale(k),
|
|
36
|
+
* i.e. space point (x, y) lands exactly at the screen center with
|
|
37
|
+
* eventTransform.k = scale. Since `getZoomLevel()` returns eventTransform.k
|
|
38
|
+
* and `getViewport()` reads screenToSpacePosition(screen center),
|
|
39
|
+
* `setViewport({x, y, zoom})` → setZoomTransformByPointPositions(
|
|
40
|
+
* Float32Array.of(x, y), durationMs ?? 0, zoom ?? getZoomLevel()) makes a
|
|
41
|
+
* follow-up `getViewport()` return exactly {x, y, zoom} (modulo the
|
|
42
|
+
* scaleExtent clamp). This also completes recovery: the core replays
|
|
43
|
+
* the full stored {x, y, zoom} through setViewport, so viewport restore is
|
|
44
|
+
* no longer zoom-only.
|
|
45
|
+
* - Context menu: cosmos fires the unified config `onContextMenu(index |
|
|
46
|
+
* undefined, pos, event)` exactly ONCE per gesture — desktop right-click
|
|
47
|
+
* (dist `onContextMenu(e)`) and touch/pen long-press (dist long-press timer
|
|
48
|
+
* → `fireContextMenu`) both route through it — while the per-target
|
|
49
|
+
* `onPointContextMenu`/`onLinkContextMenu`/`onBackgroundContextMenu`
|
|
50
|
+
* callbacks fire ADDITIONALLY for the same gesture. Wiring only the unified
|
|
51
|
+
* callback therefore avoids a double-report (same shape as the
|
|
52
|
+
* onClick/onBackgroundClick dedupe). A context menu over a LINK arrives
|
|
53
|
+
* with index undefined and is reported as background (the host event
|
|
54
|
+
* carries node-or-background only).
|
|
55
55
|
*
|
|
56
|
-
* GATED overlay/activity clock
|
|
56
|
+
* GATED overlay/activity clock:
|
|
57
57
|
* cosmos still exposes no draw/render-phase hook (`postDrawFrames: false`),
|
|
58
58
|
* so the adapter owns the single requestAnimationFrame loop that reports
|
|
59
59
|
* `onFrame(timeMs)` to the host — an ACTIVITY clock, not a post-draw hook:
|
|
@@ -65,29 +65,29 @@ import { GraphEngine, EngineCapabilities, EngineHostEvents, EngineCommit, FitVie
|
|
|
65
65
|
* cosmos transitions) and otherwise burns a small one-shot tick budget that
|
|
66
66
|
* every visual write re-arms (commits, highlight/focus/pin setters, camera
|
|
67
67
|
* moves, hover events; animated camera moves self-sustain through per-step
|
|
68
|
-
* onZoom bursts). Releasing a run reason always grants ONE trailing tick
|
|
68
|
+
* onZoom bursts). Releasing a run reason always grants ONE trailing tick
|
|
69
69
|
* the releasing activity's final GPU write lands after the current draw
|
|
70
70
|
* pass. At rest: zero rAF registrations from cosmos AND from this adapter
|
|
71
71
|
* (`capabilities.idleFrames: 'stops'`). The clock stops on context
|
|
72
72
|
* loss/destroy, re-arms on recovery, and skips the callback (keeping its
|
|
73
73
|
* schedule) while `document.hidden`.
|
|
74
74
|
*
|
|
75
|
-
* Screenshots use the
|
|
75
|
+
* Screenshots use the same-tick capture method (apps/spike/src/instrument.ts):
|
|
76
76
|
* cosmos renders with preserveDrawingBuffer:false, so the WebGL buffer is only
|
|
77
|
-
* readable via a synchronous drawImage inside the same rAF tick it was drawn
|
|
77
|
+
* readable via a synchronous drawImage inside the same rAF tick it was drawn
|
|
78
78
|
* `captureScreenshot` schedules one rAF, draws the cosmos canvas onto an
|
|
79
79
|
* offscreen 2D canvas inside that tick, and resolves the Blob (null on any
|
|
80
80
|
* failure or unusable lifecycle state).
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
81
|
+
* - The D3 drag events carry NO point index (the drag subject is a bare
|
|
82
|
+
* `{x, y}`); cosmos assigns `store.draggingPointIndex` immediately before
|
|
83
|
+
* invoking `onDragStart`, so the adapter reads it there (see
|
|
84
|
+
* `readDraggingIndex` for the public-callback fallback).
|
|
85
|
+
* - During a drag, cosmos' drag shader hard-pins the dragged point's
|
|
86
|
+
* position texture entry to the mouse's SPACE position every frame
|
|
87
|
+
* (dist `drag`: `pointPosition.rg = mousePos` where `mousePos` =
|
|
88
|
+
* screenToSpace(pointer)). So the point's final space position equals
|
|
89
|
+
* `screenToSpacePosition([event.x, event.y])` at drag end — an O(1) CPU
|
|
90
|
+
* transform, chosen over `getPointPositions` (full GPU readback).
|
|
91
91
|
*/
|
|
92
92
|
|
|
93
93
|
/** Derived from the contract to avoid importing the core root barrel. */
|
|
@@ -132,7 +132,7 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
132
132
|
/** Sticky override from EngineConfigUpdate.seedRadius. */
|
|
133
133
|
private seedRadiusOverride;
|
|
134
134
|
/** Point count of the last structure-bearing commit — the roster length a
|
|
135
|
-
* `cluster: null` clear must write an all-unclustered array for
|
|
135
|
+
* `cluster: null` clear must write an all-unclustered array for. */
|
|
136
136
|
private lastPointCount;
|
|
137
137
|
/**
|
|
138
138
|
* cosmos fires `onClick` (index undefined) AND `onBackgroundClick` for the
|
|
@@ -143,6 +143,9 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
143
143
|
private dragIndex;
|
|
144
144
|
/** Last hover reported by cosmos — fallback dragged-point source. */
|
|
145
145
|
private lastHoverIndex;
|
|
146
|
+
/** Live native link hover gates the unified onClick's
|
|
147
|
+
* background interpretation — a hovered link owns the click). */
|
|
148
|
+
private hoveredLinkIndex;
|
|
146
149
|
/** rAF id of the pending activity-clock tick; null = clock not running. */
|
|
147
150
|
private frameHandle;
|
|
148
151
|
/** Window driving the clock, cached so stop works after the div detaches. */
|
|
@@ -184,7 +187,7 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
184
187
|
* zoom — `setViewport(p)` then `getViewport()` returns p, modulo cosmos'
|
|
185
188
|
* d3 scaleExtent clamp. A missing x or y is filled from the current
|
|
186
189
|
* viewport; zoom-only calls keep the `setZoomLevel` path (d3's scaleTo
|
|
187
|
-
* preserves the current center). Instant unless `durationMs` is given
|
|
190
|
+
* preserves the current center). Instant unless `durationMs` is given
|
|
188
191
|
* cosmos' own default duration is 250 ms, which would animate context-
|
|
189
192
|
* recovery replays.
|
|
190
193
|
*/
|
|
@@ -205,7 +208,7 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
205
208
|
setPinnedIndices(indices: readonly number[] | null): void;
|
|
206
209
|
getPositions(): Float32Array | null;
|
|
207
210
|
/**
|
|
208
|
-
* Captures the cosmos canvas via the
|
|
211
|
+
* Captures the cosmos canvas via the same-tick method (see module
|
|
209
212
|
* header): one rAF is scheduled and, inside that tick, the WebGL canvas is
|
|
210
213
|
* drawn synchronously onto an offscreen 2D canvas (cosmos renders with
|
|
211
214
|
* preserveDrawingBuffer:false, so the buffer is only readable same-tick).
|
|
@@ -216,13 +219,13 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
216
219
|
destroy(): void;
|
|
217
220
|
/**
|
|
218
221
|
* One rAF tick of the gated activity clock. Ordering is load-bearing:
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
222
|
+
* 1. the tick budget is consumed BEFORE the host callback runs, so work
|
|
223
|
+
* scheduled from inside onFrame re-arms a fresh tick instead of being
|
|
224
|
+
* coalesced away;
|
|
225
|
+
* 2. the reschedule/stop decision is made BEFORE the host callback, so a
|
|
226
|
+
* throwing host can never kill a should-keep-running clock (and a
|
|
227
|
+
* stopping clock stays stopped even if the callback wakes it — the
|
|
228
|
+
* wake starts a new loop via requestTicks/wake, not this handle).
|
|
226
229
|
* Skips the callback (but keeps its schedule) while the document is hidden.
|
|
227
230
|
*/
|
|
228
231
|
private readonly frameTick;
|
|
@@ -248,7 +251,7 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
248
251
|
private get activeGraph();
|
|
249
252
|
/**
|
|
250
253
|
* cosmos owns its canvas; we can only wire webglcontext* listeners after
|
|
251
|
-
* init by querying it. A missing canvas downgrades to an info diagnostic
|
|
254
|
+
* init by querying it. A missing canvas downgrades to an info diagnostic
|
|
252
255
|
* the engine keeps working, just without context-loss recovery.
|
|
253
256
|
*/
|
|
254
257
|
private attachContextListeners;
|
|
@@ -307,48 +310,48 @@ declare class CosmosEngine implements GraphEngine {
|
|
|
307
310
|
private handleDragEnd;
|
|
308
311
|
private emitViewportChange;
|
|
309
312
|
/**
|
|
310
|
-
* One visibly atomic update
|
|
311
|
-
* exactly one render
|
|
313
|
+
* One visibly atomic update: all channels and config are staged, then
|
|
314
|
+
* exactly one render draws them; restart reheats after the render.
|
|
312
315
|
*/
|
|
313
316
|
private applyCommit;
|
|
314
317
|
/**
|
|
315
|
-
* Applies the
|
|
318
|
+
* Applies the stage-4 cluster force (capability `clusterForce`).
|
|
316
319
|
*
|
|
317
320
|
* Contract mapping, verified against the 3.3.0 dist (`index.d.ts`):
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
321
|
+
* - `pointClusters` (Float32Array, NaN = unclustered) →
|
|
322
|
+
* `setPointClusters((number | undefined)[])`, where cosmos' documented
|
|
323
|
+
* "does not belong to any cluster" value is `undefined`;
|
|
324
|
+
* - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →
|
|
325
|
+
* `setClusterPositions((number | undefined)[])`; a non-finite entry means
|
|
326
|
+
* "no position" and cosmos falls back to that cluster's centermass;
|
|
327
|
+
* - `null` clears: an all-`undefined` array of the CURRENT roster length
|
|
328
|
+
* (length must track the roster) plus empty cluster positions.
|
|
326
329
|
* `strength` is the scene-wide `simulationCluster` config coefficient
|
|
327
330
|
* applied in the config block, not the per-point
|
|
328
331
|
* `setPointClusterStrength` buffer (Orbit's strength is scene-wide).
|
|
329
332
|
*/
|
|
330
333
|
private applyClusterForce;
|
|
331
334
|
/**
|
|
332
|
-
* Applies the
|
|
335
|
+
* Applies the image-atlas channel: upserts convert ImageBitmap →
|
|
333
336
|
* ImageData through an offscreen 2D canvas into the slot mirror, removals
|
|
334
337
|
* blank their slot, and any atlas change re-uploads the FULL ImageData
|
|
335
338
|
* array (cosmos' setImageData is whole-array only, matching
|
|
336
339
|
* `rangeUpdates: []`). Environments without a usable 2D context (jsdom)
|
|
337
|
-
* no-op the channel and report `engine:image-channel-unavailable` once
|
|
340
|
+
* no-op the channel and report `engine:image-channel-unavailable` once
|
|
338
341
|
* never throw.
|
|
339
342
|
*/
|
|
340
343
|
private applyResources;
|
|
341
344
|
/**
|
|
342
345
|
* Reads an ImageData of the given size off an offscreen 2D canvas, drawing
|
|
343
346
|
* `bitmap` onto it first when provided (ImageBitmap → ImageData transcode;
|
|
344
|
-
* without a bitmap: a transparent blank). Returns null — never throws
|
|
347
|
+
* without a bitmap: a transparent blank). Returns null — never throws
|
|
345
348
|
* where no 2D context exists (jsdom without the canvas package).
|
|
346
349
|
*/
|
|
347
350
|
private canvasImageData;
|
|
348
351
|
/** Documented degradation, reported at most once per engine instance. */
|
|
349
352
|
private reportImageChannelUnavailable;
|
|
350
353
|
/**
|
|
351
|
-
* Replaces NaN pairs (= "no known position"
|
|
354
|
+
* Replaces NaN pairs (= "no known position") with random points on a
|
|
352
355
|
* ring of radius seedRadius around the space center. cosmos treats NaN
|
|
353
356
|
* positions as *absent* points, so they must never reach setPointPositions.
|
|
354
357
|
* Known positions pass through verbatim (same array when nothing to seed).
|
package/dist/index.js
CHANGED
|
@@ -67,21 +67,21 @@ var DEFAULT_SPACE_SIZE = 4096;
|
|
|
67
67
|
var DEFAULT_RESTORE_DEADLINE_MS = 1e4;
|
|
68
68
|
var CosmosEngine = class {
|
|
69
69
|
capabilities = {
|
|
70
|
-
// Evidence-backed
|
|
70
|
+
// Evidence-backed flip: the probe measured native onLinkClick/
|
|
71
71
|
// onLinkMouseOver delivering correct link indices with ~4px perpendicular
|
|
72
|
-
// tolerance
|
|
72
|
+
// tolerance.
|
|
73
73
|
linkPicking: true,
|
|
74
74
|
rangeUpdates: [],
|
|
75
75
|
trackedPositions: true,
|
|
76
76
|
simulation: true,
|
|
77
|
-
//
|
|
77
|
+
// cosmos 3.3.0 exposes the `linkDefaultArrows` config key
|
|
78
78
|
// (config.d.ts) — instanced arrowheads toggle atomically via setConfigPartial.
|
|
79
79
|
edgeArrows: true,
|
|
80
|
-
//
|
|
80
|
+
// cosmos 3.3.0 exposes setImageData(ImageData[]) +
|
|
81
81
|
// setPointImageIndices(Float32Array) (index.d.ts) — per-point sprites via
|
|
82
82
|
// an adapter-maintained slot→ImageData atlas.
|
|
83
83
|
pointImages: true,
|
|
84
|
-
//
|
|
84
|
+
// stage 4: cosmos 3.3.0 ships a real GPU cluster force
|
|
85
85
|
// `setPointClusters((number|undefined)[])`, `setClusterPositions(
|
|
86
86
|
// (number|undefined)[])`, `setPointClusterStrength(Float32Array)`
|
|
87
87
|
// (index.d.ts) plus the `simulationCluster` coefficient (config.d.ts,
|
|
@@ -89,14 +89,14 @@ var CosmosEngine = class {
|
|
|
89
89
|
// `undefined` is cosmos' documented "not in any cluster" value, which the
|
|
90
90
|
// adapter maps from the contract's NaN.
|
|
91
91
|
clusterForce: true,
|
|
92
|
-
//
|
|
92
|
+
// stop-at-rest: cosmos 3.4.0 ships on-demand rendering — the M0
|
|
93
93
|
// quiescence row measured 0 idle frames AND 0 rAF registrations per
|
|
94
|
-
// 750ms at rest
|
|
95
|
-
// The adapter's own activity clock is gated to match
|
|
94
|
+
// 750ms at rest.
|
|
95
|
+
// The adapter's own activity clock is gated to match.
|
|
96
96
|
idleFrames: "stops",
|
|
97
97
|
// onFrame is an activity clock, not an exact post-draw hook — cosmos
|
|
98
98
|
// still exposes no public frame hook (probe `post-draw-frames`);
|
|
99
|
-
// overlays may lag one sample
|
|
99
|
+
// overlays may lag one sample.
|
|
100
100
|
postDrawFrames: false
|
|
101
101
|
};
|
|
102
102
|
options;
|
|
@@ -118,7 +118,7 @@ var CosmosEngine = class {
|
|
|
118
118
|
/** Sticky override from EngineConfigUpdate.seedRadius. */
|
|
119
119
|
seedRadiusOverride;
|
|
120
120
|
/** Point count of the last structure-bearing commit — the roster length a
|
|
121
|
-
* `cluster: null` clear must write an all-unclustered array for
|
|
121
|
+
* `cluster: null` clear must write an all-unclustered array for. */
|
|
122
122
|
lastPointCount = 0;
|
|
123
123
|
/**
|
|
124
124
|
* cosmos fires `onClick` (index undefined) AND `onBackgroundClick` for the
|
|
@@ -129,6 +129,9 @@ var CosmosEngine = class {
|
|
|
129
129
|
dragIndex = null;
|
|
130
130
|
/** Last hover reported by cosmos — fallback dragged-point source. */
|
|
131
131
|
lastHoverIndex = null;
|
|
132
|
+
/** Live native link hover gates the unified onClick's
|
|
133
|
+
* background interpretation — a hovered link owns the click). */
|
|
134
|
+
hoveredLinkIndex = null;
|
|
132
135
|
// --- adapter-owned GATED overlay/activity clock (see module header) ---
|
|
133
136
|
/** rAF id of the pending activity-clock tick; null = clock not running. */
|
|
134
137
|
frameHandle = null;
|
|
@@ -140,7 +143,7 @@ var CosmosEngine = class {
|
|
|
140
143
|
pendingTicks = 0;
|
|
141
144
|
/** One-shot guard for the repulsionTheta deprecation diagnostic. */
|
|
142
145
|
repulsionThetaWarned = false;
|
|
143
|
-
// --- WebGL context-loss recovery state
|
|
146
|
+
// --- WebGL context-loss recovery state ---
|
|
144
147
|
/** cosmos' canvas (queried post-mount) carrying the webglcontext* listeners. */
|
|
145
148
|
canvas = null;
|
|
146
149
|
contextLost = false;
|
|
@@ -149,7 +152,7 @@ var CosmosEngine = class {
|
|
|
149
152
|
deadline = null;
|
|
150
153
|
/** Graph constructor cached at mount so recovery never re-imports cosmos. */
|
|
151
154
|
cosmosCtor = null;
|
|
152
|
-
// ---
|
|
155
|
+
// --- image atlas (capability pointImages) ---
|
|
153
156
|
/**
|
|
154
157
|
* slot → ImageData mirror of the cosmos image atlas. ImageData is CPU-side,
|
|
155
158
|
* so the mirror survives context loss — any post-restore atlas commit
|
|
@@ -259,7 +262,7 @@ var CosmosEngine = class {
|
|
|
259
262
|
* zoom — `setViewport(p)` then `getViewport()` returns p, modulo cosmos'
|
|
260
263
|
* d3 scaleExtent clamp. A missing x or y is filled from the current
|
|
261
264
|
* viewport; zoom-only calls keep the `setZoomLevel` path (d3's scaleTo
|
|
262
|
-
* preserves the current center). Instant unless `durationMs` is given
|
|
265
|
+
* preserves the current center). Instant unless `durationMs` is given
|
|
263
266
|
* cosmos' own default duration is 250 ms, which would animate context-
|
|
264
267
|
* recovery replays.
|
|
265
268
|
*/
|
|
@@ -320,7 +323,7 @@ var CosmosEngine = class {
|
|
|
320
323
|
});
|
|
321
324
|
this.requestTicks(2);
|
|
322
325
|
}
|
|
323
|
-
// --- spatial queries & pinning
|
|
326
|
+
// --- spatial queries & pinning ---
|
|
324
327
|
pointsInPolygon(screenPolygon) {
|
|
325
328
|
const graph = this.activeGraph;
|
|
326
329
|
if (!graph) return [];
|
|
@@ -358,7 +361,7 @@ var CosmosEngine = class {
|
|
|
358
361
|
return graph ? Float32Array.from(graph.getPointPositions()) : null;
|
|
359
362
|
}
|
|
360
363
|
/**
|
|
361
|
-
* Captures the cosmos canvas via the
|
|
364
|
+
* Captures the cosmos canvas via the same-tick method (see module
|
|
362
365
|
* header): one rAF is scheduled and, inside that tick, the WebGL canvas is
|
|
363
366
|
* drawn synchronously onto an offscreen 2D canvas (cosmos renders with
|
|
364
367
|
* preserveDrawingBuffer:false, so the buffer is only readable same-tick).
|
|
@@ -425,13 +428,13 @@ var CosmosEngine = class {
|
|
|
425
428
|
// --- gated overlay/activity clock (see module header) ---
|
|
426
429
|
/**
|
|
427
430
|
* One rAF tick of the gated activity clock. Ordering is load-bearing:
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
431
|
+
* 1. the tick budget is consumed BEFORE the host callback runs, so work
|
|
432
|
+
* scheduled from inside onFrame re-arms a fresh tick instead of being
|
|
433
|
+
* coalesced away;
|
|
434
|
+
* 2. the reschedule/stop decision is made BEFORE the host callback, so a
|
|
435
|
+
* throwing host can never kill a should-keep-running clock (and a
|
|
436
|
+
* stopping clock stays stopped even if the callback wakes it — the
|
|
437
|
+
* wake starts a new loop via requestTicks/wake, not this handle).
|
|
435
438
|
* Skips the callback (but keeps its schedule) while the document is hidden.
|
|
436
439
|
*/
|
|
437
440
|
frameTick = (timeMs) => {
|
|
@@ -485,14 +488,14 @@ var CosmosEngine = class {
|
|
|
485
488
|
this.runReasons.clear();
|
|
486
489
|
this.pendingTicks = 0;
|
|
487
490
|
}
|
|
488
|
-
// --- WebGL context-loss recovery
|
|
491
|
+
// --- WebGL context-loss recovery ---
|
|
489
492
|
/** The graph, unless it is unusable (context lost / terminally failed). */
|
|
490
493
|
get activeGraph() {
|
|
491
494
|
return this.contextLost || this.failed ? null : this.graph;
|
|
492
495
|
}
|
|
493
496
|
/**
|
|
494
497
|
* cosmos owns its canvas; we can only wire webglcontext* listeners after
|
|
495
|
-
* init by querying it. A missing canvas downgrades to an info diagnostic
|
|
498
|
+
* init by querying it. A missing canvas downgrades to an info diagnostic
|
|
496
499
|
* the engine keeps working, just without context-loss recovery.
|
|
497
500
|
*/
|
|
498
501
|
attachContextListeners() {
|
|
@@ -666,21 +669,23 @@ var CosmosEngine = class {
|
|
|
666
669
|
// cosmos 3.4 defaults this to true. Pinned OFF for the 3.4 upgrade:
|
|
667
670
|
// occlusion culling changes which overlapping pixels draw, and the M5
|
|
668
671
|
// pixel-diff thresholds (CHANGED_MIN/RESTORED_MAX) were tuned against
|
|
669
|
-
// un-culled rendering.
|
|
670
|
-
//
|
|
672
|
+
// un-culled rendering. Keep one variable at a time; enabling culling
|
|
673
|
+
// requires its own threshold re-validation.
|
|
671
674
|
pointOcclusionCulling: false,
|
|
672
|
-
// Native point dragging; the core owns pin semantics on top
|
|
675
|
+
// Native point dragging; the core owns pin semantics on top.
|
|
673
676
|
enableDrag: this.options.enableDrag ?? true,
|
|
674
677
|
onPointClick: (index, _position, event) => {
|
|
675
678
|
this.events?.onPointClick?.(index, clickModifiers(event));
|
|
676
679
|
},
|
|
677
680
|
onBackgroundClick: (event) => {
|
|
678
|
-
this.emitNullPointClick(event);
|
|
681
|
+
if (this.hoveredLinkIndex === null) this.emitNullPointClick(event);
|
|
679
682
|
},
|
|
680
683
|
// onClick fires for every canvas click; an undefined index means no
|
|
681
684
|
// point was hit (background clicks — link clicks arrive via onLinkClick).
|
|
682
685
|
onClick: (index, _position, event) => {
|
|
683
|
-
if (index === void 0
|
|
686
|
+
if (index === void 0 && this.hoveredLinkIndex === null) {
|
|
687
|
+
this.emitNullPointClick(event);
|
|
688
|
+
}
|
|
684
689
|
},
|
|
685
690
|
// Unified context-menu channel: fires exactly once per gesture (desktop
|
|
686
691
|
// right-click AND touch long-press — cosmos synthesizes the latter);
|
|
@@ -705,10 +710,12 @@ var CosmosEngine = class {
|
|
|
705
710
|
this.events?.onLinkClick?.(linkIndex);
|
|
706
711
|
},
|
|
707
712
|
onLinkMouseOver: (linkIndex) => {
|
|
713
|
+
this.hoveredLinkIndex = linkIndex;
|
|
708
714
|
this.requestTicks(1);
|
|
709
715
|
this.events?.onLinkHover?.(linkIndex);
|
|
710
716
|
},
|
|
711
717
|
onLinkMouseOut: () => {
|
|
718
|
+
this.hoveredLinkIndex = null;
|
|
712
719
|
this.requestTicks(1);
|
|
713
720
|
this.events?.onLinkHover?.(null);
|
|
714
721
|
},
|
|
@@ -726,7 +733,7 @@ var CosmosEngine = class {
|
|
|
726
733
|
this.requestTicks(2);
|
|
727
734
|
this.emitViewportChange();
|
|
728
735
|
},
|
|
729
|
-
// --- gated-clock run reasons
|
|
736
|
+
// --- gated-clock run reasons ---
|
|
730
737
|
onSimulationStart: () => {
|
|
731
738
|
this.wake("sim");
|
|
732
739
|
},
|
|
@@ -826,8 +833,8 @@ var CosmosEngine = class {
|
|
|
826
833
|
if (viewport) this.events?.onViewportChange?.(viewport);
|
|
827
834
|
}
|
|
828
835
|
/**
|
|
829
|
-
* One visibly atomic update
|
|
830
|
-
* exactly one render
|
|
836
|
+
* One visibly atomic update: all channels and config are staged, then
|
|
837
|
+
* exactly one render draws them; restart reheats after the render.
|
|
831
838
|
*/
|
|
832
839
|
applyCommit(graph, update) {
|
|
833
840
|
const { config, structure, buffers, resources, restart } = update;
|
|
@@ -902,17 +909,17 @@ var CosmosEngine = class {
|
|
|
902
909
|
this.requestTicks(2);
|
|
903
910
|
}
|
|
904
911
|
/**
|
|
905
|
-
* Applies the
|
|
912
|
+
* Applies the stage-4 cluster force (capability `clusterForce`).
|
|
906
913
|
*
|
|
907
914
|
* Contract mapping, verified against the 3.3.0 dist (`index.d.ts`):
|
|
908
|
-
*
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
915
|
-
*
|
|
915
|
+
* - `pointClusters` (Float32Array, NaN = unclustered) →
|
|
916
|
+
* `setPointClusters((number | undefined)[])`, where cosmos' documented
|
|
917
|
+
* "does not belong to any cluster" value is `undefined`;
|
|
918
|
+
* - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →
|
|
919
|
+
* `setClusterPositions((number | undefined)[])`; a non-finite entry means
|
|
920
|
+
* "no position" and cosmos falls back to that cluster's centermass;
|
|
921
|
+
* - `null` clears: an all-`undefined` array of the CURRENT roster length
|
|
922
|
+
* (length must track the roster) plus empty cluster positions.
|
|
916
923
|
* `strength` is the scene-wide `simulationCluster` config coefficient
|
|
917
924
|
* applied in the config block, not the per-point
|
|
918
925
|
* `setPointClusterStrength` buffer (Orbit's strength is scene-wide).
|
|
@@ -941,12 +948,12 @@ var CosmosEngine = class {
|
|
|
941
948
|
}
|
|
942
949
|
}
|
|
943
950
|
/**
|
|
944
|
-
* Applies the
|
|
951
|
+
* Applies the image-atlas channel: upserts convert ImageBitmap →
|
|
945
952
|
* ImageData through an offscreen 2D canvas into the slot mirror, removals
|
|
946
953
|
* blank their slot, and any atlas change re-uploads the FULL ImageData
|
|
947
954
|
* array (cosmos' setImageData is whole-array only, matching
|
|
948
955
|
* `rangeUpdates: []`). Environments without a usable 2D context (jsdom)
|
|
949
|
-
* no-op the channel and report `engine:image-channel-unavailable` once
|
|
956
|
+
* no-op the channel and report `engine:image-channel-unavailable` once
|
|
950
957
|
* never throw.
|
|
951
958
|
*/
|
|
952
959
|
applyResources(graph, resources) {
|
|
@@ -992,7 +999,7 @@ var CosmosEngine = class {
|
|
|
992
999
|
/**
|
|
993
1000
|
* Reads an ImageData of the given size off an offscreen 2D canvas, drawing
|
|
994
1001
|
* `bitmap` onto it first when provided (ImageBitmap → ImageData transcode;
|
|
995
|
-
* without a bitmap: a transparent blank). Returns null — never throws
|
|
1002
|
+
* without a bitmap: a transparent blank). Returns null — never throws
|
|
996
1003
|
* where no 2D context exists (jsdom without the canvas package).
|
|
997
1004
|
*/
|
|
998
1005
|
canvasImageData(width, height, bitmap) {
|
|
@@ -1021,7 +1028,7 @@ var CosmosEngine = class {
|
|
|
1021
1028
|
});
|
|
1022
1029
|
}
|
|
1023
1030
|
/**
|
|
1024
|
-
* Replaces NaN pairs (= "no known position"
|
|
1031
|
+
* Replaces NaN pairs (= "no known position") with random points on a
|
|
1025
1032
|
* ring of radius seedRadius around the space center. cosmos treats NaN
|
|
1026
1033
|
* positions as *absent* points, so they must never reach setPointPositions.
|
|
1027
1034
|
* Known positions pass through verbatim (same array when nothing to seed).
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/restoreDeadline.ts","../src/CosmosEngine.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * RestoreDeadline — a visibility-aware countdown used while a WebGL context is\n * lost. Browsers routinely defer `webglcontextrestored` for backgrounded tabs,\n * so the budget must only burn while the document is visible: hidden time is\n * banked (timer cleared, remaining ms kept) and the countdown re-arms from the\n * remainder when the tab becomes visible again.\n */\nexport class RestoreDeadline {\n private timer: ReturnType<typeof setTimeout> | null = null;\n /** Unspent budget in ms; recomputed each time the timer is disarmed. */\n private remaining: number;\n /** Timestamp when the current timer was armed (for banking on hide). */\n private armedAt = 0;\n private started = false;\n /** Terminal: set on expiry or cancel; guarantees onExpire fires at most once. */\n private done = false;\n\n private readonly handleVisibilityChange = (): void => {\n if (this.done) return;\n if (this.doc.visibilityState === 'visible') this.arm();\n else this.disarm();\n };\n\n constructor(\n private readonly doc: Document,\n ms: number,\n private readonly onExpire: () => void,\n ) {\n this.remaining = ms;\n }\n\n start(): void {\n if (this.done || this.started) return;\n this.started = true;\n this.doc.addEventListener('visibilitychange', this.handleVisibilityChange);\n if (this.doc.visibilityState === 'visible') this.arm();\n }\n\n cancel(): void {\n if (this.done) return;\n this.done = true;\n if (this.timer !== null) {\n globalThis.clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.started) {\n this.doc.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n }\n\n private arm(): void {\n if (this.timer !== null) return;\n this.armedAt = Date.now();\n this.timer = globalThis.setTimeout(() => {\n this.timer = null;\n this.done = true;\n this.doc.removeEventListener('visibilitychange', this.handleVisibilityChange);\n this.onExpire();\n }, this.remaining);\n }\n\n private disarm(): void {\n if (this.timer === null) return;\n globalThis.clearTimeout(this.timer);\n this.timer = null;\n this.remaining = Math.max(0, this.remaining - (Date.now() - this.armedAt));\n }\n}\n","/**\n * CosmosEngine — GraphEngine adapter over @cosmos.gl/graph (spec §13).\n *\n * Node-safe module: cosmos is loaded lazily via `await import()` inside\n * `mount()` (§18); module scope carries only type-only imports (erased at\n * runtime) and never touches the DOM.\n *\n * Color scale note: the EngineCommit contract carries RGBA floats in [0,1],\n * which is exactly cosmos' native scale (verified against the 3.3.0 dist:\n * hex config colors are parsed via /255 into 0–1 floats and setPointColors\n * input is fed to GPU buffers untouched) — so color buffers pass through.\n *\n * Interaction notes (verified against the 3.3.0 dist):\n * - Link picking is native: setting any onLink* config callback flips\n * cosmos' internal `isLinkHoveringEnabled` on, so wiring the callbacks in\n * `buildInitialConfig` is sufficient (no extra config flag exists).\n * - `findPointsInPolygon` takes SCREEN coordinates (\"from 0 to the\n * width/height of the canvas\" per dist/index.d.ts), so `pointsInPolygon`\n * passes the host's screen polygon through without conversion.\n * - `findPointsInRect` uses the SAME screen space and expects ordered\n * corners `[[left, top], [right, bottom]]` (the dist flips Y assuming that\n * ordering), so `pointsInRect` normalizes the host's [x0,y0,x1,y1] rect to\n * min/max corners and passes it through without conversion.\n * - Camera pan (S11 — the zoom-only limitation is LIFTED): cosmos 3.3 has no\n * pan-to API, but `setZoomTransformByPointPositions(positions, duration,\n * scale, padding)` (dist/index.d.ts) is an exact center+zoom when `scale`\n * is explicit. Derivation from the dist (`zoomInstance.getTransform`):\n * space→screen-at-k=1 goes through `store.scaleX/scaleY`, which are LINEAR\n * with slope ±1 (scaleX(x) = x + (w−S)/2; scaleY(y) = (S−y) + (h−S)/2,\n * S = adjustedSpaceSize, w/h = canvas size); a single-point bbox is widened\n * ±0.5 SYMMETRICALLY (center preserved); an explicit `scale` bypasses the\n * fit math and `padding` entirely — k = clamp(scale, d3 scaleExtent) and\n * the result is translate(w/2 − scaleX(x)·k, h/2 − scaleY(y)·k).scale(k),\n * i.e. space point (x, y) lands exactly at the screen center with\n * eventTransform.k = scale. Since `getZoomLevel()` returns eventTransform.k\n * and `getViewport()` reads screenToSpacePosition(screen center),\n * `setViewport({x, y, zoom})` → setZoomTransformByPointPositions(\n * Float32Array.of(x, y), durationMs ?? 0, zoom ?? getZoomLevel()) makes a\n * follow-up `getViewport()` return exactly {x, y, zoom} (modulo the\n * scaleExtent clamp). This also completes §13.1 recovery: the core replays\n * the full stored {x, y, zoom} through setViewport, so viewport restore is\n * no longer zoom-only.\n * - Context menu: cosmos fires the unified config `onContextMenu(index |\n * undefined, pos, event)` exactly ONCE per gesture — desktop right-click\n * (dist `onContextMenu(e)`) and touch/pen long-press (dist long-press timer\n * → `fireContextMenu`) both route through it — while the per-target\n * `onPointContextMenu`/`onLinkContextMenu`/`onBackgroundContextMenu`\n * callbacks fire ADDITIONALLY for the same gesture. Wiring only the unified\n * callback therefore avoids a double-report (same shape as the\n * onClick/onBackgroundClick dedupe). A context menu over a LINK arrives\n * with index undefined and is reported as background (the host event\n * carries node-or-background only).\n *\n * GATED overlay/activity clock (ADR-005; M0 evidence docs/m0-conformance.md):\n * cosmos still exposes no draw/render-phase hook (`postDrawFrames: false`),\n * so the adapter owns the single requestAnimationFrame loop that reports\n * `onFrame(timeMs)` to the host — an ACTIVITY clock, not a post-draw hook:\n * overlays may lag the canvas by one sample (reported once at mount via\n * `engine:overlay-activity-clock`). Since cosmos 3.4 idle-stops its own\n * rendering (on-demand rendering, quiescence probe: 0 idle frames/750ms),\n * this clock is GATED to match — it free-runs only while a run reason is\n * held (sim hot via onSimulationStart/Pause/Unpause/End, drag gestures,\n * cosmos transitions) and otherwise burns a small one-shot tick budget that\n * every visual write re-arms (commits, highlight/focus/pin setters, camera\n * moves, hover events; animated camera moves self-sustain through per-step\n * onZoom bursts). Releasing a run reason always grants ONE trailing tick —\n * the releasing activity's final GPU write lands after the current draw\n * pass. At rest: zero rAF registrations from cosmos AND from this adapter\n * (`capabilities.idleFrames: 'stops'`). The clock stops on context\n * loss/destroy, re-arms on recovery, and skips the callback (keeping its\n * schedule) while `document.hidden`.\n *\n * Screenshots use the M0 same-tick capture method (apps/spike/src/instrument.ts):\n * cosmos renders with preserveDrawingBuffer:false, so the WebGL buffer is only\n * readable via a synchronous drawImage inside the same rAF tick it was drawn —\n * `captureScreenshot` schedules one rAF, draws the cosmos canvas onto an\n * offscreen 2D canvas inside that tick, and resolves the Blob (null on any\n * failure or unusable lifecycle state).\n * - The D3 drag events carry NO point index (the drag subject is a bare\n * `{x, y}`); cosmos assigns `store.draggingPointIndex` immediately before\n * invoking `onDragStart`, so the adapter reads it there (see\n * `readDraggingIndex` for the public-callback fallback).\n * - During a drag, cosmos' drag shader hard-pins the dragged point's\n * position texture entry to the mouse's SPACE position every frame\n * (dist `drag()`: `pointPosition.rg = mousePos` where `mousePos` =\n * screenToSpace(pointer)). So the point's final space position equals\n * `screenToSpacePosition([event.x, event.y])` at drag end — an O(1) CPU\n * transform, chosen over `getPointPositions()` (full GPU readback).\n */\n\nimport type { Graph as CosmosGraph, GraphConfig } from '@cosmos.gl/graph';\nimport type {\n EngineCapabilities,\n EngineCommit,\n EngineHostEvents,\n FitViewOptions,\n GraphEngine,\n} from '@modernrelay/orbit-core/engine';\nimport { RestoreDeadline } from './restoreDeadline';\n\n/** Derived from the contract to avoid importing the core root barrel. */\ntype ViewportState = NonNullable<ReturnType<GraphEngine['getViewport']>>;\n\n/**\n * Structural view of cosmos' `graph.store` — private in the 3.3.0 d.ts but a\n * stable runtime field. `draggingPointIndex` is assigned right before cosmos\n * invokes `onDragStart` (verified in the dist), making it the authoritative\n * dragged-point source; `hoveredPoint` mirrors the public onPointMouseOver\n * payload.\n */\ninterface CosmosStoreLike {\n hoveredPoint?: { index: number; position: [number, number] };\n draggingPointIndex?: number;\n}\n\n/**\n * Extracts click modifiers from a cosmos-forwarded event. Duck-typed rather\n * than `instanceof MouseEvent`: node-safe and cross-realm-safe. Returns\n * undefined when the event carries no modifier state.\n */\nfunction clickModifiers(event: unknown): { metaKey: boolean; shiftKey: boolean } | undefined {\n const e = event as { metaKey?: unknown; shiftKey?: unknown } | null | undefined;\n if (e && typeof e.metaKey === 'boolean' && typeof e.shiftKey === 'boolean') {\n return { metaKey: e.metaKey, shiftKey: e.shiftKey };\n }\n return undefined;\n}\n\nexport interface CosmosEngineOptions {\n /** Simulation space size passed to cosmos (cosmos default: 4096). */\n spaceSize?: number;\n /** Ring radius for seeding unknown (NaN) positions. Default: spaceSize/4. */\n seedRadius?: number;\n /** Whether cosmos auto-fits the view on init. Default: false (the core drives the camera). */\n fitViewOnInit?: boolean;\n /** Native point dragging (cosmos `enableDrag`). Default: true. */\n enableDrag?: boolean;\n /** Escape hatch: shallow-merged last into the cosmos constructor config. */\n initialConfig?: Record<string, unknown>;\n /**\n * Visible-time budget (ms) for the browser to restore a lost WebGL context\n * before an `engine:context-restore-deadline` diagnostic is emitted. The\n * deadline is observability only — a later restore still recovers.\n * Default: 10_000.\n */\n restoreDeadlineMs?: number;\n}\n\n/** cosmos' own default `spaceSize` (see @cosmos.gl/graph config defaults). */\nconst DEFAULT_SPACE_SIZE = 4096;\n\n/** Default visible-time budget before the restore-deadline diagnostic. */\nconst DEFAULT_RESTORE_DEADLINE_MS = 10_000;\n\n/** §8 image-atlas channel of an EngineCommit (adapter-local alias). */\ntype EngineResources = NonNullable<EngineCommit['resources']>;\n\nexport class CosmosEngine implements GraphEngine {\n readonly capabilities: EngineCapabilities = {\n // Evidence-backed S6 flip: the M0 probe measured native onLinkClick/\n // onLinkMouseOver delivering correct link indices with ~4px perpendicular\n // tolerance (docs/m0-conformance.json, `link-picking`).\n linkPicking: true,\n rangeUpdates: [],\n trackedPositions: true,\n simulation: true,\n // §16.12: cosmos 3.3.0 exposes the `linkDefaultArrows` config key\n // (config.d.ts) — instanced arrowheads toggle atomically via setConfigPartial.\n edgeArrows: true,\n // §8: cosmos 3.3.0 exposes setImageData(ImageData[]) +\n // setPointImageIndices(Float32Array) (index.d.ts) — per-point sprites via\n // an adapter-maintained slot→ImageData atlas.\n pointImages: true,\n // §16.3 stage 4: cosmos 3.3.0 ships a real GPU cluster force —\n // `setPointClusters((number|undefined)[])`, `setClusterPositions(\n // (number|undefined)[])`, `setPointClusterStrength(Float32Array)`\n // (index.d.ts) plus the `simulationCluster` coefficient (config.d.ts,\n // default 0.1) and the `Clusters` core module (dist/modules/Clusters).\n // `undefined` is cosmos' documented \"not in any cluster\" value, which the\n // adapter maps from the contract's NaN.\n clusterForce: true,\n // §17 stop-at-rest: cosmos 3.4.0 ships on-demand rendering — the M0\n // quiescence row measured 0 idle frames AND 0 rAF registrations per\n // 750ms at rest (docs/m0-conformance.md, was 91 on 3.3.0/ADR-002).\n // The adapter's own activity clock is gated to match (ADR-005).\n idleFrames: 'stops',\n // onFrame is an activity clock, not an exact post-draw hook — cosmos\n // still exposes no public frame hook (probe `post-draw-frames`);\n // overlays may lag one sample (ADR-002).\n postDrawFrames: false,\n };\n\n private readonly options: CosmosEngineOptions;\n private graph: CosmosGraph | null = null;\n private innerDiv: HTMLDivElement | null = null;\n private events: EngineHostEvents | null = null;\n /**\n * Pre-mount/lost-context commits collapse per channel and are applied as one\n * atomic commit once a usable graph exists.\n */\n private pendingCommit: EngineCommit | null = null;\n private applied: number | null = null;\n private destroyed = false;\n private mounting = false;\n /** Constructed graph whose `ready` promise has not settled yet. */\n private graphAwaitingReady: CosmosGraph | null = null;\n /** Guards every graph teardown, including async init/recovery races. */\n private readonly destroyedGraphs = new WeakSet<CosmosGraph>();\n /** Sticky override from EngineConfigUpdate.seedRadius. */\n private seedRadiusOverride: number | undefined;\n /** Point count of the last structure-bearing commit — the roster length a\n * `cluster: null` clear must write an all-unclustered array for (§16.3). */\n private lastPointCount = 0;\n /**\n * cosmos fires `onClick` (index undefined) AND `onBackgroundClick` for the\n * same background click; remembering the MouseEvent dedupes the null emit.\n */\n private lastNullClickEvent: unknown = null;\n /** Point latched at cosmos onDragStart; cleared when the gesture ends. */\n private dragIndex: number | null = null;\n /** Last hover reported by cosmos — fallback dragged-point source. */\n private lastHoverIndex: number | null = null;\n\n // --- adapter-owned GATED overlay/activity clock (see module header) ---\n\n /** rAF id of the pending activity-clock tick; null = clock not running. */\n private frameHandle: number | null = null;\n /** Window driving the clock, cached so stop works after the div detaches. */\n private frameWindow: Window | null = null;\n /** Continuous-run reasons; the clock free-runs while any is held. */\n private readonly runReasons = new Set<'sim' | 'drag' | 'transition'>();\n /** One-shot tick budget for write/interaction re-arm bursts. */\n private pendingTicks = 0;\n /** One-shot guard for the repulsionTheta deprecation diagnostic. */\n private repulsionThetaWarned = false;\n\n // --- WebGL context-loss recovery state (§13.1) ---\n\n /** cosmos' canvas (queried post-mount) carrying the webglcontext* listeners. */\n private canvas: HTMLCanvasElement | null = null;\n private contextLost = false;\n /** Terminal: GL reinitialization failed; commits stash inertly forever. */\n private failed = false;\n private deadline: RestoreDeadline | null = null;\n /** Graph constructor cached at mount so recovery never re-imports cosmos. */\n private cosmosCtor: (new (div: HTMLDivElement, config?: GraphConfig) => CosmosGraph) | null =\n null;\n\n // --- §8 image atlas (capability pointImages) ---\n\n /**\n * slot → ImageData mirror of the cosmos image atlas. ImageData is CPU-side,\n * so the mirror survives context loss — any post-restore atlas commit\n * re-uploads the FULL array to the fresh graph. `null` = removed (blank).\n */\n private imageSlots: (ImageData | null)[] = [];\n /** Lazily created 1×1 transparent entry filling removed/hole slots. */\n private blankImage: ImageData | null = null;\n /** One-shot guard for the `engine:image-channel-unavailable` diagnostic. */\n private imageChannelUnavailable = false;\n\n constructor(options: CosmosEngineOptions = {}) {\n this.options = options;\n }\n\n async mount(container: HTMLElement, events: EngineHostEvents): Promise<void> {\n if (this.destroyed) throw new Error('CosmosEngine: mount() after destroy()');\n if (this.mounting || this.graph) throw new Error('CosmosEngine: mount() may only be called once');\n this.mounting = true;\n this.events = events;\n\n // cosmos wants a dedicated HTMLDivElement filling the host container.\n const div = container.ownerDocument.createElement('div');\n div.style.width = '100%';\n div.style.height = '100%';\n container.appendChild(div);\n this.innerDiv = div;\n\n let graph: CosmosGraph | null = null;\n try {\n // §18: cosmos (and its WebGL dependencies) load only at mount time.\n const { Graph } = await import('@cosmos.gl/graph');\n // destroy() may have landed while the dynamic import was pending.\n if (this.destroyed) {\n div.remove();\n return;\n }\n graph = new Graph(div, this.buildInitialConfig());\n this.graphAwaitingReady = graph;\n await graph.ready;\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n if (this.destroyed) {\n // destroy() raced the async init; tear the graph down immediately.\n this.destroyGraphOnce(graph);\n div.remove();\n return;\n }\n this.graph = graph;\n this.cosmosCtor = Graph;\n this.attachContextListeners();\n // Documented degradation (M0): overlays ride an activity clock because\n // cosmos has no draw-phase hook. Emitted once, at mount only.\n events.onDiagnostic?.({\n code: 'engine:overlay-activity-clock',\n severity: 'info',\n message:\n 'CosmosEngine: cosmos exposes no draw-phase hook (postDrawFrames:false); ' +\n 'overlays ride an adapter-owned, idle-gated requestAnimationFrame activity ' +\n 'clock (stops at rest — idleFrames:stops) and may lag the canvas by one frame.',\n });\n // cosmos 3.4 keeps rendering when the FPS monitor is shown — that\n // silently defeats the idleFrames:'stops' declaration, so say so once.\n if ((this.options.initialConfig as GraphConfig | undefined)?.showFPSMonitor) {\n events.onDiagnostic?.({\n code: 'engine:fps-monitor-defeats-quiescence',\n severity: 'info',\n message:\n 'CosmosEngine: showFPSMonitor keeps cosmos rendering every frame; ' +\n 'stop-at-rest quiescence is disabled while it is shown.',\n });\n }\n // Gated clock: no unconditional start — cosmos draws its own init\n // frame; a short burst lets overlays sample it, then the clock stops\n // until a wake source (commit/sim/gesture) re-arms it.\n this.requestTicks(2);\n const pending = this.pendingCommit;\n this.pendingCommit = null;\n if (pending) this.applyCommit(graph, pending);\n } catch (err) {\n if (graph !== null) {\n if (this.graph === graph) {\n this.stopFrameLoop();\n this.detachContextListeners();\n this.graph = null;\n }\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n this.destroyGraphOnce(graph);\n }\n div.remove();\n if (this.innerDiv === div) this.innerDiv = null;\n // destroy() is terminal and already cleaned up the constructed graph;\n // a later ready rejection must not escape or notify stale hosts.\n if (this.destroyed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n events.onError?.(error);\n throw error;\n }\n }\n\n commit(update: EngineCommit): void {\n if (this.destroyed) throw new Error('CosmosEngine: commit() after destroy()');\n const graph = this.activeGraph;\n if (!graph) {\n // Pre-mount, context-lost, or failed: retain the latest value of every\n // independently replaceable channel. The merged commit is flushed on\n // mount/restore (or remains inert forever after terminal failure).\n this.queueCommit(update);\n return;\n }\n this.applyCommit(graph, update);\n }\n\n appliedRevision(): number | null {\n return this.applied;\n }\n\n // --- camera ---\n // Every camera write re-arms the clock; ANIMATED moves then self-sustain\n // through cosmos' per-step onZoom events (each grants a fresh burst), so\n // no duration bookkeeping is needed here.\n\n fitView(opts?: FitViewOptions): void {\n this.activeGraph?.fitView(opts?.durationMs, opts?.padding);\n this.requestTicks(2);\n }\n\n zoom(factor: number, durationMs?: number): void {\n const graph = this.activeGraph;\n if (!graph) return;\n graph.setZoomLevel(graph.getZoomLevel() * factor, durationMs);\n this.requestTicks(2);\n }\n\n /**\n * REAL pan (the former zoom-only limitation is lifted — see module header):\n * when a target center is provided, one `setZoomTransformByPointPositions`\n * call centers space point (x, y) at EXACTLY the requested (or current)\n * zoom — `setViewport(p)` then `getViewport()` returns p, modulo cosmos'\n * d3 scaleExtent clamp. A missing x or y is filled from the current\n * viewport; zoom-only calls keep the `setZoomLevel` path (d3's scaleTo\n * preserves the current center). Instant unless `durationMs` is given —\n * cosmos' own default duration is 250 ms, which would animate context-\n * recovery replays.\n */\n setViewport(v: Partial<ViewportState>, opts?: { durationMs?: number }): void {\n const graph = this.activeGraph;\n if (!graph) return;\n if (v.x !== undefined || v.y !== undefined) {\n const current = v.x === undefined || v.y === undefined ? this.getViewport() : null;\n const x = v.x ?? current?.x;\n const y = v.y ?? current?.y;\n if (x !== undefined && y !== undefined) {\n graph.setZoomTransformByPointPositions(\n Float32Array.of(x, y),\n opts?.durationMs ?? 0,\n v.zoom ?? graph.getZoomLevel(),\n );\n this.requestTicks(2);\n return;\n }\n // No usable center (detached container): degrade to zoom-only below.\n }\n if (v.zoom !== undefined) graph.setZoomLevel(v.zoom, opts?.durationMs ?? 0);\n this.requestTicks(2);\n }\n\n getViewport(): ViewportState | null {\n const graph = this.activeGraph;\n const div = this.innerDiv;\n if (!graph || !div) return null;\n const [x, y] = graph.screenToSpacePosition([div.clientWidth / 2, div.clientHeight / 2]);\n return { x, y, zoom: graph.getZoomLevel() };\n }\n\n zoomToIndex(index: number, durationMs?: number): void {\n this.activeGraph?.zoomToPointByIndex(index, durationMs);\n this.requestTicks(2);\n }\n\n // --- simulation ---\n\n start(alpha?: number): void {\n // cosmos fires onSimulationStart (→ wake) — the direct wake covers a\n // callback wiring gap and is idempotent through the Set.\n this.wake('sim');\n this.activeGraph?.start(alpha);\n }\n\n pause(): void {\n this.sleep('sim');\n this.activeGraph?.pause();\n }\n\n // --- built-in interaction visuals ---\n\n setSelectedIndices(indices: readonly number[] | null): void {\n const graph = this.activeGraph;\n if (!graph) return;\n // cosmos 3.3 has no imperative select/unselect API; selection visuals are\n // config-driven — points NOT in `highlightedPointIndices` grey out, and an\n // explicit `undefined` resets the key (clears highlighting) per\n // setConfigPartial semantics.\n graph.setConfigPartial({\n highlightedPointIndices: indices === null ? undefined : Array.from(indices),\n } as unknown as GraphConfig);\n this.requestTicks(2); // §17 write re-arm: overlays sample the new state\n }\n\n setFocusedIndex(index: number | null): void {\n const graph = this.activeGraph;\n if (!graph) return;\n graph.setConfigPartial({\n focusedPointIndex: index === null ? undefined : index,\n } as unknown as GraphConfig);\n this.requestTicks(2);\n }\n\n // --- spatial queries & pinning (§13/§15) ---\n\n pointsInPolygon(screenPolygon: readonly [number, number][]): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos' findPointsInPolygon already expects SCREEN coordinates (0 to\n // canvas width/height per the 3.3.0 d.ts) — no conversion; copy the pairs\n // only to satisfy cosmos' mutable-signature and shield the caller's input.\n return graph.findPointsInPolygon(screenPolygon.map(([x, y]): [number, number] => [x, y]));\n }\n\n pointsInRect(screenRect: readonly [number, number, number, number]): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos' findPointsInRect expects SCREEN coordinates (0 to canvas\n // width/height — the same space as findPointsInPolygon per the 3.3.0\n // d.ts) as ordered corners [[left, top], [right, bottom]] (the dist flips\n // Y assuming that ordering) — normalize so any opposite-corner pair works.\n const [x0, y0, x1, y1] = screenRect;\n return graph.findPointsInRect([\n [Math.min(x0, x1), Math.min(y0, y1)],\n [Math.max(x0, x1), Math.max(y0, y1)],\n ]);\n }\n\n neighborIndices(index: number): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos dedupes but a self-loop can report the point as its own neighbor.\n return graph.getNeighboringPointIndices(index).filter((i) => i !== index);\n }\n\n screenToSpace(p: readonly [number, number]): [number, number] | null {\n const graph = this.activeGraph;\n return graph ? graph.screenToSpacePosition([p[0], p[1]]) : null;\n }\n\n spaceToScreen(p: readonly [number, number]): [number, number] | null {\n const graph = this.activeGraph;\n return graph ? graph.spaceToScreenPosition([p[0], p[1]]) : null;\n }\n\n setPinnedIndices(indices: readonly number[] | null): void {\n // Full-set replace, idempotent; null and [] both unpin all (cosmos treats\n // them identically). Pin re-application after recovery is core-owned.\n this.activeGraph?.setPinnedPoints(indices === null ? null : Array.from(indices));\n this.requestTicks(2);\n }\n\n // --- readback ---\n\n getPositions(): Float32Array | null {\n const graph = this.activeGraph;\n return graph ? Float32Array.from(graph.getPointPositions()) : null;\n }\n\n /**\n * Captures the cosmos canvas via the M0 same-tick method (see module\n * header): one rAF is scheduled and, inside that tick, the WebGL canvas is\n * drawn synchronously onto an offscreen 2D canvas (cosmos renders with\n * preserveDrawingBuffer:false, so the buffer is only readable same-tick).\n * Resolves null on any failure or unusable lifecycle state (pre-mount,\n * context lost/failed, destroyed, no 2D context, toBlob failure).\n */\n captureScreenshot(): Promise<Blob | null> {\n const graph = this.activeGraph;\n const canvas = graph ? this.canvas : null;\n const win = canvas?.ownerDocument.defaultView ?? null;\n if (!graph || !canvas || !win || typeof win.requestAnimationFrame !== 'function') {\n return Promise.resolve(null);\n }\n // Under on-demand rendering (cosmos >= 3.4) an idle scene draws nothing,\n // and with preserveDrawingBuffer:false an undrawn buffer reads blank —\n // render() is a visual mutator that schedules the frame our capture rAF\n // then samples same-tick.\n try {\n graph.render();\n } catch {\n return Promise.resolve(null);\n }\n return new Promise((resolve) => {\n win.requestAnimationFrame(() => {\n // Re-check: loss/destroy (or a restore swapping in a new canvas) may\n // have landed between scheduling and this tick.\n if (this.destroyed || !this.activeGraph || this.canvas !== canvas) {\n resolve(null);\n return;\n }\n try {\n const off = canvas.ownerDocument.createElement('canvas');\n off.width = canvas.width;\n off.height = canvas.height;\n const ctx = off.getContext('2d');\n if (!ctx) {\n resolve(null);\n return;\n }\n ctx.drawImage(canvas, 0, 0);\n off.toBlob((blob) => {\n resolve(blob);\n });\n } catch {\n resolve(null);\n }\n });\n });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n // Set first: if a context-restore reinit is mid-await, it observes the\n // flag, destroys the graph it just built, and emits nothing.\n this.destroyed = true;\n this.stopFrameLoop();\n this.deadline?.cancel();\n this.deadline = null;\n this.detachContextListeners();\n const graph = this.graph;\n this.graph = null;\n this.destroyGraphOnce(graph);\n const awaiting = this.graphAwaitingReady;\n this.graphAwaitingReady = null;\n this.destroyGraphOnce(awaiting);\n this.innerDiv?.remove();\n this.innerDiv = null;\n this.events = null;\n this.pendingCommit = null;\n this.imageSlots = [];\n this.blankImage = null;\n }\n\n // --- gated overlay/activity clock (see module header) ---\n\n /**\n * One rAF tick of the gated activity clock. Ordering is load-bearing:\n * 1. the tick budget is consumed BEFORE the host callback runs, so work\n * scheduled from inside onFrame re-arms a fresh tick instead of being\n * coalesced away;\n * 2. the reschedule/stop decision is made BEFORE the host callback, so a\n * throwing host can never kill a should-keep-running clock (and a\n * stopping clock stays stopped even if the callback wakes it — the\n * wake starts a new loop via requestTicks/wake, not this handle).\n * Skips the callback (but keeps its schedule) while the document is hidden.\n */\n private readonly frameTick = (timeMs: number): void => {\n const win = this.frameWindow;\n if (!win || this.frameHandle === null) return;\n if (this.pendingTicks > 0) this.pendingTicks -= 1;\n const keepRunning = this.runReasons.size > 0 || this.pendingTicks > 0;\n this.frameHandle = keepRunning ? win.requestAnimationFrame(this.frameTick) : null;\n if (!keepRunning) this.frameWindow = null;\n if (!win.document.hidden) this.events?.onFrame?.(timeMs);\n };\n\n /** Hold the clock open for a continuous activity (sim/drag/transition). */\n private wake(reason: 'sim' | 'drag' | 'transition'): void {\n this.runReasons.add(reason);\n this.ensureFrameLoop();\n }\n\n /**\n * Release a continuous-run reason. ALWAYS grants one trailing tick: the\n * releasing activity's final GPU write lands after the current draw pass\n * (the upstream drag-release bug class), so overlays need one more sample.\n */\n private sleep(reason: 'sim' | 'drag' | 'transition'): void {\n this.runReasons.delete(reason);\n this.requestTicks(1);\n }\n\n /**\n * Grant a one-shot tick budget (write/interaction re-arm). Two ticks is\n * the standard write burst: ordering between this clock's rAF callback and\n * cosmos' internal render frame within one tick is unguaranteed, so the\n * second tick guarantees overlays sample post-draw state (consistent with\n * the documented may-lag-one-sample degradation).\n */\n private requestTicks(n: number): void {\n if (this.destroyed || this.contextLost || this.failed || !this.graph) return;\n this.pendingTicks = Math.max(this.pendingTicks, n);\n this.ensureFrameLoop();\n }\n\n private ensureFrameLoop(): void {\n if (this.destroyed || this.frameHandle !== null) return;\n const win = this.innerDiv?.ownerDocument.defaultView ?? null;\n // No window / no rAF (detached document, exotic embedder): no clock — the\n // engine keeps working, overlays simply get no ticks.\n if (!win || typeof win.requestAnimationFrame !== 'function') return;\n this.frameWindow = win;\n this.frameHandle = win.requestAnimationFrame(this.frameTick);\n }\n\n private stopFrameLoop(): void {\n if (this.frameHandle !== null) {\n this.frameWindow?.cancelAnimationFrame(this.frameHandle);\n this.frameHandle = null;\n }\n this.frameWindow = null;\n this.runReasons.clear();\n this.pendingTicks = 0;\n }\n\n // --- WebGL context-loss recovery (§13.1) ---\n\n /** The graph, unless it is unusable (context lost / terminally failed). */\n private get activeGraph(): CosmosGraph | null {\n return this.contextLost || this.failed ? null : this.graph;\n }\n\n /**\n * cosmos owns its canvas; we can only wire webglcontext* listeners after\n * init by querying it. A missing canvas downgrades to an info diagnostic —\n * the engine keeps working, just without context-loss recovery.\n */\n private attachContextListeners(): void {\n const canvas = this.innerDiv?.querySelector('canvas') ?? null;\n if (!canvas) {\n this.events?.onDiagnostic?.({\n code: 'engine:context-listeners-unavailable',\n severity: 'info',\n message:\n 'CosmosEngine: no <canvas> found in the cosmos container; WebGL context-loss recovery is disabled.',\n });\n return;\n }\n this.canvas = canvas;\n canvas.addEventListener('webglcontextlost', this.handleContextLost);\n canvas.addEventListener('webglcontextrestored', this.handleContextRestored);\n }\n\n private detachContextListeners(): void {\n const canvas = this.canvas;\n if (!canvas) return;\n canvas.removeEventListener('webglcontextlost', this.handleContextLost);\n canvas.removeEventListener('webglcontextrestored', this.handleContextRestored);\n this.canvas = null;\n }\n\n /** DOM listener: nothing may throw out of it. */\n private readonly handleContextLost = (event: Event): void => {\n try {\n // preventDefault signals the browser that restoration is wanted; it must\n // run even on states we otherwise ignore.\n event.preventDefault();\n if (this.destroyed || this.failed || this.contextLost) return;\n this.contextLost = true;\n // The GL machine is dead: pause the activity clock until recovery.\n this.stopFrameLoop();\n // Any in-flight gesture died with the context; drop its latched state.\n this.dragIndex = null;\n this.lastHoverIndex = null;\n try {\n this.graph?.pause();\n } catch {\n // pausing a dead-context graph is best-effort only\n }\n this.startRestoreDeadline();\n this.events?.onContextEvent?.({ type: 'lost' });\n } catch {\n // swallow: DOM listeners must never throw\n }\n };\n\n /** DOM listener: nothing may throw out of it (async work is caught below). */\n private readonly handleContextRestored = (): void => {\n if (this.destroyed || this.failed || !this.contextLost) return;\n this.reinitializeAfterRestore().catch((err: unknown) => {\n if (this.destroyed) return;\n this.failed = true;\n const error = err instanceof Error ? err : new Error(String(err));\n try {\n this.events?.onContextEvent?.({ type: 'failed', error });\n } catch {\n // swallow: host callback errors must not become unhandled rejections\n }\n });\n };\n\n /**\n * cosmos cannot reuse a restored context (its GPU resources are gone), so\n * recovery = tear down the old Graph and build a fresh one in the same div,\n * flush the stashed commit, and only then report `restored` — the core\n * re-commits the full scene in response.\n */\n private async reinitializeAfterRestore(): Promise<void> {\n this.deadline?.cancel();\n this.deadline = null;\n this.detachContextListeners();\n const oldGraph = this.graph;\n this.graph = null;\n this.destroyGraphOnce(oldGraph);\n const div = this.innerDiv;\n const Ctor = this.cosmosCtor;\n if (!div || !Ctor) return; // destroy() raced ahead of us\n const graph = new Ctor(div, this.buildInitialConfig());\n this.graphAwaitingReady = graph;\n try {\n await graph.ready;\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n if (this.destroyed) {\n // destroy() landed mid-reinit: tear down the new graph, emit nothing.\n this.destroyGraphOnce(graph);\n return;\n }\n\n // Activation is one failure boundary. If listener wiring, frame-loop\n // startup, pending-channel upload, or restored delivery throws, the\n // replacement must not survive as an inert failed graph.\n this.graph = graph;\n this.attachContextListeners(); // the new Graph made a new canvas\n this.contextLost = false;\n // Gated clock: the fresh graph starts paused; the stashed commit (and\n // the core's full replay after `restored`) re-arm via requestTicks —\n // no unconditional restart, no re-diagnostic.\n this.requestTicks(2);\n const pending = this.pendingCommit;\n this.pendingCommit = null;\n if (pending) this.applyCommit(graph, pending);\n // Emit only after the stashed commit is visible: `restored` promises a\n // commit-ready engine whose applied revision is consistent.\n this.events?.onContextEvent?.({ type: 'restored' });\n } catch (err) {\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n this.stopFrameLoop();\n if (this.graph === graph) {\n this.detachContextListeners();\n this.graph = null;\n }\n this.destroyGraphOnce(graph);\n throw err;\n }\n }\n\n private startRestoreDeadline(): void {\n const doc = this.canvas?.ownerDocument;\n if (!doc) return;\n const ms = this.options.restoreDeadlineMs ?? DEFAULT_RESTORE_DEADLINE_MS;\n const deadline = new RestoreDeadline(doc, ms, () => {\n // Observability only: listeners stay mounted, state is unchanged, and a\n // late restore still recovers.\n this.deadline = null;\n this.events?.onDiagnostic?.({\n code: 'engine:context-restore-deadline',\n severity: 'warning',\n message: `CosmosEngine: WebGL context was not restored within ${ms}ms of visible time.`,\n });\n });\n this.deadline = deadline;\n deadline.start();\n }\n\n // -------------------------------------------------------------------------\n\n /**\n * Coalesces partial commits without discarding independent channels. The\n * newest call supplies the visible revision; structure is one atomic\n * channel, buffers/config merge per field, and restart persists until a\n * later explicit directive (including `false`) replaces it.\n */\n private queueCommit(update: EngineCommit): void {\n const previous = this.pendingCommit;\n if (previous === null) {\n this.pendingCommit = update;\n return;\n }\n\n const merged: EngineCommit = { revision: update.revision };\n\n const structure = update.structure ?? previous.structure;\n if (structure !== undefined) merged.structure = structure;\n\n if (previous.buffers !== undefined || update.buffers !== undefined) {\n merged.buffers = { ...previous.buffers, ...update.buffers };\n }\n\n if (previous.config !== undefined || update.config !== undefined) {\n const config = { ...previous.config, ...update.config };\n if (\n previous.config?.simulation !== undefined ||\n update.config?.simulation !== undefined\n ) {\n config.simulation = {\n ...previous.config?.simulation,\n ...update.config?.simulation,\n };\n }\n merged.config = config;\n }\n\n if (previous.resources !== undefined || update.resources !== undefined) {\n merged.resources = mergeResources(previous.resources, update.resources);\n }\n\n // Contract (§13 EngineCommit): `restart: false` and an ABSENT restart are\n // equivalent no-ops (\"false/absent = keep state\") — so neither cancels a\n // pending queued restart directive; only a new {alpha} replaces it\n // (PR #8 follow-up: explicit false previously cancelled while queued).\n const restart =\n update.restart !== undefined && update.restart !== false\n ? update.restart\n : previous.restart;\n if (restart !== undefined) merged.restart = restart;\n\n this.pendingCommit = merged;\n }\n\n /** Invokes a graph's destructor at most once, even across async races. */\n private destroyGraphOnce(graph: CosmosGraph | null): void {\n if (graph === null || this.destroyedGraphs.has(graph)) return;\n this.destroyedGraphs.add(graph);\n try {\n graph.destroy();\n } catch {\n // Teardown is best-effort, but no later path may invoke it again.\n }\n }\n\n private get spaceSize(): number {\n // The escape hatch is applied last in the constructor config, so a\n // spaceSize there is what cosmos actually uses — mirror it for seeding.\n const fromInitial = this.options.initialConfig?.['spaceSize'];\n if (typeof fromInitial === 'number') return fromInitial;\n return this.options.spaceSize ?? DEFAULT_SPACE_SIZE;\n }\n\n private get seedRadius(): number {\n return this.seedRadiusOverride ?? this.options.seedRadius ?? this.spaceSize / 4;\n }\n\n private buildInitialConfig(): GraphConfig {\n const base: GraphConfig = {\n // Default false: the core owns the camera (fitView is driven explicitly).\n fitViewOnInit: this.options.fitViewOnInit ?? false,\n // cosmos 3.4 defaults this to true. Pinned OFF for the 3.4 upgrade:\n // occlusion culling changes which overlapping pixels draw, and the M5\n // pixel-diff thresholds (CHANGED_MIN/RESTORED_MAX) were tuned against\n // un-culled rendering. One variable at a time — flipping it is a\n // registered follow-up with its own threshold re-validation.\n pointOcclusionCulling: false,\n // Native point dragging; the core owns pin semantics on top (§16.3).\n enableDrag: this.options.enableDrag ?? true,\n onPointClick: (index, _position, event) => {\n this.events?.onPointClick?.(index, clickModifiers(event));\n },\n onBackgroundClick: (event) => {\n this.emitNullPointClick(event);\n },\n // onClick fires for every canvas click; an undefined index means no\n // point was hit (background clicks — link clicks arrive via onLinkClick).\n onClick: (index, _position, event) => {\n if (index === undefined) this.emitNullPointClick(event);\n },\n // Unified context-menu channel: fires exactly once per gesture (desktop\n // right-click AND touch long-press — cosmos synthesizes the latter);\n // the per-target onPoint/onLink/onBackgroundContextMenu callbacks fire\n // ADDITIONALLY for the same gesture, so only this one is wired (see\n // module header). index undefined = background (or a link).\n onContextMenu: (index, _position, event) => {\n this.handleContextMenu(index, event);\n },\n onPointMouseOver: (index) => {\n this.lastHoverIndex = index;\n this.requestTicks(1); // overlay resync (tooltip/ring anchors)\n this.events?.onPointHover?.(index);\n },\n onPointMouseOut: () => {\n this.lastHoverIndex = null;\n this.requestTicks(1);\n this.events?.onPointHover?.(null);\n },\n // Setting any onLink* callback enables cosmos' native link hit-testing.\n onLinkClick: (linkIndex) => {\n this.events?.onLinkClick?.(linkIndex);\n },\n onLinkMouseOver: (linkIndex) => {\n this.requestTicks(1);\n this.events?.onLinkHover?.(linkIndex);\n },\n onLinkMouseOut: () => {\n this.requestTicks(1);\n this.events?.onLinkHover?.(null);\n },\n onDragStart: () => {\n this.handleDragStart();\n },\n onDragEnd: (e) => {\n this.handleDragEnd(e);\n },\n onZoom: () => {\n // Per-event ticks rather than a paired start/end reason: d3-zoom\n // fires this every animation step of BOTH user gestures and\n // programmatic transitions, so the burst self-sustains for exactly\n // as long as the camera actually moves.\n this.requestTicks(2);\n this.emitViewportChange();\n },\n onZoomEnd: () => {\n this.requestTicks(2);\n this.emitViewportChange();\n },\n // --- gated-clock run reasons (§17 stop-at-rest, ADR-005) ---\n onSimulationStart: () => {\n this.wake('sim');\n },\n onSimulationUnpause: () => {\n this.wake('sim');\n },\n onSimulationPause: () => {\n this.sleep('sim');\n },\n onSimulationEnd: () => {\n this.sleep('sim');\n this.events?.onSimulationEnd?.();\n },\n onTransitionStart: () => {\n this.wake('transition');\n },\n onTransitionEnd: () => {\n this.sleep('transition');\n },\n };\n if (this.options.spaceSize !== undefined) base.spaceSize = this.options.spaceSize;\n // Escape hatch: shallow-merged last so callers can override anything\n // above — EXCEPT that callback keys defined on BOTH sides COMPOSE\n // (adapter's first, then the caller's) rather than clobber. The gated\n // clock's wake/sleep wiring and the host event channels live in these\n // callbacks; a caller supplying onSimulationStart/onZoom/onDragEnd/…\n // through initialConfig must not silently sever them (ADR-005).\n const extra = this.options.initialConfig as GraphConfig | undefined;\n if (!extra) return base;\n const merged: GraphConfig = { ...base, ...extra };\n for (const key of Object.keys(base)) {\n const ours = (base as Record<string, unknown>)[key];\n const theirs = (extra as Record<string, unknown>)[key];\n if (typeof ours === 'function' && typeof theirs === 'function') {\n (merged as Record<string, unknown>)[key] = (...args: unknown[]) => {\n (ours as (...a: unknown[]) => unknown)(...args);\n return (theirs as (...a: unknown[]) => unknown)(...args);\n };\n }\n }\n return merged;\n }\n\n /**\n * Maps cosmos' unified context-menu callback to the host event: index\n * undefined → null (background), MouseEvent client coords → container-\n * relative CSS px (the inner div fills the host container exactly). The\n * native event is preventDefault-ed so the browser menu never opens — but\n * only when the host actually registered onContextMenu (it always does in\n * Orbit: the core owns the typed 'contextMenu' event channel). cosmos'\n * desktop `contextmenu` handler already prevents the event itself; repeating\n * it is an idempotent no-op that also covers the touch long-press path\n * (where cosmos forwards the originating pointerdown event instead).\n */\n private handleContextMenu(index: number | undefined, event: MouseEvent): void {\n const events = this.events;\n if (!events?.onContextMenu) return;\n if (typeof event.preventDefault === 'function') event.preventDefault();\n const div = this.innerDiv;\n if (!div) return;\n const rect = div.getBoundingClientRect();\n events.onContextMenu(index ?? null, [event.clientX - rect.left, event.clientY - rect.top]);\n }\n\n /** Emits onPointClick(null) once per originating click event. */\n private emitNullPointClick(event: unknown): void {\n if (event != null && event === this.lastNullClickEvent) return;\n this.lastNullClickEvent = event ?? null;\n this.events?.onPointClick?.(null, clickModifiers(event));\n }\n\n /**\n * The D3 drag event carries no point index; cosmos assigns\n * `store.draggingPointIndex` right before invoking onDragStart (see module\n * header). The public onPointMouseOver stream is the fallback — cosmos only\n * starts a drag while a point is hovered.\n */\n private readDraggingIndex(): number | null {\n const store = (this.graph as unknown as { store?: CosmosStoreLike } | null)?.store;\n return store?.draggingPointIndex ?? store?.hoveredPoint?.index ?? this.lastHoverIndex;\n }\n\n private handleDragStart(): void {\n // Wake before the index resolution: the gesture is real (cosmos renders\n // it) even when the dragged-point fallback chain comes up empty.\n this.wake('drag');\n const index = this.readDraggingIndex();\n if (index === null) return;\n this.dragIndex = index;\n this.events?.onDragStart?.(index);\n }\n\n /**\n * Reports the dragged point's final SPACE position. cosmos' drag shader\n * pins the point to the mouse's space position every frame, so converting\n * the event's screen coords is exact and O(1) (see module header).\n */\n private handleDragEnd(e: { x: number; y: number }): void {\n // Release the run reason even when no index was latched — cosmos pairs\n // start/end, but a mid-gesture hover loss must not leak a held reason.\n this.sleep('drag');\n const index = this.dragIndex;\n this.dragIndex = null;\n if (index === null) return;\n const graph = this.activeGraph;\n if (!graph) return; // context died mid-gesture; the drag is dropped\n const [x, y] = graph.screenToSpacePosition([e.x, e.y]);\n this.events?.onDragEnd?.(index, x, y);\n }\n\n private emitViewportChange(): void {\n const viewport = this.getViewport();\n if (viewport) this.events?.onViewportChange?.(viewport);\n }\n\n /**\n * One visibly atomic update (§13): all channels and config are staged, then\n * exactly one render() draws them; restart reheats after the render.\n */\n private applyCommit(graph: CosmosGraph, update: EngineCommit): void {\n const { config, structure, buffers, resources, restart } = update;\n\n if (config) {\n if (config.seedRadius !== undefined) this.seedRadiusOverride = config.seedRadius;\n const partial: GraphConfig = {};\n if (config.backgroundColor !== undefined) partial.backgroundColor = config.backgroundColor;\n // §16.12 arrowheads: cosmos' `linkDefaultArrows` config key (3.3.0\n // config.d.ts) — a pure config toggle, no per-link buffer involved.\n if (config.linkArrows !== undefined) partial.linkDefaultArrows = config.linkArrows;\n // §16.13 link visibility: cosmos 3.3.0 has a first-class `renderLinks`\n // config key (config.d.ts, default true) — config-only, never a buffer\n // rebuild (no linkOpacity workaround needed).\n if (config.renderLinks !== undefined) partial.renderLinks = config.renderLinks;\n // §8 theme tokens: cosmos accepts CSS color strings natively.\n if (config.defaultPointColor !== undefined) {\n partial.pointDefaultColor = config.defaultPointColor;\n }\n if (config.defaultLinkColor !== undefined) {\n partial.linkDefaultColor = config.defaultLinkColor;\n }\n // §17 disable-transitions ladder step: 0 = atomic jumps; null restores\n // cosmos' own default (config.d.ts `transitionDuration`, 800ms).\n if (config.transitionDurationMs !== undefined) {\n partial.transitionDuration = config.transitionDurationMs ?? 800;\n }\n // §13 emphasis ring: cosmos' FOCUSED ring (config.d.ts\n // `focusedPointRingColor`; drawn whenever a focused index is set — no\n // boolean gate). Deliberately NOT `renderHoveredPointRing`: that would\n // draw a second ring from cosmos' own hover state, and the focused path\n // is what lets orbit choose the ringed node (keyboard nav, focusNode).\n if (config.emphasisRingColor !== undefined) {\n partial.focusedPointRingColor = config.emphasisRingColor;\n }\n const sim = config.simulation;\n if (sim) {\n if (sim.gravity !== undefined) partial.simulationGravity = sim.gravity;\n if (sim.repulsion !== undefined) partial.simulationRepulsion = sim.repulsion;\n if (sim.friction !== undefined) partial.simulationFriction = sim.friction;\n if (sim.linkDistance !== undefined) partial.simulationLinkDistance = sim.linkDistance;\n if (sim.linkSpring !== undefined) partial.simulationLinkSpring = sim.linkSpring;\n // §10 tunables added in v0.10.2 — each maps 1:1 onto a cosmos config\n // key; an omitted field is never written, so cosmos' own default\n // stands (config.d.ts `defaultConfigValues`).\n if (sim.decay !== undefined) partial.simulationDecay = sim.decay;\n if (sim.collision !== undefined) partial.simulationCollision = sim.collision;\n if (sim.collisionRadius !== undefined) {\n partial.simulationCollisionRadius = sim.collisionRadius;\n }\n if (sim.collisionPadding !== undefined) {\n partial.simulationCollisionPadding = sim.collisionPadding;\n }\n // cosmos >= 3.4 replaced Barnes-Hut many-body with grid-based\n // repulsion: `simulationRepulsionTheta` is deprecated and\n // NON-FUNCTIONAL. Sending it would misrepresent state, so the key is\n // not mapped; the host learns once instead of wondering silently.\n if (sim.repulsionTheta !== undefined && !this.repulsionThetaWarned) {\n this.repulsionThetaWarned = true;\n this.events?.onDiagnostic?.({\n code: 'engine:repulsion-theta-deprecated',\n severity: 'info',\n message:\n 'CosmosEngine: cosmos >= 3.4 uses grid-based repulsion; ' +\n 'simulation.repulsionTheta is ignored by this engine.',\n });\n }\n if (sim.center !== undefined) partial.simulationCenter = sim.center;\n if (sim.repulsionFromMouse !== undefined) {\n partial.simulationRepulsionFromMouse = sim.repulsionFromMouse;\n }\n }\n // §16.3 stage-4 cluster force: the scene-wide coefficient is cosmos'\n // `simulationCluster` config key (config.d.ts, default 0.1); membership\n // and centers are buffer-shaped and staged below.\n if (config.cluster != null && config.cluster.strength !== undefined) {\n partial.simulationCluster = config.cluster.strength;\n }\n if (Object.keys(partial).length > 0) graph.setConfigPartial(partial);\n }\n\n if (structure) {\n this.lastPointCount = structure.pointCount;\n graph.setPointPositions(this.withSeededPositions(structure.positions));\n // cosmos takes link endpoint indices as Float32Array; exact for < 2^24 points.\n graph.setLinks(Float32Array.from(structure.links));\n }\n\n // Staged AFTER the roster so cosmos sees a membership array matching the\n // point count of this same commit (I2), and before the single render().\n if (config && config.cluster !== undefined) this.applyClusterForce(graph, config.cluster);\n\n if (buffers) {\n // [0,1] RGBA floats — cosmos' native scale; pass through (see header note).\n if (buffers.pointColor) graph.setPointColors(buffers.pointColor);\n if (buffers.pointSize) graph.setPointSizes(buffers.pointSize);\n if (buffers.linkColor) graph.setLinkColors(buffers.linkColor);\n if (buffers.linkWidth) graph.setLinkWidths(buffers.linkWidth);\n }\n\n // §8 atlas resources are staged before the SAME render() as every other\n // channel, keeping the commit visibly atomic.\n if (resources) this.applyResources(graph, resources);\n\n graph.render();\n this.applied = update.revision;\n\n if (restart) graph.start(restart.alpha);\n // §17 write re-arm: the commit's render lands this tick; the burst lets\n // overlays sample the post-draw state. A restart additionally holds the\n // clock via the sim run reason (onSimulationStart → wake).\n if (restart) this.wake('sim');\n this.requestTicks(2);\n }\n\n /**\n * Applies the §16.3 stage-4 cluster force (capability `clusterForce`).\n *\n * Contract mapping, verified against the 3.3.0 dist (`index.d.ts`):\n * - `pointClusters` (Float32Array, NaN = unclustered) →\n * `setPointClusters((number | undefined)[])`, where cosmos' documented\n * \"does not belong to any cluster\" value is `undefined`;\n * - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →\n * `setClusterPositions((number | undefined)[])`; a non-finite entry means\n * \"no position\" and cosmos falls back to that cluster's centermass;\n * - `null` clears: an all-`undefined` array of the CURRENT roster length\n * (length must track the roster) plus empty cluster positions.\n * `strength` is the scene-wide `simulationCluster` config coefficient\n * applied in the config block, not the per-point\n * `setPointClusterStrength` buffer (Orbit's strength is scene-wide).\n */\n private applyClusterForce(\n graph: CosmosGraph,\n cluster: NonNullable<EngineCommit['config']>['cluster'],\n ): void {\n if (cluster == null) {\n graph.setPointClusters(new Array<number | undefined>(this.lastPointCount).fill(undefined));\n graph.setClusterPositions([]);\n return;\n }\n const source = cluster.pointClusters;\n const assignments = new Array<number | undefined>(source.length);\n for (let i = 0; i < source.length; i++) {\n const value = source[i]!;\n assignments[i] = Number.isFinite(value) ? value : undefined;\n }\n graph.setPointClusters(assignments);\n const centers = cluster.centers;\n if (centers !== undefined) {\n const positions = new Array<number | undefined>(centers.length);\n for (let i = 0; i < centers.length; i++) {\n const value = centers[i]!;\n positions[i] = Number.isFinite(value) ? value : undefined;\n }\n graph.setClusterPositions(positions);\n }\n }\n\n /**\n * Applies the §8 image-atlas channel: upserts convert ImageBitmap →\n * ImageData through an offscreen 2D canvas into the slot mirror, removals\n * blank their slot, and any atlas change re-uploads the FULL ImageData\n * array (cosmos' setImageData is whole-array only, matching\n * `rangeUpdates: []`). Environments without a usable 2D context (jsdom)\n * no-op the channel and report `engine:image-channel-unavailable` once —\n * never throw.\n */\n private applyResources(graph: CosmosGraph, resources: EngineResources): void {\n const atlas = resources.imageAtlas;\n if (atlas) {\n let dirty = false;\n let conversionFailed = false;\n if (atlas.upserts) {\n for (const { slot, bitmap } of atlas.upserts) {\n if (!Number.isInteger(slot) || slot < 0) continue;\n const data = this.canvasImageData(bitmap.width, bitmap.height, bitmap);\n if (data === null) {\n conversionFailed = true;\n continue;\n }\n while (this.imageSlots.length <= slot) this.imageSlots.push(null);\n this.imageSlots[slot] = data;\n dirty = true;\n }\n }\n if (atlas.removeSlots) {\n for (const slot of atlas.removeSlots) {\n // Only slots that currently hold an image need blanking.\n if (slot >= 0 && slot < this.imageSlots.length && this.imageSlots[slot] != null) {\n this.imageSlots[slot] = null;\n dirty = true;\n }\n }\n }\n if (conversionFailed) this.reportImageChannelUnavailable();\n if (dirty) {\n const blank = this.blankImage ?? (this.blankImage = this.canvasImageData(1, 1));\n if (blank === null) {\n this.reportImageChannelUnavailable();\n } else {\n // Array.from (not .map) so sparse holes also materialize as blanks.\n graph.setImageData(Array.from(this.imageSlots, (d) => d ?? blank));\n }\n }\n }\n // Indices into an atlas that can never be populated are meaningless —\n // once the channel is known-unavailable the whole channel no-ops.\n if (resources.pointImageIndex && !this.imageChannelUnavailable) {\n graph.setPointImageIndices(resources.pointImageIndex);\n }\n }\n\n /**\n * Reads an ImageData of the given size off an offscreen 2D canvas, drawing\n * `bitmap` onto it first when provided (ImageBitmap → ImageData transcode;\n * without a bitmap: a transparent blank). Returns null — never throws —\n * where no 2D context exists (jsdom without the canvas package).\n */\n private canvasImageData(width: number, height: number, bitmap?: ImageBitmap): ImageData | null {\n const doc = this.innerDiv?.ownerDocument;\n if (!doc || !(width > 0) || !(height > 0)) return null;\n try {\n const canvas = doc.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n if (bitmap) ctx.drawImage(bitmap, 0, 0);\n return ctx.getImageData(0, 0, width, height);\n } catch {\n return null;\n }\n }\n\n /** Documented degradation, reported at most once per engine instance. */\n private reportImageChannelUnavailable(): void {\n if (this.imageChannelUnavailable) return;\n this.imageChannelUnavailable = true;\n this.events?.onDiagnostic?.({\n code: 'engine:image-channel-unavailable',\n severity: 'warning',\n message:\n 'CosmosEngine: no 2D canvas context is available to convert ImageBitmap ' +\n 'atlas entries to ImageData; point images are disabled in this environment.',\n });\n }\n\n /**\n * Replaces NaN pairs (= \"no known position\", §7.3) with random points on a\n * ring of radius seedRadius around the space center. cosmos treats NaN\n * positions as *absent* points, so they must never reach setPointPositions.\n * Known positions pass through verbatim (same array when nothing to seed).\n */\n private withSeededPositions(positions: Float32Array): Float32Array {\n let needsSeeding = false;\n for (let i = 0; i < positions.length; i += 2) {\n if (Number.isNaN(positions[i]!) || Number.isNaN(positions[i + 1]!)) {\n needsSeeding = true;\n break;\n }\n }\n if (!needsSeeding) return positions;\n\n const out = Float32Array.from(positions);\n const center = this.spaceSize / 2;\n const radius = this.seedRadius;\n for (let i = 0; i < out.length; i += 2) {\n if (Number.isNaN(out[i]!) || Number.isNaN(out[i + 1]!)) {\n const angle = Math.random() * Math.PI * 2;\n out[i] = center + radius * Math.cos(angle);\n out[i + 1] = center + radius * Math.sin(angle);\n }\n }\n return out;\n }\n}\n\n/**\n * Per-channel merge for queued §8 resources (pre-mount / context-lost):\n * upserts union per slot (latest bitmap wins), a later remove drops an\n * earlier pending upsert of the same slot (and vice versa — folding order\n * mirrors applyResources: upserts before removes within each commit), and\n * the latest pointImageIndex replaces wholesale.\n */\nfunction mergeResources(\n previous: EngineCommit['resources'],\n update: EngineCommit['resources'],\n): EngineResources {\n const upsertBySlot = new Map<number, ImageBitmap>();\n const removes = new Set<number>();\n for (const atlas of [previous?.imageAtlas, update?.imageAtlas]) {\n if (!atlas) continue;\n for (const { slot, bitmap } of atlas.upserts ?? []) {\n upsertBySlot.set(slot, bitmap);\n removes.delete(slot);\n }\n for (const slot of atlas.removeSlots ?? []) {\n upsertBySlot.delete(slot);\n removes.add(slot);\n }\n }\n const merged: EngineResources = {};\n if (upsertBySlot.size > 0 || removes.size > 0) {\n const imageAtlas: NonNullable<EngineResources['imageAtlas']> = {};\n if (upsertBySlot.size > 0) {\n imageAtlas.upserts = Array.from(upsertBySlot, ([slot, bitmap]) => ({ slot, bitmap }));\n }\n if (removes.size > 0) imageAtlas.removeSlots = Array.from(removes);\n merged.imageAtlas = imageAtlas;\n }\n const pointImageIndex = update?.pointImageIndex ?? previous?.pointImageIndex;\n if (pointImageIndex !== undefined) merged.pointImageIndex = pointImageIndex;\n return merged;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/restoreDeadline.ts","../src/CosmosEngine.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * RestoreDeadline — a visibility-aware countdown used while a WebGL context is\n * lost. Browsers routinely defer `webglcontextrestored` for backgrounded tabs,\n * so the budget must only burn while the document is visible: hidden time is\n * banked (timer cleared, remaining ms kept) and the countdown re-arms from the\n * remainder when the tab becomes visible again.\n */\nexport class RestoreDeadline {\n private timer: ReturnType<typeof setTimeout> | null = null;\n /** Unspent budget in ms; recomputed each time the timer is disarmed. */\n private remaining: number;\n /** Timestamp when the current timer was armed (for banking on hide). */\n private armedAt = 0;\n private started = false;\n /** Terminal: set on expiry or cancel; guarantees onExpire fires at most once. */\n private done = false;\n\n private readonly handleVisibilityChange = (): void => {\n if (this.done) return;\n if (this.doc.visibilityState === 'visible') this.arm();\n else this.disarm();\n };\n\n constructor(\n private readonly doc: Document,\n ms: number,\n private readonly onExpire: () => void,\n ) {\n this.remaining = ms;\n }\n\n start(): void {\n if (this.done || this.started) return;\n this.started = true;\n this.doc.addEventListener('visibilitychange', this.handleVisibilityChange);\n if (this.doc.visibilityState === 'visible') this.arm();\n }\n\n cancel(): void {\n if (this.done) return;\n this.done = true;\n if (this.timer !== null) {\n globalThis.clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.started) {\n this.doc.removeEventListener('visibilitychange', this.handleVisibilityChange);\n }\n }\n\n private arm(): void {\n if (this.timer !== null) return;\n this.armedAt = Date.now();\n this.timer = globalThis.setTimeout(() => {\n this.timer = null;\n this.done = true;\n this.doc.removeEventListener('visibilitychange', this.handleVisibilityChange);\n this.onExpire();\n }, this.remaining);\n }\n\n private disarm(): void {\n if (this.timer === null) return;\n globalThis.clearTimeout(this.timer);\n this.timer = null;\n this.remaining = Math.max(0, this.remaining - (Date.now() - this.armedAt));\n }\n}\n","/**\n * CosmosEngine — GraphEngine adapter over @cosmos.gl/graph.\n *\n * Node-safe module: cosmos is loaded lazily via `await import` inside\n * `mount`; module scope carries only type-only imports (erased at\n * runtime) and never touches the DOM.\n *\n * Color scale note: the EngineCommit contract carries RGBA floats in [0,1],\n * which is exactly cosmos' native scale (verified against the 3.3.0 dist:\n * hex config colors are parsed via /255 into 0–1 floats and setPointColors\n * input is fed to GPU buffers untouched) — so color buffers pass through.\n *\n * Interaction notes (verified against the 3.3.0 dist):\n * - Link picking is native: setting any onLink* config callback flips\n * cosmos' internal `isLinkHoveringEnabled` on, so wiring the callbacks in\n * `buildInitialConfig` is sufficient (no extra config flag exists).\n * - `findPointsInPolygon` takes SCREEN coordinates (\"from 0 to the\n * width/height of the canvas\" per dist/index.d.ts), so `pointsInPolygon`\n * passes the host's screen polygon through without conversion.\n * - `findPointsInRect` uses the SAME screen space and expects ordered\n * corners `[[left, top], [right, bottom]]` (the dist flips Y assuming that\n * ordering), so `pointsInRect` normalizes the host's [x0,y0,x1,y1] rect to\n * min/max corners and passes it through without conversion.\n * - Camera pan (the earlier zoom-only limitation is LIFTED): cosmos 3.3 has no\n * pan-to API, but `setZoomTransformByPointPositions(positions, duration,\n * scale, padding)` (dist/index.d.ts) is an exact center+zoom when `scale`\n * is explicit. Derivation from the dist (`zoomInstance.getTransform`):\n * space→screen-at-k=1 goes through `store.scaleX/scaleY`, which are LINEAR\n * with slope ±1 (scaleX(x) = x + (w−S)/2; scaleY(y) = (S−y) + (h−S)/2,\n * S = adjustedSpaceSize, w/h = canvas size); a single-point bbox is widened\n * ±0.5 SYMMETRICALLY (center preserved); an explicit `scale` bypasses the\n * fit math and `padding` entirely — k = clamp(scale, d3 scaleExtent) and\n * the result is translate(w/2 − scaleX(x)·k, h/2 − scaleY(y)·k).scale(k),\n * i.e. space point (x, y) lands exactly at the screen center with\n * eventTransform.k = scale. Since `getZoomLevel()` returns eventTransform.k\n * and `getViewport()` reads screenToSpacePosition(screen center),\n * `setViewport({x, y, zoom})` → setZoomTransformByPointPositions(\n * Float32Array.of(x, y), durationMs ?? 0, zoom ?? getZoomLevel()) makes a\n * follow-up `getViewport()` return exactly {x, y, zoom} (modulo the\n * scaleExtent clamp). This also completes recovery: the core replays\n * the full stored {x, y, zoom} through setViewport, so viewport restore is\n * no longer zoom-only.\n * - Context menu: cosmos fires the unified config `onContextMenu(index |\n * undefined, pos, event)` exactly ONCE per gesture — desktop right-click\n * (dist `onContextMenu(e)`) and touch/pen long-press (dist long-press timer\n * → `fireContextMenu`) both route through it — while the per-target\n * `onPointContextMenu`/`onLinkContextMenu`/`onBackgroundContextMenu`\n * callbacks fire ADDITIONALLY for the same gesture. Wiring only the unified\n * callback therefore avoids a double-report (same shape as the\n * onClick/onBackgroundClick dedupe). A context menu over a LINK arrives\n * with index undefined and is reported as background (the host event\n * carries node-or-background only).\n *\n * GATED overlay/activity clock:\n * cosmos still exposes no draw/render-phase hook (`postDrawFrames: false`),\n * so the adapter owns the single requestAnimationFrame loop that reports\n * `onFrame(timeMs)` to the host — an ACTIVITY clock, not a post-draw hook:\n * overlays may lag the canvas by one sample (reported once at mount via\n * `engine:overlay-activity-clock`). Since cosmos 3.4 idle-stops its own\n * rendering (on-demand rendering, quiescence probe: 0 idle frames/750ms),\n * this clock is GATED to match — it free-runs only while a run reason is\n * held (sim hot via onSimulationStart/Pause/Unpause/End, drag gestures,\n * cosmos transitions) and otherwise burns a small one-shot tick budget that\n * every visual write re-arms (commits, highlight/focus/pin setters, camera\n * moves, hover events; animated camera moves self-sustain through per-step\n * onZoom bursts). Releasing a run reason always grants ONE trailing tick\n * the releasing activity's final GPU write lands after the current draw\n * pass. At rest: zero rAF registrations from cosmos AND from this adapter\n * (`capabilities.idleFrames: 'stops'`). The clock stops on context\n * loss/destroy, re-arms on recovery, and skips the callback (keeping its\n * schedule) while `document.hidden`.\n *\n * Screenshots use the same-tick capture method (apps/spike/src/instrument.ts):\n * cosmos renders with preserveDrawingBuffer:false, so the WebGL buffer is only\n * readable via a synchronous drawImage inside the same rAF tick it was drawn\n * `captureScreenshot` schedules one rAF, draws the cosmos canvas onto an\n * offscreen 2D canvas inside that tick, and resolves the Blob (null on any\n * failure or unusable lifecycle state).\n * - The D3 drag events carry NO point index (the drag subject is a bare\n * `{x, y}`); cosmos assigns `store.draggingPointIndex` immediately before\n * invoking `onDragStart`, so the adapter reads it there (see\n * `readDraggingIndex` for the public-callback fallback).\n * - During a drag, cosmos' drag shader hard-pins the dragged point's\n * position texture entry to the mouse's SPACE position every frame\n * (dist `drag`: `pointPosition.rg = mousePos` where `mousePos` =\n * screenToSpace(pointer)). So the point's final space position equals\n * `screenToSpacePosition([event.x, event.y])` at drag end — an O(1) CPU\n * transform, chosen over `getPointPositions` (full GPU readback).\n */\n\nimport type { Graph as CosmosGraph, GraphConfig } from '@cosmos.gl/graph';\nimport type {\n EngineCapabilities,\n EngineCommit,\n EngineHostEvents,\n FitViewOptions,\n GraphEngine,\n} from '@modernrelay/orbit-core/engine';\nimport { RestoreDeadline } from './restoreDeadline';\n\n/** Derived from the contract to avoid importing the core root barrel. */\ntype ViewportState = NonNullable<ReturnType<GraphEngine['getViewport']>>;\n\n/**\n * Structural view of cosmos' `graph.store` — private in the 3.3.0 d.ts but a\n * stable runtime field. `draggingPointIndex` is assigned right before cosmos\n * invokes `onDragStart` (verified in the dist), making it the authoritative\n * dragged-point source; `hoveredPoint` mirrors the public onPointMouseOver\n * payload.\n */\ninterface CosmosStoreLike {\n hoveredPoint?: { index: number; position: [number, number] };\n draggingPointIndex?: number;\n}\n\n/**\n * Extracts click modifiers from a cosmos-forwarded event. Duck-typed rather\n * than `instanceof MouseEvent`: node-safe and cross-realm-safe. Returns\n * undefined when the event carries no modifier state.\n */\nfunction clickModifiers(event: unknown): { metaKey: boolean; shiftKey: boolean } | undefined {\n const e = event as { metaKey?: unknown; shiftKey?: unknown } | null | undefined;\n if (e && typeof e.metaKey === 'boolean' && typeof e.shiftKey === 'boolean') {\n return { metaKey: e.metaKey, shiftKey: e.shiftKey };\n }\n return undefined;\n}\n\nexport interface CosmosEngineOptions {\n /** Simulation space size passed to cosmos (cosmos default: 4096). */\n spaceSize?: number;\n /** Ring radius for seeding unknown (NaN) positions. Default: spaceSize/4. */\n seedRadius?: number;\n /** Whether cosmos auto-fits the view on init. Default: false (the core drives the camera). */\n fitViewOnInit?: boolean;\n /** Native point dragging (cosmos `enableDrag`). Default: true. */\n enableDrag?: boolean;\n /** Escape hatch: shallow-merged last into the cosmos constructor config. */\n initialConfig?: Record<string, unknown>;\n /**\n * Visible-time budget (ms) for the browser to restore a lost WebGL context\n * before an `engine:context-restore-deadline` diagnostic is emitted. The\n * deadline is observability only — a later restore still recovers.\n * Default: 10_000.\n */\n restoreDeadlineMs?: number;\n}\n\n/** cosmos' own default `spaceSize` (see @cosmos.gl/graph config defaults). */\nconst DEFAULT_SPACE_SIZE = 4096;\n\n/** Default visible-time budget before the restore-deadline diagnostic. */\nconst DEFAULT_RESTORE_DEADLINE_MS = 10_000;\n\n/** image-atlas channel of an EngineCommit (adapter-local alias). */\ntype EngineResources = NonNullable<EngineCommit['resources']>;\n\nexport class CosmosEngine implements GraphEngine {\n readonly capabilities: EngineCapabilities = {\n // Evidence-backed flip: the probe measured native onLinkClick/\n // onLinkMouseOver delivering correct link indices with ~4px perpendicular\n // tolerance.\n linkPicking: true,\n rangeUpdates: [],\n trackedPositions: true,\n simulation: true,\n // cosmos 3.3.0 exposes the `linkDefaultArrows` config key\n // (config.d.ts) — instanced arrowheads toggle atomically via setConfigPartial.\n edgeArrows: true,\n // cosmos 3.3.0 exposes setImageData(ImageData[]) +\n // setPointImageIndices(Float32Array) (index.d.ts) — per-point sprites via\n // an adapter-maintained slot→ImageData atlas.\n pointImages: true,\n // stage 4: cosmos 3.3.0 ships a real GPU cluster force\n // `setPointClusters((number|undefined)[])`, `setClusterPositions(\n // (number|undefined)[])`, `setPointClusterStrength(Float32Array)`\n // (index.d.ts) plus the `simulationCluster` coefficient (config.d.ts,\n // default 0.1) and the `Clusters` core module (dist/modules/Clusters).\n // `undefined` is cosmos' documented \"not in any cluster\" value, which the\n // adapter maps from the contract's NaN.\n clusterForce: true,\n // stop-at-rest: cosmos 3.4.0 ships on-demand rendering — the M0\n // quiescence row measured 0 idle frames AND 0 rAF registrations per\n // 750ms at rest.\n // The adapter's own activity clock is gated to match.\n idleFrames: 'stops',\n // onFrame is an activity clock, not an exact post-draw hook — cosmos\n // still exposes no public frame hook (probe `post-draw-frames`);\n // overlays may lag one sample.\n postDrawFrames: false,\n };\n\n private readonly options: CosmosEngineOptions;\n private graph: CosmosGraph | null = null;\n private innerDiv: HTMLDivElement | null = null;\n private events: EngineHostEvents | null = null;\n /**\n * Pre-mount/lost-context commits collapse per channel and are applied as one\n * atomic commit once a usable graph exists.\n */\n private pendingCommit: EngineCommit | null = null;\n private applied: number | null = null;\n private destroyed = false;\n private mounting = false;\n /** Constructed graph whose `ready` promise has not settled yet. */\n private graphAwaitingReady: CosmosGraph | null = null;\n /** Guards every graph teardown, including async init/recovery races. */\n private readonly destroyedGraphs = new WeakSet<CosmosGraph>();\n /** Sticky override from EngineConfigUpdate.seedRadius. */\n private seedRadiusOverride: number | undefined;\n /** Point count of the last structure-bearing commit — the roster length a\n * `cluster: null` clear must write an all-unclustered array for. */\n private lastPointCount = 0;\n /**\n * cosmos fires `onClick` (index undefined) AND `onBackgroundClick` for the\n * same background click; remembering the MouseEvent dedupes the null emit.\n */\n private lastNullClickEvent: unknown = null;\n /** Point latched at cosmos onDragStart; cleared when the gesture ends. */\n private dragIndex: number | null = null;\n /** Last hover reported by cosmos — fallback dragged-point source. */\n private lastHoverIndex: number | null = null;\n /** Live native link hover gates the unified onClick's\n * background interpretation — a hovered link owns the click). */\n private hoveredLinkIndex: number | null = null;\n\n // --- adapter-owned GATED overlay/activity clock (see module header) ---\n\n /** rAF id of the pending activity-clock tick; null = clock not running. */\n private frameHandle: number | null = null;\n /** Window driving the clock, cached so stop works after the div detaches. */\n private frameWindow: Window | null = null;\n /** Continuous-run reasons; the clock free-runs while any is held. */\n private readonly runReasons = new Set<'sim' | 'drag' | 'transition'>();\n /** One-shot tick budget for write/interaction re-arm bursts. */\n private pendingTicks = 0;\n /** One-shot guard for the repulsionTheta deprecation diagnostic. */\n private repulsionThetaWarned = false;\n\n // --- WebGL context-loss recovery state ---\n\n /** cosmos' canvas (queried post-mount) carrying the webglcontext* listeners. */\n private canvas: HTMLCanvasElement | null = null;\n private contextLost = false;\n /** Terminal: GL reinitialization failed; commits stash inertly forever. */\n private failed = false;\n private deadline: RestoreDeadline | null = null;\n /** Graph constructor cached at mount so recovery never re-imports cosmos. */\n private cosmosCtor: (new (div: HTMLDivElement, config?: GraphConfig) => CosmosGraph) | null =\n null;\n\n // --- image atlas (capability pointImages) ---\n\n /**\n * slot → ImageData mirror of the cosmos image atlas. ImageData is CPU-side,\n * so the mirror survives context loss — any post-restore atlas commit\n * re-uploads the FULL array to the fresh graph. `null` = removed (blank).\n */\n private imageSlots: (ImageData | null)[] = [];\n /** Lazily created 1×1 transparent entry filling removed/hole slots. */\n private blankImage: ImageData | null = null;\n /** One-shot guard for the `engine:image-channel-unavailable` diagnostic. */\n private imageChannelUnavailable = false;\n\n constructor(options: CosmosEngineOptions = {}) {\n this.options = options;\n }\n\n async mount(container: HTMLElement, events: EngineHostEvents): Promise<void> {\n if (this.destroyed) throw new Error('CosmosEngine: mount() after destroy()');\n if (this.mounting || this.graph) throw new Error('CosmosEngine: mount() may only be called once');\n this.mounting = true;\n this.events = events;\n\n // cosmos wants a dedicated HTMLDivElement filling the host container.\n const div = container.ownerDocument.createElement('div');\n div.style.width = '100%';\n div.style.height = '100%';\n container.appendChild(div);\n this.innerDiv = div;\n\n let graph: CosmosGraph | null = null;\n try {\n // cosmos (and its WebGL dependencies) load only at mount time.\n const { Graph } = await import('@cosmos.gl/graph');\n // destroy may have landed while the dynamic import was pending.\n if (this.destroyed) {\n div.remove();\n return;\n }\n graph = new Graph(div, this.buildInitialConfig());\n this.graphAwaitingReady = graph;\n await graph.ready;\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n if (this.destroyed) {\n // destroy raced the async init; tear the graph down immediately.\n this.destroyGraphOnce(graph);\n div.remove();\n return;\n }\n this.graph = graph;\n this.cosmosCtor = Graph;\n this.attachContextListeners();\n // Documented degradation (M0): overlays ride an activity clock because\n // cosmos has no draw-phase hook. Emitted once, at mount only.\n events.onDiagnostic?.({\n code: 'engine:overlay-activity-clock',\n severity: 'info',\n message:\n 'CosmosEngine: cosmos exposes no draw-phase hook (postDrawFrames:false); ' +\n 'overlays ride an adapter-owned, idle-gated requestAnimationFrame activity ' +\n 'clock (stops at rest — idleFrames:stops) and may lag the canvas by one frame.',\n });\n // cosmos 3.4 keeps rendering when the FPS monitor is shown — that\n // silently defeats the idleFrames:'stops' declaration, so say so once.\n if ((this.options.initialConfig as GraphConfig | undefined)?.showFPSMonitor) {\n events.onDiagnostic?.({\n code: 'engine:fps-monitor-defeats-quiescence',\n severity: 'info',\n message:\n 'CosmosEngine: showFPSMonitor keeps cosmos rendering every frame; ' +\n 'stop-at-rest quiescence is disabled while it is shown.',\n });\n }\n // Gated clock: no unconditional start — cosmos draws its own init\n // frame; a short burst lets overlays sample it, then the clock stops\n // until a wake source (commit/sim/gesture) re-arms it.\n this.requestTicks(2);\n const pending = this.pendingCommit;\n this.pendingCommit = null;\n if (pending) this.applyCommit(graph, pending);\n } catch (err) {\n if (graph !== null) {\n if (this.graph === graph) {\n this.stopFrameLoop();\n this.detachContextListeners();\n this.graph = null;\n }\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n this.destroyGraphOnce(graph);\n }\n div.remove();\n if (this.innerDiv === div) this.innerDiv = null;\n // destroy is terminal and already cleaned up the constructed graph;\n // a later ready rejection must not escape or notify stale hosts.\n if (this.destroyed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n events.onError?.(error);\n throw error;\n }\n }\n\n commit(update: EngineCommit): void {\n if (this.destroyed) throw new Error('CosmosEngine: commit() after destroy()');\n const graph = this.activeGraph;\n if (!graph) {\n // Pre-mount, context-lost, or failed: retain the latest value of every\n // independently replaceable channel. The merged commit is flushed on\n // mount/restore (or remains inert forever after terminal failure).\n this.queueCommit(update);\n return;\n }\n this.applyCommit(graph, update);\n }\n\n appliedRevision(): number | null {\n return this.applied;\n }\n\n // --- camera ---\n // Every camera write re-arms the clock; ANIMATED moves then self-sustain\n // through cosmos' per-step onZoom events (each grants a fresh burst), so\n // no duration bookkeeping is needed here.\n\n fitView(opts?: FitViewOptions): void {\n this.activeGraph?.fitView(opts?.durationMs, opts?.padding);\n this.requestTicks(2);\n }\n\n zoom(factor: number, durationMs?: number): void {\n const graph = this.activeGraph;\n if (!graph) return;\n graph.setZoomLevel(graph.getZoomLevel() * factor, durationMs);\n this.requestTicks(2);\n }\n\n /**\n * REAL pan (the former zoom-only limitation is lifted — see module header):\n * when a target center is provided, one `setZoomTransformByPointPositions`\n * call centers space point (x, y) at EXACTLY the requested (or current)\n * zoom — `setViewport(p)` then `getViewport()` returns p, modulo cosmos'\n * d3 scaleExtent clamp. A missing x or y is filled from the current\n * viewport; zoom-only calls keep the `setZoomLevel` path (d3's scaleTo\n * preserves the current center). Instant unless `durationMs` is given\n * cosmos' own default duration is 250 ms, which would animate context-\n * recovery replays.\n */\n setViewport(v: Partial<ViewportState>, opts?: { durationMs?: number }): void {\n const graph = this.activeGraph;\n if (!graph) return;\n if (v.x !== undefined || v.y !== undefined) {\n const current = v.x === undefined || v.y === undefined ? this.getViewport() : null;\n const x = v.x ?? current?.x;\n const y = v.y ?? current?.y;\n if (x !== undefined && y !== undefined) {\n graph.setZoomTransformByPointPositions(\n Float32Array.of(x, y),\n opts?.durationMs ?? 0,\n v.zoom ?? graph.getZoomLevel(),\n );\n this.requestTicks(2);\n return;\n }\n // No usable center (detached container): degrade to zoom-only below.\n }\n if (v.zoom !== undefined) graph.setZoomLevel(v.zoom, opts?.durationMs ?? 0);\n this.requestTicks(2);\n }\n\n getViewport(): ViewportState | null {\n const graph = this.activeGraph;\n const div = this.innerDiv;\n if (!graph || !div) return null;\n const [x, y] = graph.screenToSpacePosition([div.clientWidth / 2, div.clientHeight / 2]);\n return { x, y, zoom: graph.getZoomLevel() };\n }\n\n zoomToIndex(index: number, durationMs?: number): void {\n this.activeGraph?.zoomToPointByIndex(index, durationMs);\n this.requestTicks(2);\n }\n\n // --- simulation ---\n\n start(alpha?: number): void {\n // cosmos fires onSimulationStart (→ wake) — the direct wake covers a\n // callback wiring gap and is idempotent through the Set.\n this.wake('sim');\n this.activeGraph?.start(alpha);\n }\n\n pause(): void {\n this.sleep('sim');\n this.activeGraph?.pause();\n }\n\n // --- built-in interaction visuals ---\n\n setSelectedIndices(indices: readonly number[] | null): void {\n const graph = this.activeGraph;\n if (!graph) return;\n // cosmos 3.3 has no imperative select/unselect API; selection visuals are\n // config-driven — points NOT in `highlightedPointIndices` grey out, and an\n // explicit `undefined` resets the key (clears highlighting) per\n // setConfigPartial semantics.\n graph.setConfigPartial({\n highlightedPointIndices: indices === null ? undefined : Array.from(indices),\n } as unknown as GraphConfig);\n this.requestTicks(2); // write re-arm: overlays sample the new state\n }\n\n setFocusedIndex(index: number | null): void {\n const graph = this.activeGraph;\n if (!graph) return;\n graph.setConfigPartial({\n focusedPointIndex: index === null ? undefined : index,\n } as unknown as GraphConfig);\n this.requestTicks(2);\n }\n\n // --- spatial queries & pinning ---\n\n pointsInPolygon(screenPolygon: readonly [number, number][]): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos' findPointsInPolygon already expects SCREEN coordinates (0 to\n // canvas width/height per the 3.3.0 d.ts) — no conversion; copy the pairs\n // only to satisfy cosmos' mutable-signature and shield the caller's input.\n return graph.findPointsInPolygon(screenPolygon.map(([x, y]): [number, number] => [x, y]));\n }\n\n pointsInRect(screenRect: readonly [number, number, number, number]): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos' findPointsInRect expects SCREEN coordinates (0 to canvas\n // width/height — the same space as findPointsInPolygon per the 3.3.0\n // d.ts) as ordered corners [[left, top], [right, bottom]] (the dist flips\n // Y assuming that ordering) — normalize so any opposite-corner pair works.\n const [x0, y0, x1, y1] = screenRect;\n return graph.findPointsInRect([\n [Math.min(x0, x1), Math.min(y0, y1)],\n [Math.max(x0, x1), Math.max(y0, y1)],\n ]);\n }\n\n neighborIndices(index: number): number[] {\n const graph = this.activeGraph;\n if (!graph) return [];\n // cosmos dedupes but a self-loop can report the point as its own neighbor.\n return graph.getNeighboringPointIndices(index).filter((i) => i !== index);\n }\n\n screenToSpace(p: readonly [number, number]): [number, number] | null {\n const graph = this.activeGraph;\n return graph ? graph.screenToSpacePosition([p[0], p[1]]) : null;\n }\n\n spaceToScreen(p: readonly [number, number]): [number, number] | null {\n const graph = this.activeGraph;\n return graph ? graph.spaceToScreenPosition([p[0], p[1]]) : null;\n }\n\n setPinnedIndices(indices: readonly number[] | null): void {\n // Full-set replace, idempotent; null and [] both unpin all (cosmos treats\n // them identically). Pin re-application after recovery is core-owned.\n this.activeGraph?.setPinnedPoints(indices === null ? null : Array.from(indices));\n this.requestTicks(2);\n }\n\n // --- readback ---\n\n getPositions(): Float32Array | null {\n const graph = this.activeGraph;\n return graph ? Float32Array.from(graph.getPointPositions()) : null;\n }\n\n /**\n * Captures the cosmos canvas via the same-tick method (see module\n * header): one rAF is scheduled and, inside that tick, the WebGL canvas is\n * drawn synchronously onto an offscreen 2D canvas (cosmos renders with\n * preserveDrawingBuffer:false, so the buffer is only readable same-tick).\n * Resolves null on any failure or unusable lifecycle state (pre-mount,\n * context lost/failed, destroyed, no 2D context, toBlob failure).\n */\n captureScreenshot(): Promise<Blob | null> {\n const graph = this.activeGraph;\n const canvas = graph ? this.canvas : null;\n const win = canvas?.ownerDocument.defaultView ?? null;\n if (!graph || !canvas || !win || typeof win.requestAnimationFrame !== 'function') {\n return Promise.resolve(null);\n }\n // Under on-demand rendering (cosmos >= 3.4) an idle scene draws nothing,\n // and with preserveDrawingBuffer:false an undrawn buffer reads blank\n // render is a visual mutator that schedules the frame our capture rAF\n // then samples same-tick.\n try {\n graph.render();\n } catch {\n return Promise.resolve(null);\n }\n return new Promise((resolve) => {\n win.requestAnimationFrame(() => {\n // Re-check: loss/destroy (or a restore swapping in a new canvas) may\n // have landed between scheduling and this tick.\n if (this.destroyed || !this.activeGraph || this.canvas !== canvas) {\n resolve(null);\n return;\n }\n try {\n const off = canvas.ownerDocument.createElement('canvas');\n off.width = canvas.width;\n off.height = canvas.height;\n const ctx = off.getContext('2d');\n if (!ctx) {\n resolve(null);\n return;\n }\n ctx.drawImage(canvas, 0, 0);\n off.toBlob((blob) => {\n resolve(blob);\n });\n } catch {\n resolve(null);\n }\n });\n });\n }\n\n destroy(): void {\n if (this.destroyed) return;\n // Set first: if a context-restore reinit is mid-await, it observes the\n // flag, destroys the graph it just built, and emits nothing.\n this.destroyed = true;\n this.stopFrameLoop();\n this.deadline?.cancel();\n this.deadline = null;\n this.detachContextListeners();\n const graph = this.graph;\n this.graph = null;\n this.destroyGraphOnce(graph);\n const awaiting = this.graphAwaitingReady;\n this.graphAwaitingReady = null;\n this.destroyGraphOnce(awaiting);\n this.innerDiv?.remove();\n this.innerDiv = null;\n this.events = null;\n this.pendingCommit = null;\n this.imageSlots = [];\n this.blankImage = null;\n }\n\n // --- gated overlay/activity clock (see module header) ---\n\n /**\n * One rAF tick of the gated activity clock. Ordering is load-bearing:\n * 1. the tick budget is consumed BEFORE the host callback runs, so work\n * scheduled from inside onFrame re-arms a fresh tick instead of being\n * coalesced away;\n * 2. the reschedule/stop decision is made BEFORE the host callback, so a\n * throwing host can never kill a should-keep-running clock (and a\n * stopping clock stays stopped even if the callback wakes it — the\n * wake starts a new loop via requestTicks/wake, not this handle).\n * Skips the callback (but keeps its schedule) while the document is hidden.\n */\n private readonly frameTick = (timeMs: number): void => {\n const win = this.frameWindow;\n if (!win || this.frameHandle === null) return;\n if (this.pendingTicks > 0) this.pendingTicks -= 1;\n const keepRunning = this.runReasons.size > 0 || this.pendingTicks > 0;\n this.frameHandle = keepRunning ? win.requestAnimationFrame(this.frameTick) : null;\n if (!keepRunning) this.frameWindow = null;\n if (!win.document.hidden) this.events?.onFrame?.(timeMs);\n };\n\n /** Hold the clock open for a continuous activity (sim/drag/transition). */\n private wake(reason: 'sim' | 'drag' | 'transition'): void {\n this.runReasons.add(reason);\n this.ensureFrameLoop();\n }\n\n /**\n * Release a continuous-run reason. ALWAYS grants one trailing tick: the\n * releasing activity's final GPU write lands after the current draw pass\n * (the upstream drag-release bug class), so overlays need one more sample.\n */\n private sleep(reason: 'sim' | 'drag' | 'transition'): void {\n this.runReasons.delete(reason);\n this.requestTicks(1);\n }\n\n /**\n * Grant a one-shot tick budget (write/interaction re-arm). Two ticks is\n * the standard write burst: ordering between this clock's rAF callback and\n * cosmos' internal render frame within one tick is unguaranteed, so the\n * second tick guarantees overlays sample post-draw state (consistent with\n * the documented may-lag-one-sample degradation).\n */\n private requestTicks(n: number): void {\n if (this.destroyed || this.contextLost || this.failed || !this.graph) return;\n this.pendingTicks = Math.max(this.pendingTicks, n);\n this.ensureFrameLoop();\n }\n\n private ensureFrameLoop(): void {\n if (this.destroyed || this.frameHandle !== null) return;\n const win = this.innerDiv?.ownerDocument.defaultView ?? null;\n // No window / no rAF (detached document, exotic embedder): no clock — the\n // engine keeps working, overlays simply get no ticks.\n if (!win || typeof win.requestAnimationFrame !== 'function') return;\n this.frameWindow = win;\n this.frameHandle = win.requestAnimationFrame(this.frameTick);\n }\n\n private stopFrameLoop(): void {\n if (this.frameHandle !== null) {\n this.frameWindow?.cancelAnimationFrame(this.frameHandle);\n this.frameHandle = null;\n }\n this.frameWindow = null;\n this.runReasons.clear();\n this.pendingTicks = 0;\n }\n\n // --- WebGL context-loss recovery ---\n\n /** The graph, unless it is unusable (context lost / terminally failed). */\n private get activeGraph(): CosmosGraph | null {\n return this.contextLost || this.failed ? null : this.graph;\n }\n\n /**\n * cosmos owns its canvas; we can only wire webglcontext* listeners after\n * init by querying it. A missing canvas downgrades to an info diagnostic\n * the engine keeps working, just without context-loss recovery.\n */\n private attachContextListeners(): void {\n const canvas = this.innerDiv?.querySelector('canvas') ?? null;\n if (!canvas) {\n this.events?.onDiagnostic?.({\n code: 'engine:context-listeners-unavailable',\n severity: 'info',\n message:\n 'CosmosEngine: no <canvas> found in the cosmos container; WebGL context-loss recovery is disabled.',\n });\n return;\n }\n this.canvas = canvas;\n canvas.addEventListener('webglcontextlost', this.handleContextLost);\n canvas.addEventListener('webglcontextrestored', this.handleContextRestored);\n }\n\n private detachContextListeners(): void {\n const canvas = this.canvas;\n if (!canvas) return;\n canvas.removeEventListener('webglcontextlost', this.handleContextLost);\n canvas.removeEventListener('webglcontextrestored', this.handleContextRestored);\n this.canvas = null;\n }\n\n /** DOM listener: nothing may throw out of it. */\n private readonly handleContextLost = (event: Event): void => {\n try {\n // preventDefault signals the browser that restoration is wanted; it must\n // run even on states we otherwise ignore.\n event.preventDefault();\n if (this.destroyed || this.failed || this.contextLost) return;\n this.contextLost = true;\n // The GL machine is dead: pause the activity clock until recovery.\n this.stopFrameLoop();\n // Any in-flight gesture died with the context; drop its latched state.\n this.dragIndex = null;\n this.lastHoverIndex = null;\n try {\n this.graph?.pause();\n } catch {\n // pausing a dead-context graph is best-effort only\n }\n this.startRestoreDeadline();\n this.events?.onContextEvent?.({ type: 'lost' });\n } catch {\n // swallow: DOM listeners must never throw\n }\n };\n\n /** DOM listener: nothing may throw out of it (async work is caught below). */\n private readonly handleContextRestored = (): void => {\n if (this.destroyed || this.failed || !this.contextLost) return;\n this.reinitializeAfterRestore().catch((err: unknown) => {\n if (this.destroyed) return;\n this.failed = true;\n const error = err instanceof Error ? err : new Error(String(err));\n try {\n this.events?.onContextEvent?.({ type: 'failed', error });\n } catch {\n // swallow: host callback errors must not become unhandled rejections\n }\n });\n };\n\n /**\n * cosmos cannot reuse a restored context (its GPU resources are gone), so\n * recovery = tear down the old Graph and build a fresh one in the same div,\n * flush the stashed commit, and only then report `restored` — the core\n * re-commits the full scene in response.\n */\n private async reinitializeAfterRestore(): Promise<void> {\n this.deadline?.cancel();\n this.deadline = null;\n this.detachContextListeners();\n const oldGraph = this.graph;\n this.graph = null;\n this.destroyGraphOnce(oldGraph);\n const div = this.innerDiv;\n const Ctor = this.cosmosCtor;\n if (!div || !Ctor) return; // destroy() raced ahead of us\n const graph = new Ctor(div, this.buildInitialConfig());\n this.graphAwaitingReady = graph;\n try {\n await graph.ready;\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n if (this.destroyed) {\n // destroy landed mid-reinit: tear down the new graph, emit nothing.\n this.destroyGraphOnce(graph);\n return;\n }\n\n // Activation is one failure boundary. If listener wiring, frame-loop\n // startup, pending-channel upload, or restored delivery throws, the\n // replacement must not survive as an inert failed graph.\n this.graph = graph;\n this.attachContextListeners(); // the new Graph made a new canvas\n this.contextLost = false;\n // Gated clock: the fresh graph starts paused; the stashed commit (and\n // the core's full replay after `restored`) re-arm via requestTicks\n // no unconditional restart, no re-diagnostic.\n this.requestTicks(2);\n const pending = this.pendingCommit;\n this.pendingCommit = null;\n if (pending) this.applyCommit(graph, pending);\n // Emit only after the stashed commit is visible: `restored` promises a\n // commit-ready engine whose applied revision is consistent.\n this.events?.onContextEvent?.({ type: 'restored' });\n } catch (err) {\n if (this.graphAwaitingReady === graph) this.graphAwaitingReady = null;\n this.stopFrameLoop();\n if (this.graph === graph) {\n this.detachContextListeners();\n this.graph = null;\n }\n this.destroyGraphOnce(graph);\n throw err;\n }\n }\n\n private startRestoreDeadline(): void {\n const doc = this.canvas?.ownerDocument;\n if (!doc) return;\n const ms = this.options.restoreDeadlineMs ?? DEFAULT_RESTORE_DEADLINE_MS;\n const deadline = new RestoreDeadline(doc, ms, () => {\n // Observability only: listeners stay mounted, state is unchanged, and a\n // late restore still recovers.\n this.deadline = null;\n this.events?.onDiagnostic?.({\n code: 'engine:context-restore-deadline',\n severity: 'warning',\n message: `CosmosEngine: WebGL context was not restored within ${ms}ms of visible time.`,\n });\n });\n this.deadline = deadline;\n deadline.start();\n }\n\n // -------------------------------------------------------------------------\n\n /**\n * Coalesces partial commits without discarding independent channels. The\n * newest call supplies the visible revision; structure is one atomic\n * channel, buffers/config merge per field, and restart persists until a\n * later explicit directive (including `false`) replaces it.\n */\n private queueCommit(update: EngineCommit): void {\n const previous = this.pendingCommit;\n if (previous === null) {\n this.pendingCommit = update;\n return;\n }\n\n const merged: EngineCommit = { revision: update.revision };\n\n const structure = update.structure ?? previous.structure;\n if (structure !== undefined) merged.structure = structure;\n\n if (previous.buffers !== undefined || update.buffers !== undefined) {\n merged.buffers = { ...previous.buffers, ...update.buffers };\n }\n\n if (previous.config !== undefined || update.config !== undefined) {\n const config = { ...previous.config, ...update.config };\n if (\n previous.config?.simulation !== undefined ||\n update.config?.simulation !== undefined\n ) {\n config.simulation = {\n ...previous.config?.simulation,\n ...update.config?.simulation,\n };\n }\n merged.config = config;\n }\n\n if (previous.resources !== undefined || update.resources !== undefined) {\n merged.resources = mergeResources(previous.resources, update.resources);\n }\n\n // Contract: `restart: false` and an ABSENT restart are\n // equivalent no-ops (\"false/absent = keep state\") — so neither cancels a\n // pending queued restart directive; only a new {alpha} replaces it.\n const restart =\n update.restart !== undefined && update.restart !== false\n ? update.restart\n : previous.restart;\n if (restart !== undefined) merged.restart = restart;\n\n this.pendingCommit = merged;\n }\n\n /** Invokes a graph's destructor at most once, even across async races. */\n private destroyGraphOnce(graph: CosmosGraph | null): void {\n if (graph === null || this.destroyedGraphs.has(graph)) return;\n this.destroyedGraphs.add(graph);\n try {\n graph.destroy();\n } catch {\n // Teardown is best-effort, but no later path may invoke it again.\n }\n }\n\n private get spaceSize(): number {\n // The escape hatch is applied last in the constructor config, so a\n // spaceSize there is what cosmos actually uses — mirror it for seeding.\n const fromInitial = this.options.initialConfig?.['spaceSize'];\n if (typeof fromInitial === 'number') return fromInitial;\n return this.options.spaceSize ?? DEFAULT_SPACE_SIZE;\n }\n\n private get seedRadius(): number {\n return this.seedRadiusOverride ?? this.options.seedRadius ?? this.spaceSize / 4;\n }\n\n private buildInitialConfig(): GraphConfig {\n const base: GraphConfig = {\n // Default false: the core owns the camera (fitView is driven explicitly).\n fitViewOnInit: this.options.fitViewOnInit ?? false,\n // cosmos 3.4 defaults this to true. Pinned OFF for the 3.4 upgrade:\n // occlusion culling changes which overlapping pixels draw, and the M5\n // pixel-diff thresholds (CHANGED_MIN/RESTORED_MAX) were tuned against\n // un-culled rendering. Keep one variable at a time; enabling culling\n // requires its own threshold re-validation.\n pointOcclusionCulling: false,\n // Native point dragging; the core owns pin semantics on top.\n enableDrag: this.options.enableDrag ?? true,\n onPointClick: (index, _position, event) => {\n this.events?.onPointClick?.(index, clickModifiers(event));\n },\n onBackgroundClick: (event) => {\n // Same guard as the unified onClick below: a hovered link\n // owns the gesture regardless of which cosmos channel reports it.\n if (this.hoveredLinkIndex === null) this.emitNullPointClick(event);\n },\n // onClick fires for every canvas click; an undefined index means no\n // point was hit (background clicks — link clicks arrive via onLinkClick).\n onClick: (index, _position, event) => {\n // A link click also reaches here with index undefined\n // (no POINT was hit), so treating every undefined as background\n // cleared selection on every edge click. A hovered link means the\n // gesture targets the link — cosmos's ~4px hover tolerance IS its\n // click tolerance — and onLinkClick delivers it; only a no-point,\n // no-link click is background.\n if (index === undefined && this.hoveredLinkIndex === null) {\n this.emitNullPointClick(event);\n }\n },\n // Unified context-menu channel: fires exactly once per gesture (desktop\n // right-click AND touch long-press — cosmos synthesizes the latter);\n // the per-target onPoint/onLink/onBackgroundContextMenu callbacks fire\n // ADDITIONALLY for the same gesture, so only this one is wired (see\n // module header). index undefined = background (or a link).\n onContextMenu: (index, _position, event) => {\n this.handleContextMenu(index, event);\n },\n onPointMouseOver: (index) => {\n this.lastHoverIndex = index;\n this.requestTicks(1); // overlay resync (tooltip/ring anchors)\n this.events?.onPointHover?.(index);\n },\n onPointMouseOut: () => {\n this.lastHoverIndex = null;\n this.requestTicks(1);\n this.events?.onPointHover?.(null);\n },\n // Setting any onLink* callback enables cosmos' native link hit-testing.\n onLinkClick: (linkIndex) => {\n this.events?.onLinkClick?.(linkIndex);\n },\n onLinkMouseOver: (linkIndex) => {\n this.hoveredLinkIndex = linkIndex;\n this.requestTicks(1);\n this.events?.onLinkHover?.(linkIndex);\n },\n onLinkMouseOut: () => {\n this.hoveredLinkIndex = null;\n this.requestTicks(1);\n this.events?.onLinkHover?.(null);\n },\n onDragStart: () => {\n this.handleDragStart();\n },\n onDragEnd: (e) => {\n this.handleDragEnd(e);\n },\n onZoom: () => {\n // Per-event ticks rather than a paired start/end reason: d3-zoom\n // fires this every animation step of BOTH user gestures and\n // programmatic transitions, so the burst self-sustains for exactly\n // as long as the camera actually moves.\n this.requestTicks(2);\n this.emitViewportChange();\n },\n onZoomEnd: () => {\n this.requestTicks(2);\n this.emitViewportChange();\n },\n // --- gated-clock run reasons ---\n onSimulationStart: () => {\n this.wake('sim');\n },\n onSimulationUnpause: () => {\n this.wake('sim');\n },\n onSimulationPause: () => {\n this.sleep('sim');\n },\n onSimulationEnd: () => {\n this.sleep('sim');\n this.events?.onSimulationEnd?.();\n },\n onTransitionStart: () => {\n this.wake('transition');\n },\n onTransitionEnd: () => {\n this.sleep('transition');\n },\n };\n if (this.options.spaceSize !== undefined) base.spaceSize = this.options.spaceSize;\n // Escape hatch: shallow-merged last so callers can override anything\n // above — EXCEPT that callback keys defined on BOTH sides COMPOSE\n // (adapter's first, then the caller's) rather than clobber. The gated\n // clock's wake/sleep wiring and the host event channels live in these\n // callbacks; a caller supplying onSimulationStart/onZoom/onDragEnd/…\n // through initialConfig must not silently sever them.\n const extra = this.options.initialConfig as GraphConfig | undefined;\n if (!extra) return base;\n const merged: GraphConfig = { ...base, ...extra };\n for (const key of Object.keys(base)) {\n const ours = (base as Record<string, unknown>)[key];\n const theirs = (extra as Record<string, unknown>)[key];\n if (typeof ours === 'function' && typeof theirs === 'function') {\n (merged as Record<string, unknown>)[key] = (...args: unknown[]) => {\n (ours as (...a: unknown[]) => unknown)(...args);\n return (theirs as (...a: unknown[]) => unknown)(...args);\n };\n }\n }\n return merged;\n }\n\n /**\n * Maps cosmos' unified context-menu callback to the host event: index\n * undefined → null (background), MouseEvent client coords → container-\n * relative CSS px (the inner div fills the host container exactly). The\n * native event is preventDefault-ed so the browser menu never opens — but\n * only when the host actually registered onContextMenu (it always does in\n * Orbit: the core owns the typed 'contextMenu' event channel). cosmos'\n * desktop `contextmenu` handler already prevents the event itself; repeating\n * it is an idempotent no-op that also covers the touch long-press path\n * (where cosmos forwards the originating pointerdown event instead).\n */\n private handleContextMenu(index: number | undefined, event: MouseEvent): void {\n const events = this.events;\n if (!events?.onContextMenu) return;\n if (typeof event.preventDefault === 'function') event.preventDefault();\n const div = this.innerDiv;\n if (!div) return;\n const rect = div.getBoundingClientRect();\n events.onContextMenu(index ?? null, [event.clientX - rect.left, event.clientY - rect.top]);\n }\n\n /** Emits onPointClick(null) once per originating click event. */\n private emitNullPointClick(event: unknown): void {\n if (event != null && event === this.lastNullClickEvent) return;\n this.lastNullClickEvent = event ?? null;\n this.events?.onPointClick?.(null, clickModifiers(event));\n }\n\n /**\n * The D3 drag event carries no point index; cosmos assigns\n * `store.draggingPointIndex` right before invoking onDragStart (see module\n * header). The public onPointMouseOver stream is the fallback — cosmos only\n * starts a drag while a point is hovered.\n */\n private readDraggingIndex(): number | null {\n const store = (this.graph as unknown as { store?: CosmosStoreLike } | null)?.store;\n return store?.draggingPointIndex ?? store?.hoveredPoint?.index ?? this.lastHoverIndex;\n }\n\n private handleDragStart(): void {\n // Wake before the index resolution: the gesture is real (cosmos renders\n // it) even when the dragged-point fallback chain comes up empty.\n this.wake('drag');\n const index = this.readDraggingIndex();\n if (index === null) return;\n this.dragIndex = index;\n this.events?.onDragStart?.(index);\n }\n\n /**\n * Reports the dragged point's final SPACE position. cosmos' drag shader\n * pins the point to the mouse's space position every frame, so converting\n * the event's screen coords is exact and O(1) (see module header).\n */\n private handleDragEnd(e: { x: number; y: number }): void {\n // Release the run reason even when no index was latched — cosmos pairs\n // start/end, but a mid-gesture hover loss must not leak a held reason.\n this.sleep('drag');\n const index = this.dragIndex;\n this.dragIndex = null;\n if (index === null) return;\n const graph = this.activeGraph;\n if (!graph) return; // context died mid-gesture; the drag is dropped\n const [x, y] = graph.screenToSpacePosition([e.x, e.y]);\n this.events?.onDragEnd?.(index, x, y);\n }\n\n private emitViewportChange(): void {\n const viewport = this.getViewport();\n if (viewport) this.events?.onViewportChange?.(viewport);\n }\n\n /**\n * One visibly atomic update: all channels and config are staged, then\n * exactly one render draws them; restart reheats after the render.\n */\n private applyCommit(graph: CosmosGraph, update: EngineCommit): void {\n const { config, structure, buffers, resources, restart } = update;\n\n if (config) {\n if (config.seedRadius !== undefined) this.seedRadiusOverride = config.seedRadius;\n const partial: GraphConfig = {};\n if (config.backgroundColor !== undefined) partial.backgroundColor = config.backgroundColor;\n // arrowheads: cosmos' `linkDefaultArrows` config key (3.3.0\n // config.d.ts) — a pure config toggle, no per-link buffer involved.\n if (config.linkArrows !== undefined) partial.linkDefaultArrows = config.linkArrows;\n // link visibility: cosmos 3.3.0 has a first-class `renderLinks`\n // config key (config.d.ts, default true) — config-only, never a buffer\n // rebuild (no linkOpacity workaround needed).\n if (config.renderLinks !== undefined) partial.renderLinks = config.renderLinks;\n // theme tokens: cosmos accepts CSS color strings natively.\n if (config.defaultPointColor !== undefined) {\n partial.pointDefaultColor = config.defaultPointColor;\n }\n if (config.defaultLinkColor !== undefined) {\n partial.linkDefaultColor = config.defaultLinkColor;\n }\n // disable-transitions ladder step: 0 = atomic jumps; null restores\n // cosmos' own default (config.d.ts `transitionDuration`, 800ms).\n if (config.transitionDurationMs !== undefined) {\n partial.transitionDuration = config.transitionDurationMs ?? 800;\n }\n // emphasis ring: cosmos' FOCUSED ring (config.d.ts\n // `focusedPointRingColor`; drawn whenever a focused index is set — no\n // boolean gate). Deliberately NOT `renderHoveredPointRing`: that would\n // draw a second ring from cosmos' own hover state, and the focused path\n // is what lets orbit choose the ringed node (keyboard nav, focusNode).\n if (config.emphasisRingColor !== undefined) {\n partial.focusedPointRingColor = config.emphasisRingColor;\n }\n const sim = config.simulation;\n if (sim) {\n if (sim.gravity !== undefined) partial.simulationGravity = sim.gravity;\n if (sim.repulsion !== undefined) partial.simulationRepulsion = sim.repulsion;\n if (sim.friction !== undefined) partial.simulationFriction = sim.friction;\n if (sim.linkDistance !== undefined) partial.simulationLinkDistance = sim.linkDistance;\n if (sim.linkSpring !== undefined) partial.simulationLinkSpring = sim.linkSpring;\n // tunables added in v0.10.2 — each maps 1:1 onto a cosmos config\n // key; an omitted field is never written, so cosmos' own default\n // stands (config.d.ts `defaultConfigValues`).\n if (sim.decay !== undefined) partial.simulationDecay = sim.decay;\n if (sim.collision !== undefined) partial.simulationCollision = sim.collision;\n if (sim.collisionRadius !== undefined) {\n partial.simulationCollisionRadius = sim.collisionRadius;\n }\n if (sim.collisionPadding !== undefined) {\n partial.simulationCollisionPadding = sim.collisionPadding;\n }\n // cosmos >= 3.4 replaced Barnes-Hut many-body with grid-based\n // repulsion: `simulationRepulsionTheta` is deprecated and\n // NON-FUNCTIONAL. Sending it would misrepresent state, so the key is\n // not mapped; the host learns once instead of wondering silently.\n if (sim.repulsionTheta !== undefined && !this.repulsionThetaWarned) {\n this.repulsionThetaWarned = true;\n this.events?.onDiagnostic?.({\n code: 'engine:repulsion-theta-deprecated',\n severity: 'info',\n message:\n 'CosmosEngine: cosmos >= 3.4 uses grid-based repulsion; ' +\n 'simulation.repulsionTheta is ignored by this engine.',\n });\n }\n if (sim.center !== undefined) partial.simulationCenter = sim.center;\n if (sim.repulsionFromMouse !== undefined) {\n partial.simulationRepulsionFromMouse = sim.repulsionFromMouse;\n }\n }\n // stage-4 cluster force: the scene-wide coefficient is cosmos'\n // `simulationCluster` config key (config.d.ts, default 0.1); membership\n // and centers are buffer-shaped and staged below.\n if (config.cluster != null && config.cluster.strength !== undefined) {\n partial.simulationCluster = config.cluster.strength;\n }\n if (Object.keys(partial).length > 0) graph.setConfigPartial(partial);\n }\n\n if (structure) {\n this.lastPointCount = structure.pointCount;\n graph.setPointPositions(this.withSeededPositions(structure.positions));\n // cosmos takes link endpoint indices as Float32Array; exact for < 2^24 points.\n graph.setLinks(Float32Array.from(structure.links));\n }\n\n // Staged AFTER the roster so cosmos sees a membership array matching the\n // point count of this same commit (I2), and before the single render.\n if (config && config.cluster !== undefined) this.applyClusterForce(graph, config.cluster);\n\n if (buffers) {\n // [0,1] RGBA floats — cosmos' native scale; pass through (see header note).\n if (buffers.pointColor) graph.setPointColors(buffers.pointColor);\n if (buffers.pointSize) graph.setPointSizes(buffers.pointSize);\n if (buffers.linkColor) graph.setLinkColors(buffers.linkColor);\n if (buffers.linkWidth) graph.setLinkWidths(buffers.linkWidth);\n }\n\n // atlas resources are staged before the SAME render as every other\n // channel, keeping the commit visibly atomic.\n if (resources) this.applyResources(graph, resources);\n\n graph.render();\n this.applied = update.revision;\n\n if (restart) graph.start(restart.alpha);\n // write re-arm: the commit's render lands this tick; the burst lets\n // overlays sample the post-draw state. A restart additionally holds the\n // clock via the sim run reason (onSimulationStart → wake).\n if (restart) this.wake('sim');\n this.requestTicks(2);\n }\n\n /**\n * Applies the stage-4 cluster force (capability `clusterForce`).\n *\n * Contract mapping, verified against the 3.3.0 dist (`index.d.ts`):\n * - `pointClusters` (Float32Array, NaN = unclustered) →\n * `setPointClusters((number | undefined)[])`, where cosmos' documented\n * \"does not belong to any cluster\" value is `undefined`;\n * - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →\n * `setClusterPositions((number | undefined)[])`; a non-finite entry means\n * \"no position\" and cosmos falls back to that cluster's centermass;\n * - `null` clears: an all-`undefined` array of the CURRENT roster length\n * (length must track the roster) plus empty cluster positions.\n * `strength` is the scene-wide `simulationCluster` config coefficient\n * applied in the config block, not the per-point\n * `setPointClusterStrength` buffer (Orbit's strength is scene-wide).\n */\n private applyClusterForce(\n graph: CosmosGraph,\n cluster: NonNullable<EngineCommit['config']>['cluster'],\n ): void {\n if (cluster == null) {\n graph.setPointClusters(new Array<number | undefined>(this.lastPointCount).fill(undefined));\n graph.setClusterPositions([]);\n return;\n }\n const source = cluster.pointClusters;\n const assignments = new Array<number | undefined>(source.length);\n for (let i = 0; i < source.length; i++) {\n const value = source[i]!;\n assignments[i] = Number.isFinite(value) ? value : undefined;\n }\n graph.setPointClusters(assignments);\n const centers = cluster.centers;\n if (centers !== undefined) {\n const positions = new Array<number | undefined>(centers.length);\n for (let i = 0; i < centers.length; i++) {\n const value = centers[i]!;\n positions[i] = Number.isFinite(value) ? value : undefined;\n }\n graph.setClusterPositions(positions);\n }\n }\n\n /**\n * Applies the image-atlas channel: upserts convert ImageBitmap →\n * ImageData through an offscreen 2D canvas into the slot mirror, removals\n * blank their slot, and any atlas change re-uploads the FULL ImageData\n * array (cosmos' setImageData is whole-array only, matching\n * `rangeUpdates: []`). Environments without a usable 2D context (jsdom)\n * no-op the channel and report `engine:image-channel-unavailable` once\n * never throw.\n */\n private applyResources(graph: CosmosGraph, resources: EngineResources): void {\n const atlas = resources.imageAtlas;\n if (atlas) {\n let dirty = false;\n let conversionFailed = false;\n if (atlas.upserts) {\n for (const { slot, bitmap } of atlas.upserts) {\n if (!Number.isInteger(slot) || slot < 0) continue;\n const data = this.canvasImageData(bitmap.width, bitmap.height, bitmap);\n if (data === null) {\n conversionFailed = true;\n continue;\n }\n while (this.imageSlots.length <= slot) this.imageSlots.push(null);\n this.imageSlots[slot] = data;\n dirty = true;\n }\n }\n if (atlas.removeSlots) {\n for (const slot of atlas.removeSlots) {\n // Only slots that currently hold an image need blanking.\n if (slot >= 0 && slot < this.imageSlots.length && this.imageSlots[slot] != null) {\n this.imageSlots[slot] = null;\n dirty = true;\n }\n }\n }\n if (conversionFailed) this.reportImageChannelUnavailable();\n if (dirty) {\n const blank = this.blankImage ?? (this.blankImage = this.canvasImageData(1, 1));\n if (blank === null) {\n this.reportImageChannelUnavailable();\n } else {\n // Array.from (not.map) so sparse holes also materialize as blanks.\n graph.setImageData(Array.from(this.imageSlots, (d) => d ?? blank));\n }\n }\n }\n // Indices into an atlas that can never be populated are meaningless\n // once the channel is known-unavailable the whole channel no-ops.\n if (resources.pointImageIndex && !this.imageChannelUnavailable) {\n graph.setPointImageIndices(resources.pointImageIndex);\n }\n }\n\n /**\n * Reads an ImageData of the given size off an offscreen 2D canvas, drawing\n * `bitmap` onto it first when provided (ImageBitmap → ImageData transcode;\n * without a bitmap: a transparent blank). Returns null — never throws\n * where no 2D context exists (jsdom without the canvas package).\n */\n private canvasImageData(width: number, height: number, bitmap?: ImageBitmap): ImageData | null {\n const doc = this.innerDiv?.ownerDocument;\n if (!doc || !(width > 0) || !(height > 0)) return null;\n try {\n const canvas = doc.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n if (bitmap) ctx.drawImage(bitmap, 0, 0);\n return ctx.getImageData(0, 0, width, height);\n } catch {\n return null;\n }\n }\n\n /** Documented degradation, reported at most once per engine instance. */\n private reportImageChannelUnavailable(): void {\n if (this.imageChannelUnavailable) return;\n this.imageChannelUnavailable = true;\n this.events?.onDiagnostic?.({\n code: 'engine:image-channel-unavailable',\n severity: 'warning',\n message:\n 'CosmosEngine: no 2D canvas context is available to convert ImageBitmap ' +\n 'atlas entries to ImageData; point images are disabled in this environment.',\n });\n }\n\n /**\n * Replaces NaN pairs (= \"no known position\") with random points on a\n * ring of radius seedRadius around the space center. cosmos treats NaN\n * positions as *absent* points, so they must never reach setPointPositions.\n * Known positions pass through verbatim (same array when nothing to seed).\n */\n private withSeededPositions(positions: Float32Array): Float32Array {\n let needsSeeding = false;\n for (let i = 0; i < positions.length; i += 2) {\n if (Number.isNaN(positions[i]!) || Number.isNaN(positions[i + 1]!)) {\n needsSeeding = true;\n break;\n }\n }\n if (!needsSeeding) return positions;\n\n const out = Float32Array.from(positions);\n const center = this.spaceSize / 2;\n const radius = this.seedRadius;\n for (let i = 0; i < out.length; i += 2) {\n if (Number.isNaN(out[i]!) || Number.isNaN(out[i + 1]!)) {\n const angle = Math.random() * Math.PI * 2;\n out[i] = center + radius * Math.cos(angle);\n out[i + 1] = center + radius * Math.sin(angle);\n }\n }\n return out;\n }\n}\n\n/**\n * Per-channel merge for queued resources (pre-mount / context-lost):\n * upserts union per slot (latest bitmap wins), a later remove drops an\n * earlier pending upsert of the same slot (and vice versa — folding order\n * mirrors applyResources: upserts before removes within each commit), and\n * the latest pointImageIndex replaces wholesale.\n */\nfunction mergeResources(\n previous: EngineCommit['resources'],\n update: EngineCommit['resources'],\n): EngineResources {\n const upsertBySlot = new Map<number, ImageBitmap>();\n const removes = new Set<number>();\n for (const atlas of [previous?.imageAtlas, update?.imageAtlas]) {\n if (!atlas) continue;\n for (const { slot, bitmap } of atlas.upserts ?? []) {\n upsertBySlot.set(slot, bitmap);\n removes.delete(slot);\n }\n for (const slot of atlas.removeSlots ?? []) {\n upsertBySlot.delete(slot);\n removes.add(slot);\n }\n }\n const merged: EngineResources = {};\n if (upsertBySlot.size > 0 || removes.size > 0) {\n const imageAtlas: NonNullable<EngineResources['imageAtlas']> = {};\n if (upsertBySlot.size > 0) {\n imageAtlas.upserts = Array.from(upsertBySlot, ([slot, bitmap]) => ({ slot, bitmap }));\n }\n if (removes.size > 0) imageAtlas.removeSlots = Array.from(removes);\n merged.imageAtlas = imageAtlas;\n }\n const pointImageIndex = update?.pointImageIndex ?? previous?.pointImageIndex;\n if (pointImageIndex !== undefined) merged.pointImageIndex = pointImageIndex;\n return merged;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernrelay/orbit-engine-cosmos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "cosmos.gl engine adapter for Orbit: GPU force layout, native picking, context-loss recovery.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@cosmos.gl/graph": "3.4.0",
|
|
27
|
-
"@modernrelay/orbit-core": "0.
|
|
27
|
+
"@modernrelay/orbit-core": "0.14.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.6.0",
|