@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 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). Any pin bump requires re-running the M0 probe suite and
9
- regenerating the conformance matrix before the new version is considered
10
- supported. (3.3.0 3.4.0 re-probed 2026-08-10: all 11 rows green the
11
- quiescence row flipped to PASS on upstream on-demand rendering, ADR-005.)
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 (quiescence row below; ADR-005). |
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-07-21 on Apple M5 Pro, ANGLE Metal, headful
25
- Chromium; evidence in `docs/evidence/m0/`):
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 in S6:** the adapter now reports `capabilities.linkPicking: true` and wires `onLinkClick`/`onLinkMouseOver`/`onLinkMouseOut` to the host events, backed by this record ([full matrix](../../docs/m0-conformance.md)). |
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 (ADR-001 stands). |
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 (match 1.0). This validates the adapter's recreate-on-restore protocol: `CosmosEngine` rebuilds the Graph in the same container and the core replays the scene. |
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
- The full, generated matrix (including deferred areas: `mobile`, `resize`,
39
- `resource-estimates`) lives at [docs/m0-conformance.md](../../docs/m0-conformance.md).
40
+ ## Interaction surface
40
41
 
41
- ## Interaction surface (S6)
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 (S7)
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 (ADR-005): 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`). |
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 3.3.0 d.ts; the dist flips Y assuming ordered corners) — no conversion. |
66
- | `captureScreenshot()` | Resolves a PNG `Blob` of the current frame, or `null` when unsupported, not ready, lost, or on any capture failure. | The M0 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 (ADR-005). |
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 (S10)
67
+ ## Styling channels
69
68
 
70
- Facts verified against the 3.3.0 dist typings (`config.d.ts` / `index.d.ts`):
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.3.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. |
76
- | `renderLinks` toggle | config-only | cosmos 3.3.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. |
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 (S12, §16.3 stage 4)
83
+ ## Cluster force
85
84
 
86
85
  | Capability | Value | Mechanism / basis |
87
86
  | --- | --- | --- |
88
- | `clusterForce` | `true` | **Dist investigation (3.3.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 is not yet GPU-probed; a headful probe record is the S13 conformance follow-up (see the GPU evidence policy below).** |
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 (S11)
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.** cosmos 3.3 has no pan-to API, but `setZoomTransformByPointPositions(positions, duration, scale, padding)` is an exact center+zoom when `scale` is explicit — verified in the 3.3.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())`. |
113
- | §13.1 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 "viewport restore is zoom-only" caveat recorded in ADR-004 / spec §13.1 for cosmos 3.3. |
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 never produces GPU evidence: it re-runs only the
120
- Node-safe probes (`pnpm probe:node`) and validates the committed matrix
121
- (`pnpm conformance:check`). Results rendered through SwiftShader or any other
122
- software rasterizer are not accepted as conformance evidence — headless runs
123
- are permitted solely as a harness smoke test and their records must not be
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 (spec §13).
4
+ * CosmosEngine — GraphEngine adapter over @cosmos.gl/graph.
5
5
  *
6
- * Node-safe module: cosmos is loaded lazily via `await import()` inside
7
- * `mount()` (§18); module scope carries only type-only imports (erased at
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
- * - 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 (S11 the 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 §13.1 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).
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 (ADR-005; M0 evidence docs/m0-conformance.md):
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 M0 same-tick capture method (apps/spike/src/instrument.ts):
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
- * - 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).
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 (§16.3). */
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 M0 same-tick method (see module
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
- * 1. the tick budget is consumed BEFORE the host callback runs, so work
220
- * scheduled from inside onFrame re-arms a fresh tick instead of being
221
- * coalesced away;
222
- * 2. the reschedule/stop decision is made BEFORE the host callback, so a
223
- * throwing host can never kill a should-keep-running clock (and a
224
- * stopping clock stays stopped even if the callback wakes it — the
225
- * wake starts a new loop via requestTicks/wake, not this handle).
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 (§13): all channels and config are staged, then
311
- * exactly one render() draws them; restart reheats after the 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 §16.3 stage-4 cluster force (capability `clusterForce`).
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
- * - `pointClusters` (Float32Array, NaN = unclustered) →
319
- * `setPointClusters((number | undefined)[])`, where cosmos' documented
320
- * "does not belong to any cluster" value is `undefined`;
321
- * - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →
322
- * `setClusterPositions((number | undefined)[])`; a non-finite entry means
323
- * "no position" and cosmos falls back to that cluster's centermass;
324
- * - `null` clears: an all-`undefined` array of the CURRENT roster length
325
- * (length must track the roster) plus empty cluster positions.
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 §8 image-atlas channel: upserts convert ImageBitmap →
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", §7.3) with random points on a
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 S6 flip: the M0 probe measured native onLinkClick/
70
+ // Evidence-backed flip: the probe measured native onLinkClick/
71
71
  // onLinkMouseOver delivering correct link indices with ~4px perpendicular
72
- // tolerance (docs/m0-conformance.json, `link-picking`).
72
+ // tolerance.
73
73
  linkPicking: true,
74
74
  rangeUpdates: [],
75
75
  trackedPositions: true,
76
76
  simulation: true,
77
- // §16.12: cosmos 3.3.0 exposes the `linkDefaultArrows` config key
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
- // §8: cosmos 3.3.0 exposes setImageData(ImageData[]) +
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
- // §16.3 stage 4: cosmos 3.3.0 ships a real GPU cluster force
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
- // §17 stop-at-rest: cosmos 3.4.0 ships on-demand rendering — the M0
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 (docs/m0-conformance.md, was 91 on 3.3.0/ADR-002).
95
- // The adapter's own activity clock is gated to match (ADR-005).
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 (ADR-002).
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 (§16.3). */
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 (§13.1) ---
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
- // --- §8 image atlas (capability pointImages) ---
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 (§13/§15) ---
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 M0 same-tick method (see module
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
- * 1. the tick budget is consumed BEFORE the host callback runs, so work
429
- * scheduled from inside onFrame re-arms a fresh tick instead of being
430
- * coalesced away;
431
- * 2. the reschedule/stop decision is made BEFORE the host callback, so a
432
- * throwing host can never kill a should-keep-running clock (and a
433
- * stopping clock stays stopped even if the callback wakes it — the
434
- * wake starts a new loop via requestTicks/wake, not this handle).
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 (§13.1) ---
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. One variable at a time flipping it is a
670
- // registered follow-up with its own threshold re-validation.
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 (§16.3).
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) this.emitNullPointClick(event);
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 (§17 stop-at-rest, ADR-005) ---
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 (§13): all channels and config are staged, then
830
- * exactly one render() draws them; restart reheats after the 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 §16.3 stage-4 cluster force (capability `clusterForce`).
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
- * - `pointClusters` (Float32Array, NaN = unclustered) →
909
- * `setPointClusters((number | undefined)[])`, where cosmos' documented
910
- * "does not belong to any cluster" value is `undefined`;
911
- * - `centers` (Float32Array, `[x0,y0,x1,y1,…]`) →
912
- * `setClusterPositions((number | undefined)[])`; a non-finite entry means
913
- * "no position" and cosmos falls back to that cluster's centermass;
914
- * - `null` clears: an all-`undefined` array of the CURRENT roster length
915
- * (length must track the roster) plus empty cluster positions.
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 §8 image-atlas channel: upserts convert ImageBitmap →
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", §7.3) with random points on a
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.13.5",
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.13.5"
27
+ "@modernrelay/orbit-core": "0.14.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "typescript": "^5.6.0",