@modernrelay/orbit-engine-cosmos 0.2.0 → 0.13.6

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
@@ -4,10 +4,11 @@ Cosmos engine adapter for Orbit.
4
4
 
5
5
  ## Tested engine range
6
6
 
7
- This adapter is developed and probed against exactly **`@cosmos.gl/graph@3.3.0`**
7
+ This adapter is developed and probed against exactly **`@cosmos.gl/graph@3.4.0`**
8
8
  (exact pin, no range). Any pin bump requires re-running the M0 probe suite and
9
9
  regenerating the conformance matrix before the new version is considered
10
- supported.
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.)
11
12
 
12
13
  ## Capability profile
13
14
 
@@ -16,7 +17,8 @@ Node-verifiable facts (measured by `pnpm probe:node`, re-checked in CI):
16
17
  | Capability | Value | Basis |
17
18
  | --- | --- | --- |
18
19
  | `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. |
19
- | `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. |
20
+ | `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). |
20
22
  | `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. |
21
23
 
22
24
  GPU-probed capabilities (measured 2026-07-21 on Apple M5 Pro, ANGLE Metal, headful
@@ -29,8 +31,8 @@ Chromium; evidence in `docs/evidence/m0/`):
29
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)). |
30
32
  | `nan-tombstones` | ✅ pass | NaN'd points escape hit-testing, incident links vanish, `fitView` ignores tombstoned slots. |
31
33
  | `native-pinning` | ✅ pass | `setPinnedPoints` excludes points from force integration; `[]`/repeat calls are idempotent. |
32
- | `tracked-positions` | ⚠️ fail (budget) | Semantics correct (packing order, last-call-replaces), but each `getTrackedPointPositionsArray` read stalls ~18 ms p50 **regardless of k** (256→16384) — a sync pipeline flush, not payload cost. Per-frame tracked readback is not viable on 3.3.0; DOM-label positioning must read at settle/idle cadence. |
33
- | `quiescence` | ⚠️ fail | The render loop free-runs at display refresh whenever data is present (`stopFrames` fires only on empty scene/destroy) 91 frames in a 750 ms idle window. Orbit must impose stop-at-rest externally (plan S13-T06). |
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). |
35
+ | `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). |
34
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. |
35
37
 
36
38
  The full, generated matrix (including deferred areas: `mobile`, `resize`,
@@ -58,10 +60,10 @@ Coordinate-space facts verified against the 3.3.0 dist (see the
58
60
 
59
61
  | Capability | Behavior | Basis / degradation |
60
62
  | --- | --- | --- |
61
- | `onFrame` activity clock | The adapter owns a single `requestAnimationFrame` loop: started at mount, stopped on context loss and `destroy()`, resumed after recovery. Each tick is one `onFrame(timeMs)` call (the core skips all work when nothing subscribes); the callback is skipped while `document.hidden` (the clock keeps ticking). | **Documented degradation:** cosmos 3.3.0 exposes no draw/render-phase hook (`postDrawFrames: false`), so this is an *activity* clock, not a post-draw hook — DOM overlays (labels, tooltips) may lag the canvas by one frame. Reported once at mount via the `engine:overlay-activity-clock` info diagnostic. Stop-at-rest quiescence is S13 scope. |
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
64
  | `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. |
63
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. |
64
- | `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 the adapter schedules one rAF and captures inside it. |
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). |
65
67
 
66
68
  ## Styling channels (S10)
67
69
 
package/dist/index.d.ts CHANGED
@@ -53,14 +53,24 @@ import { GraphEngine, EngineCapabilities, EngineHostEvents, EngineCommit, FitVie
53
53
  * with index undefined and is reported as background (the host event
54
54
  * carries node-or-background only).
55
55
  *
56
- * Overlay/activity clock (M0 evidence, docs/m0-conformance.md): cosmos exposes
57
- * no draw/render-phase hook (`postDrawFrames: false`), so the adapter owns a
58
- * single requestAnimationFrame loop that reports `onFrame(timeMs)` to the host
59
- * — an ACTIVITY clock, not a post-draw hook: overlays may lag the canvas by
60
- * one sample. That degradation is reported once at mount via the
61
- * `engine:overlay-activity-clock` info diagnostic. The loop is started at
62
- * mount, stopped on context loss/destroy, resumed on recovery, and skips the
63
- * callback while `document.hidden` (stop-at-rest quiescence is S13 scope).
56
+ * GATED overlay/activity clock (ADR-005; M0 evidence docs/m0-conformance.md):
57
+ * cosmos still exposes no draw/render-phase hook (`postDrawFrames: false`),
58
+ * so the adapter owns the single requestAnimationFrame loop that reports
59
+ * `onFrame(timeMs)` to the host — an ACTIVITY clock, not a post-draw hook:
60
+ * overlays may lag the canvas by one sample (reported once at mount via
61
+ * `engine:overlay-activity-clock`). Since cosmos 3.4 idle-stops its own
62
+ * rendering (on-demand rendering, quiescence probe: 0 idle frames/750ms),
63
+ * this clock is GATED to match — it free-runs only while a run reason is
64
+ * held (sim hot via onSimulationStart/Pause/Unpause/End, drag gestures,
65
+ * cosmos transitions) and otherwise burns a small one-shot tick budget that
66
+ * every visual write re-arms (commits, highlight/focus/pin setters, camera
67
+ * moves, hover events; animated camera moves self-sustain through per-step
68
+ * onZoom bursts). Releasing a run reason always grants ONE trailing tick —
69
+ * the releasing activity's final GPU write lands after the current draw
70
+ * pass. At rest: zero rAF registrations from cosmos AND from this adapter
71
+ * (`capabilities.idleFrames: 'stops'`). The clock stops on context
72
+ * loss/destroy, re-arms on recovery, and skips the callback (keeping its
73
+ * schedule) while `document.hidden`.
64
74
  *
65
75
  * Screenshots use the M0 same-tick capture method (apps/spike/src/instrument.ts):
66
76
  * cosmos renders with preserveDrawingBuffer:false, so the WebGL buffer is only
@@ -133,10 +143,19 @@ declare class CosmosEngine implements GraphEngine {
133
143
  private dragIndex;
134
144
  /** Last hover reported by cosmos — fallback dragged-point source. */
135
145
  private lastHoverIndex;
146
+ /** Live native link hover (review P1: gates the unified onClick's
147
+ * background interpretation — a hovered link owns the click). */
148
+ private hoveredLinkIndex;
136
149
  /** rAF id of the pending activity-clock tick; null = clock not running. */
137
150
  private frameHandle;
138
151
  /** Window driving the clock, cached so stop works after the div detaches. */
139
152
  private frameWindow;
153
+ /** Continuous-run reasons; the clock free-runs while any is held. */
154
+ private readonly runReasons;
155
+ /** One-shot tick budget for write/interaction re-arm bursts. */
156
+ private pendingTicks;
157
+ /** One-shot guard for the repulsionTheta deprecation diagnostic. */
158
+ private repulsionThetaWarned;
140
159
  /** cosmos' canvas (queried post-mount) carrying the webglcontext* listeners. */
141
160
  private canvas;
142
161
  private contextLost;
@@ -199,13 +218,34 @@ declare class CosmosEngine implements GraphEngine {
199
218
  captureScreenshot(): Promise<Blob | null>;
200
219
  destroy(): void;
201
220
  /**
202
- * One rAF tick of the activity clock. Reschedules FIRST so a throwing host
203
- * callback can never kill the clock; skips the callback (but keeps ticking)
204
- * while the document is hidden. Deliberately cheap: a single callback
205
- * invocation — the core skips all work when nothing subscribes.
221
+ * One rAF tick of the gated activity clock. Ordering is load-bearing:
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).
229
+ * Skips the callback (but keeps its schedule) while the document is hidden.
206
230
  */
207
231
  private readonly frameTick;
208
- private startFrameLoop;
232
+ /** Hold the clock open for a continuous activity (sim/drag/transition). */
233
+ private wake;
234
+ /**
235
+ * Release a continuous-run reason. ALWAYS grants one trailing tick: the
236
+ * releasing activity's final GPU write lands after the current draw pass
237
+ * (the upstream drag-release bug class), so overlays need one more sample.
238
+ */
239
+ private sleep;
240
+ /**
241
+ * Grant a one-shot tick budget (write/interaction re-arm). Two ticks is
242
+ * the standard write burst: ordering between this clock's rAF callback and
243
+ * cosmos' internal render frame within one tick is unguaranteed, so the
244
+ * second tick guarantees overlays sample post-draw state (consistent with
245
+ * the documented may-lag-one-sample degradation).
246
+ */
247
+ private requestTicks;
248
+ private ensureFrameLoop;
209
249
  private stopFrameLoop;
210
250
  /** The graph, unless it is unusable (context lost / terminally failed). */
211
251
  private get activeGraph();
package/dist/index.js CHANGED
@@ -88,7 +88,16 @@ var CosmosEngine = class {
88
88
  // default 0.1) and the `Clusters` core module (dist/modules/Clusters).
89
89
  // `undefined` is cosmos' documented "not in any cluster" value, which the
90
90
  // adapter maps from the contract's NaN.
91
- clusterForce: true
91
+ clusterForce: true,
92
+ // §17 stop-at-rest: cosmos 3.4.0 ships on-demand rendering — the M0
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).
96
+ idleFrames: "stops",
97
+ // onFrame is an activity clock, not an exact post-draw hook — cosmos
98
+ // still exposes no public frame hook (probe `post-draw-frames`);
99
+ // overlays may lag one sample (ADR-002).
100
+ postDrawFrames: false
92
101
  };
93
102
  options;
94
103
  graph = null;
@@ -120,11 +129,20 @@ var CosmosEngine = class {
120
129
  dragIndex = null;
121
130
  /** Last hover reported by cosmos — fallback dragged-point source. */
122
131
  lastHoverIndex = null;
123
- // --- adapter-owned overlay/activity clock (see module header) ---
132
+ /** Live native link hover (review P1: gates the unified onClick's
133
+ * background interpretation — a hovered link owns the click). */
134
+ hoveredLinkIndex = null;
135
+ // --- adapter-owned GATED overlay/activity clock (see module header) ---
124
136
  /** rAF id of the pending activity-clock tick; null = clock not running. */
125
137
  frameHandle = null;
126
138
  /** Window driving the clock, cached so stop works after the div detaches. */
127
139
  frameWindow = null;
140
+ /** Continuous-run reasons; the clock free-runs while any is held. */
141
+ runReasons = /* @__PURE__ */ new Set();
142
+ /** One-shot tick budget for write/interaction re-arm bursts. */
143
+ pendingTicks = 0;
144
+ /** One-shot guard for the repulsionTheta deprecation diagnostic. */
145
+ repulsionThetaWarned = false;
128
146
  // --- WebGL context-loss recovery state (§13.1) ---
129
147
  /** cosmos' canvas (queried post-mount) carrying the webglcontext* listeners. */
130
148
  canvas = null;
@@ -180,9 +198,16 @@ var CosmosEngine = class {
180
198
  events.onDiagnostic?.({
181
199
  code: "engine:overlay-activity-clock",
182
200
  severity: "info",
183
- message: "CosmosEngine: cosmos exposes no draw-phase hook (postDrawFrames:false); overlays ride an adapter-owned requestAnimationFrame activity clock and may lag the canvas by one frame."
201
+ message: "CosmosEngine: cosmos exposes no draw-phase hook (postDrawFrames:false); overlays ride an adapter-owned, idle-gated requestAnimationFrame activity clock (stops at rest \u2014 idleFrames:stops) and may lag the canvas by one frame."
184
202
  });
185
- this.startFrameLoop();
203
+ if (this.options.initialConfig?.showFPSMonitor) {
204
+ events.onDiagnostic?.({
205
+ code: "engine:fps-monitor-defeats-quiescence",
206
+ severity: "info",
207
+ message: "CosmosEngine: showFPSMonitor keeps cosmos rendering every frame; stop-at-rest quiescence is disabled while it is shown."
208
+ });
209
+ }
210
+ this.requestTicks(2);
186
211
  const pending = this.pendingCommit;
187
212
  this.pendingCommit = null;
188
213
  if (pending) this.applyCommit(graph, pending);
@@ -217,13 +242,18 @@ var CosmosEngine = class {
217
242
  return this.applied;
218
243
  }
219
244
  // --- camera ---
245
+ // Every camera write re-arms the clock; ANIMATED moves then self-sustain
246
+ // through cosmos' per-step onZoom events (each grants a fresh burst), so
247
+ // no duration bookkeeping is needed here.
220
248
  fitView(opts) {
221
249
  this.activeGraph?.fitView(opts?.durationMs, opts?.padding);
250
+ this.requestTicks(2);
222
251
  }
223
252
  zoom(factor, durationMs) {
224
253
  const graph = this.activeGraph;
225
254
  if (!graph) return;
226
255
  graph.setZoomLevel(graph.getZoomLevel() * factor, durationMs);
256
+ this.requestTicks(2);
227
257
  }
228
258
  /**
229
259
  * REAL pan (the former zoom-only limitation is lifted — see module header):
@@ -249,10 +279,12 @@ var CosmosEngine = class {
249
279
  opts?.durationMs ?? 0,
250
280
  v.zoom ?? graph.getZoomLevel()
251
281
  );
282
+ this.requestTicks(2);
252
283
  return;
253
284
  }
254
285
  }
255
286
  if (v.zoom !== void 0) graph.setZoomLevel(v.zoom, opts?.durationMs ?? 0);
287
+ this.requestTicks(2);
256
288
  }
257
289
  getViewport() {
258
290
  const graph = this.activeGraph;
@@ -263,12 +295,15 @@ var CosmosEngine = class {
263
295
  }
264
296
  zoomToIndex(index, durationMs) {
265
297
  this.activeGraph?.zoomToPointByIndex(index, durationMs);
298
+ this.requestTicks(2);
266
299
  }
267
300
  // --- simulation ---
268
301
  start(alpha) {
302
+ this.wake("sim");
269
303
  this.activeGraph?.start(alpha);
270
304
  }
271
305
  pause() {
306
+ this.sleep("sim");
272
307
  this.activeGraph?.pause();
273
308
  }
274
309
  // --- built-in interaction visuals ---
@@ -278,6 +313,7 @@ var CosmosEngine = class {
278
313
  graph.setConfigPartial({
279
314
  highlightedPointIndices: indices === null ? void 0 : Array.from(indices)
280
315
  });
316
+ this.requestTicks(2);
281
317
  }
282
318
  setFocusedIndex(index) {
283
319
  const graph = this.activeGraph;
@@ -285,6 +321,7 @@ var CosmosEngine = class {
285
321
  graph.setConfigPartial({
286
322
  focusedPointIndex: index === null ? void 0 : index
287
323
  });
324
+ this.requestTicks(2);
288
325
  }
289
326
  // --- spatial queries & pinning (§13/§15) ---
290
327
  pointsInPolygon(screenPolygon) {
@@ -316,6 +353,7 @@ var CosmosEngine = class {
316
353
  }
317
354
  setPinnedIndices(indices) {
318
355
  this.activeGraph?.setPinnedPoints(indices === null ? null : Array.from(indices));
356
+ this.requestTicks(2);
319
357
  }
320
358
  // --- readback ---
321
359
  getPositions() {
@@ -331,9 +369,15 @@ var CosmosEngine = class {
331
369
  * context lost/failed, destroyed, no 2D context, toBlob failure).
332
370
  */
333
371
  captureScreenshot() {
334
- const canvas = this.activeGraph ? this.canvas : null;
372
+ const graph = this.activeGraph;
373
+ const canvas = graph ? this.canvas : null;
335
374
  const win = canvas?.ownerDocument.defaultView ?? null;
336
- if (!canvas || !win || typeof win.requestAnimationFrame !== "function") {
375
+ if (!graph || !canvas || !win || typeof win.requestAnimationFrame !== "function") {
376
+ return Promise.resolve(null);
377
+ }
378
+ try {
379
+ graph.render();
380
+ } catch {
337
381
  return Promise.resolve(null);
338
382
  }
339
383
  return new Promise((resolve) => {
@@ -381,20 +425,54 @@ var CosmosEngine = class {
381
425
  this.imageSlots = [];
382
426
  this.blankImage = null;
383
427
  }
384
- // --- overlay/activity clock (see module header) ---
428
+ // --- gated overlay/activity clock (see module header) ---
385
429
  /**
386
- * One rAF tick of the activity clock. Reschedules FIRST so a throwing host
387
- * callback can never kill the clock; skips the callback (but keeps ticking)
388
- * while the document is hidden. Deliberately cheap: a single callback
389
- * invocation — the core skips all work when nothing subscribes.
430
+ * One rAF tick of the gated activity clock. Ordering is load-bearing:
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).
438
+ * Skips the callback (but keeps its schedule) while the document is hidden.
390
439
  */
391
440
  frameTick = (timeMs) => {
392
441
  const win = this.frameWindow;
393
442
  if (!win || this.frameHandle === null) return;
394
- this.frameHandle = win.requestAnimationFrame(this.frameTick);
443
+ if (this.pendingTicks > 0) this.pendingTicks -= 1;
444
+ const keepRunning = this.runReasons.size > 0 || this.pendingTicks > 0;
445
+ this.frameHandle = keepRunning ? win.requestAnimationFrame(this.frameTick) : null;
446
+ if (!keepRunning) this.frameWindow = null;
395
447
  if (!win.document.hidden) this.events?.onFrame?.(timeMs);
396
448
  };
397
- startFrameLoop() {
449
+ /** Hold the clock open for a continuous activity (sim/drag/transition). */
450
+ wake(reason) {
451
+ this.runReasons.add(reason);
452
+ this.ensureFrameLoop();
453
+ }
454
+ /**
455
+ * Release a continuous-run reason. ALWAYS grants one trailing tick: the
456
+ * releasing activity's final GPU write lands after the current draw pass
457
+ * (the upstream drag-release bug class), so overlays need one more sample.
458
+ */
459
+ sleep(reason) {
460
+ this.runReasons.delete(reason);
461
+ this.requestTicks(1);
462
+ }
463
+ /**
464
+ * Grant a one-shot tick budget (write/interaction re-arm). Two ticks is
465
+ * the standard write burst: ordering between this clock's rAF callback and
466
+ * cosmos' internal render frame within one tick is unguaranteed, so the
467
+ * second tick guarantees overlays sample post-draw state (consistent with
468
+ * the documented may-lag-one-sample degradation).
469
+ */
470
+ requestTicks(n) {
471
+ if (this.destroyed || this.contextLost || this.failed || !this.graph) return;
472
+ this.pendingTicks = Math.max(this.pendingTicks, n);
473
+ this.ensureFrameLoop();
474
+ }
475
+ ensureFrameLoop() {
398
476
  if (this.destroyed || this.frameHandle !== null) return;
399
477
  const win = this.innerDiv?.ownerDocument.defaultView ?? null;
400
478
  if (!win || typeof win.requestAnimationFrame !== "function") return;
@@ -407,6 +485,8 @@ var CosmosEngine = class {
407
485
  this.frameHandle = null;
408
486
  }
409
487
  this.frameWindow = null;
488
+ this.runReasons.clear();
489
+ this.pendingTicks = 0;
410
490
  }
411
491
  // --- WebGL context-loss recovery (§13.1) ---
412
492
  /** The graph, unless it is unusable (context lost / terminally failed). */
@@ -498,7 +578,7 @@ var CosmosEngine = class {
498
578
  this.graph = graph;
499
579
  this.attachContextListeners();
500
580
  this.contextLost = false;
501
- this.startFrameLoop();
581
+ this.requestTicks(2);
502
582
  const pending = this.pendingCommit;
503
583
  this.pendingCommit = null;
504
584
  if (pending) this.applyCommit(graph, pending);
@@ -586,18 +666,26 @@ var CosmosEngine = class {
586
666
  const base = {
587
667
  // Default false: the core owns the camera (fitView is driven explicitly).
588
668
  fitViewOnInit: this.options.fitViewOnInit ?? false,
669
+ // cosmos 3.4 defaults this to true. Pinned OFF for the 3.4 upgrade:
670
+ // occlusion culling changes which overlapping pixels draw, and the M5
671
+ // pixel-diff thresholds (CHANGED_MIN/RESTORED_MAX) were tuned against
672
+ // un-culled rendering. One variable at a time — flipping it is a
673
+ // registered follow-up with its own threshold re-validation.
674
+ pointOcclusionCulling: false,
589
675
  // Native point dragging; the core owns pin semantics on top (§16.3).
590
676
  enableDrag: this.options.enableDrag ?? true,
591
677
  onPointClick: (index, _position, event) => {
592
678
  this.events?.onPointClick?.(index, clickModifiers(event));
593
679
  },
594
680
  onBackgroundClick: (event) => {
595
- this.emitNullPointClick(event);
681
+ if (this.hoveredLinkIndex === null) this.emitNullPointClick(event);
596
682
  },
597
683
  // onClick fires for every canvas click; an undefined index means no
598
684
  // point was hit (background clicks — link clicks arrive via onLinkClick).
599
685
  onClick: (index, _position, event) => {
600
- if (index === void 0) this.emitNullPointClick(event);
686
+ if (index === void 0 && this.hoveredLinkIndex === null) {
687
+ this.emitNullPointClick(event);
688
+ }
601
689
  },
602
690
  // Unified context-menu channel: fires exactly once per gesture (desktop
603
691
  // right-click AND touch long-press — cosmos synthesizes the latter);
@@ -609,10 +697,12 @@ var CosmosEngine = class {
609
697
  },
610
698
  onPointMouseOver: (index) => {
611
699
  this.lastHoverIndex = index;
700
+ this.requestTicks(1);
612
701
  this.events?.onPointHover?.(index);
613
702
  },
614
703
  onPointMouseOut: () => {
615
704
  this.lastHoverIndex = null;
705
+ this.requestTicks(1);
616
706
  this.events?.onPointHover?.(null);
617
707
  },
618
708
  // Setting any onLink* callback enables cosmos' native link hit-testing.
@@ -620,9 +710,13 @@ var CosmosEngine = class {
620
710
  this.events?.onLinkClick?.(linkIndex);
621
711
  },
622
712
  onLinkMouseOver: (linkIndex) => {
713
+ this.hoveredLinkIndex = linkIndex;
714
+ this.requestTicks(1);
623
715
  this.events?.onLinkHover?.(linkIndex);
624
716
  },
625
717
  onLinkMouseOut: () => {
718
+ this.hoveredLinkIndex = null;
719
+ this.requestTicks(1);
626
720
  this.events?.onLinkHover?.(null);
627
721
  },
628
722
  onDragStart: () => {
@@ -632,17 +726,49 @@ var CosmosEngine = class {
632
726
  this.handleDragEnd(e);
633
727
  },
634
728
  onZoom: () => {
729
+ this.requestTicks(2);
635
730
  this.emitViewportChange();
636
731
  },
637
732
  onZoomEnd: () => {
733
+ this.requestTicks(2);
638
734
  this.emitViewportChange();
639
735
  },
736
+ // --- gated-clock run reasons (§17 stop-at-rest, ADR-005) ---
737
+ onSimulationStart: () => {
738
+ this.wake("sim");
739
+ },
740
+ onSimulationUnpause: () => {
741
+ this.wake("sim");
742
+ },
743
+ onSimulationPause: () => {
744
+ this.sleep("sim");
745
+ },
640
746
  onSimulationEnd: () => {
747
+ this.sleep("sim");
641
748
  this.events?.onSimulationEnd?.();
749
+ },
750
+ onTransitionStart: () => {
751
+ this.wake("transition");
752
+ },
753
+ onTransitionEnd: () => {
754
+ this.sleep("transition");
642
755
  }
643
756
  };
644
757
  if (this.options.spaceSize !== void 0) base.spaceSize = this.options.spaceSize;
645
- return { ...base, ...this.options.initialConfig };
758
+ const extra = this.options.initialConfig;
759
+ if (!extra) return base;
760
+ const merged = { ...base, ...extra };
761
+ for (const key of Object.keys(base)) {
762
+ const ours = base[key];
763
+ const theirs = extra[key];
764
+ if (typeof ours === "function" && typeof theirs === "function") {
765
+ merged[key] = (...args) => {
766
+ ours(...args);
767
+ return theirs(...args);
768
+ };
769
+ }
770
+ }
771
+ return merged;
646
772
  }
647
773
  /**
648
774
  * Maps cosmos' unified context-menu callback to the host event: index
@@ -681,6 +807,7 @@ var CosmosEngine = class {
681
807
  return store?.draggingPointIndex ?? store?.hoveredPoint?.index ?? this.lastHoverIndex;
682
808
  }
683
809
  handleDragStart() {
810
+ this.wake("drag");
684
811
  const index = this.readDraggingIndex();
685
812
  if (index === null) return;
686
813
  this.dragIndex = index;
@@ -692,6 +819,7 @@ var CosmosEngine = class {
692
819
  * the event's screen coords is exact and O(1) (see module header).
693
820
  */
694
821
  handleDragEnd(e) {
822
+ this.sleep("drag");
695
823
  const index = this.dragIndex;
696
824
  this.dragIndex = null;
697
825
  if (index === null) return;
@@ -722,6 +850,12 @@ var CosmosEngine = class {
722
850
  if (config.defaultLinkColor !== void 0) {
723
851
  partial.linkDefaultColor = config.defaultLinkColor;
724
852
  }
853
+ if (config.transitionDurationMs !== void 0) {
854
+ partial.transitionDuration = config.transitionDurationMs ?? 800;
855
+ }
856
+ if (config.emphasisRingColor !== void 0) {
857
+ partial.focusedPointRingColor = config.emphasisRingColor;
858
+ }
725
859
  const sim = config.simulation;
726
860
  if (sim) {
727
861
  if (sim.gravity !== void 0) partial.simulationGravity = sim.gravity;
@@ -737,8 +871,13 @@ var CosmosEngine = class {
737
871
  if (sim.collisionPadding !== void 0) {
738
872
  partial.simulationCollisionPadding = sim.collisionPadding;
739
873
  }
740
- if (sim.repulsionTheta !== void 0) {
741
- partial.simulationRepulsionTheta = sim.repulsionTheta;
874
+ if (sim.repulsionTheta !== void 0 && !this.repulsionThetaWarned) {
875
+ this.repulsionThetaWarned = true;
876
+ this.events?.onDiagnostic?.({
877
+ code: "engine:repulsion-theta-deprecated",
878
+ severity: "info",
879
+ message: "CosmosEngine: cosmos >= 3.4 uses grid-based repulsion; simulation.repulsionTheta is ignored by this engine."
880
+ });
742
881
  }
743
882
  if (sim.center !== void 0) partial.simulationCenter = sim.center;
744
883
  if (sim.repulsionFromMouse !== void 0) {
@@ -766,6 +905,8 @@ var CosmosEngine = class {
766
905
  graph.render();
767
906
  this.applied = update.revision;
768
907
  if (restart) graph.start(restart.alpha);
908
+ if (restart) this.wake("sim");
909
+ this.requestTicks(2);
769
910
  }
770
911
  /**
771
912
  * Applies the §16.3 stage-4 cluster force (capability `clusterForce`).
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 * Overlay/activity clock (M0 evidence, docs/m0-conformance.md): cosmos exposes\n * no draw/render-phase hook (`postDrawFrames: false`), so the adapter owns a\n * single requestAnimationFrame loop that reports `onFrame(timeMs)` to the host\n * — an ACTIVITY clock, not a post-draw hook: overlays may lag the canvas by\n * one sample. That degradation is reported once at mount via the\n * `engine:overlay-activity-clock` info diagnostic. The loop is started at\n * mount, stopped on context loss/destroy, resumed on recovery, and skips the\n * callback while `document.hidden` (stop-at-rest quiescence is S13 scope).\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 };\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 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\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 requestAnimationFrame activity clock and ' +\n 'may lag the canvas by one frame.',\n });\n this.startFrameLoop();\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\n fitView(opts?: FitViewOptions): void {\n this.activeGraph?.fitView(opts?.durationMs, opts?.padding);\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 }\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 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 }\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 }\n\n // --- simulation ---\n\n start(alpha?: number): void {\n this.activeGraph?.start(alpha);\n }\n\n pause(): void {\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 }\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 }\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 }\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 canvas = this.activeGraph ? this.canvas : null;\n const win = canvas?.ownerDocument.defaultView ?? null;\n if (!canvas || !win || typeof win.requestAnimationFrame !== 'function') {\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 // --- overlay/activity clock (see module header) ---\n\n /**\n * One rAF tick of the activity clock. Reschedules FIRST so a throwing host\n * callback can never kill the clock; skips the callback (but keeps ticking)\n * while the document is hidden. Deliberately cheap: a single callback\n * invocation — the core skips all work when nothing subscribes.\n */\n private readonly frameTick = (timeMs: number): void => {\n const win = this.frameWindow;\n if (!win || this.frameHandle === null) return;\n this.frameHandle = win.requestAnimationFrame(this.frameTick);\n if (!win.document.hidden) this.events?.onFrame?.(timeMs);\n };\n\n private startFrameLoop(): 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 }\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 this.startFrameLoop(); // resume the activity clock (no re-diagnostic)\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 // 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.events?.onPointHover?.(index);\n },\n onPointMouseOut: () => {\n this.lastHoverIndex = null;\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.events?.onLinkHover?.(linkIndex);\n },\n onLinkMouseOut: () => {\n this.events?.onLinkHover?.(null);\n },\n onDragStart: () => {\n this.handleDragStart();\n },\n onDragEnd: (e) => {\n this.handleDragEnd(e);\n },\n onZoom: () => {\n this.emitViewportChange();\n },\n onZoomEnd: () => {\n this.emitViewportChange();\n },\n onSimulationEnd: () => {\n this.events?.onSimulationEnd?.();\n },\n };\n if (this.options.spaceSize !== undefined) base.spaceSize = this.options.spaceSize;\n // Escape hatch: shallow-merged last so callers can override anything above.\n return { ...base, ...(this.options.initialConfig as GraphConfig | undefined) };\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 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 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 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 if (sim.repulsionTheta !== undefined) {\n partial.simulationRepulsionTheta = sim.repulsionTheta;\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 }\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 (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 /** Live native link hover (review P1: 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 (§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 // Same review-P1 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 // Review P1: 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 (§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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modernrelay/orbit-engine-cosmos",
3
- "version": "0.2.0",
3
+ "version": "0.13.6",
4
4
  "description": "cosmos.gl engine adapter for Orbit: GPU force layout, native picking, context-loss recovery.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -23,8 +23,8 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@cosmos.gl/graph": "3.3.0",
27
- "@modernrelay/orbit-core": "0.2.0"
26
+ "@cosmos.gl/graph": "3.4.0",
27
+ "@modernrelay/orbit-core": "0.13.6"
28
28
  },
29
29
  "devDependencies": {
30
30
  "typescript": "^5.6.0",