@graphty/graphty-element 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +3 -3
  2. package/dist/ai.js +4 -4
  3. package/dist/catalog.js +5 -5
  4. package/dist/chunks/{AiManager-D22fxCNb.js → AiManager-DWwQiBQu.js} +5 -5
  5. package/dist/chunks/{Algorithm-BhwPK-aS.js → Algorithm-RQ629NLb.js} +210 -92
  6. package/dist/chunks/{DataSource-7S-7S3M1.js → DataSource-DEg3igzS.js} +3 -3
  7. package/dist/chunks/{GraphSession-DwlThkoy.js → GraphSession-CtqyVNsw.js} +2518 -2239
  8. package/dist/chunks/{GraphtyError-B3eKs4yg.js → GraphtyError-BwcnblTH.js} +10 -8
  9. package/dist/chunks/GraphtyLogger-5KEttFUo.js +752 -0
  10. package/dist/chunks/{NodeStyle-CS7dj20m.js → NodeStyle-Cup9O1lu.js} +2 -1
  11. package/dist/chunks/{VoiceInputAdapter-BrCQEMf0.js → VoiceInputAdapter-mD0x3z7t.js} +1 -1
  12. package/dist/chunks/{XRPivotCameraController-BE1pfwMC.js → XRPivotCameraController-Clil9NhV.js} +2 -2
  13. package/dist/chunks/{cameras-D5LX3ttm.js → cameras-DFXNYBze.js} +2 -2
  14. package/dist/chunks/{capability-check-MH9salUj.js → capability-check-dXwQ_z5B.js} +1 -1
  15. package/dist/chunks/{detect-5cVtGFHg.js → detect-CqN0mC6u.js} +3 -3
  16. package/dist/chunks/{format-detection-Bos-Q387.js → format-detection-C8vbCSlS.js} +1 -1
  17. package/dist/chunks/{index-CqZp3iwq.js → index-2VIpMJZP.js} +1576 -1211
  18. package/dist/chunks/{paletteRegistry-BSjlD98O.js → paletteRegistry-NrWOKT-A.js} +17 -17
  19. package/dist/chunks/{registry-DU-e49Y2.js → registry-CSba5QGJ.js} +1 -1
  20. package/dist/chunks/{scales-DPUY-fFk.js → scales-BUS7NWy2.js} +2206 -1357
  21. package/dist/custom-elements.json +1 -1
  22. package/dist/extend.js +26 -27
  23. package/dist/graphty-catalog.json +7 -4
  24. package/dist/graphty.bundle.js +36288 -34368
  25. package/dist/graphty.js +66 -64
  26. package/dist/index.d.ts +1 -1
  27. package/dist/logging.js +2 -2
  28. package/dist/schema.js +1 -1
  29. package/dist/session.d.ts +2 -1
  30. package/dist/session.js +37 -33
  31. package/dist/src/Edge.d.ts +1 -1
  32. package/dist/src/Graph.d.ts +41 -7
  33. package/dist/src/Node.d.ts +1 -1
  34. package/dist/src/acceleration/AccelerationController.d.ts +27 -0
  35. package/dist/src/acceleration/index.d.ts +1 -1
  36. package/dist/src/acceleration/narrow.d.ts +56 -0
  37. package/dist/src/acceleration/types.d.ts +88 -7
  38. package/dist/src/algorithms/Algorithm.d.ts +96 -2
  39. package/dist/src/algorithms/BFSAlgorithm.d.ts +9 -0
  40. package/dist/src/algorithms/DijkstraAlgorithm.d.ts +2 -8
  41. package/dist/src/algorithms/PageRankAlgorithm.d.ts +8 -0
  42. package/dist/src/algorithms/utils/graphUtils.d.ts +13 -0
  43. package/dist/src/cameras/OrbitCameraController.d.ts +1 -0
  44. package/dist/src/catalog/layouts.d.ts +13 -1
  45. package/dist/src/config/GraphBehavior.d.ts +13 -0
  46. package/dist/src/config/GraphStyle.d.ts +1 -1
  47. package/dist/src/config/StyleTemplate.d.ts +4 -0
  48. package/dist/src/data/CSVDataSource.d.ts +1 -0
  49. package/dist/src/data/csv-variant-detection.d.ts +11 -0
  50. package/dist/src/errors/codes.d.ts +14 -1
  51. package/dist/src/events.d.ts +17 -4
  52. package/dist/src/graphty-element.d.ts +48 -3
  53. package/dist/src/layout/ForceAtlas2LayoutEngine.d.ts +28 -45
  54. package/dist/src/layout/LayoutEngine.d.ts +7 -7
  55. package/dist/src/layout/SimulationLayoutEngine.d.ts +458 -0
  56. package/dist/src/layout/SpringElectricalLayoutEngine.d.ts +32 -0
  57. package/dist/src/layout/SpringLayoutEngine.d.ts +22 -32
  58. package/dist/src/managers/EventManager.d.ts +7 -0
  59. package/dist/src/managers/GraphContext.d.ts +6 -0
  60. package/dist/src/managers/LayoutManager.d.ts +98 -4
  61. package/dist/src/managers/RenderManager.d.ts +7 -0
  62. package/dist/src/managers/UpdateManager.d.ts +1 -1
  63. package/dist/src/session/catalog.d.ts +2 -2
  64. package/dist/src/session/query.d.ts +83 -0
  65. package/dist/src/session/runs/types.d.ts +10 -4
  66. package/dist/src/session/selection/targets.d.ts +20 -3
  67. package/dist/src/session/styles/StylesApi.d.ts +18 -0
  68. package/dist/src/session/styles/legend.d.ts +9 -0
  69. package/dist/src/session/styles/predicate.d.ts +11 -0
  70. package/dist/src/session/styles/sources.d.ts +16 -0
  71. package/dist/src/session/types.d.ts +38 -2
  72. package/dist/src/testing/fakeAccelerator.d.ts +323 -0
  73. package/dist/webgpu.d.ts +23 -1
  74. package/dist/webgpu.js +70 -32
  75. package/package.json +15 -11
  76. package/dist/chunks/GraphtyLogger-DoYeIghs.js +0 -609
  77. package/dist/chunks/types-Dwm9waL2.js +0 -7
@@ -50,6 +50,20 @@ export type AccelerationState = "probing" | "active" | "idle" | "unavailable" |
50
50
  * next visit, is the host application's storage and the host application's job.
51
51
  */
52
52
  export type AccelerationPolicy = "auto" | "off" | "required";
53
+ /** The three values, in the order a control offers them. */
54
+ export declare const ACCELERATION_POLICIES: readonly AccelerationPolicy[];
55
+ /** What the element does when nothing was asked: `auto`. */
56
+ export declare const ACCELERATION_POLICY_DEFAULT: AccelerationPolicy;
57
+ /**
58
+ * Whether a value is one of the three acceleration policies.
59
+ *
60
+ * A host that offers the choice gets the value back from storage, a query string or a change
61
+ * handler, where it is an unknown string. This is the check the element itself runs on the
62
+ * `acceleration` attribute, so a host cannot accept a value the element would refuse.
63
+ * @param value - Anything at all.
64
+ * @returns True when `value` is `"auto"`, `"off"` or `"required"`.
65
+ */
66
+ export declare function isAccelerationPolicy(value: unknown): value is AccelerationPolicy;
53
67
  /**
54
68
  * The arithmetic that produced a set of numbers.
55
69
  *
@@ -74,13 +88,21 @@ export declare const DEFAULT_ACCELERATOR_PRECISION: AccelerationPrecision;
74
88
  *
75
89
  * Three plain strings, so a status chip can render "NVIDIA, ampere" without importing a GPU
76
90
  * type or parsing a renderer string.
91
+ *
92
+ * This side is ALWAYS PRESENT, MAY BE EMPTY: an accelerator fills in what its driver told it and
93
+ * `""` for what it did not, so an implementer never has to choose between `""` and `undefined`.
94
+ * {@link AccelerationStatus}, what a consumer reads, is the opposite -- a field is there only
95
+ * when the backend reported one -- and `AccelerationController` is the single place that
96
+ * converts between the two, dropping every empty string on the way out. Keep it that way: a
97
+ * browser masks the device and the description for an ordinary origin, so empty is the common
98
+ * case and a consumer must never be handed `""` to render.
77
99
  */
78
100
  export interface AcceleratorDeviceInfo {
79
- /** The hardware vendor, as the driver reports it: `"nvidia"`, `"apple"`, `"intel"`. */
101
+ /** The hardware vendor, as the driver reports it: `"nvidia"`, `"apple"`, `""` when unknown. */
80
102
  readonly vendor: string;
81
103
  /** The device family, as the driver reports it: `"ampere"`, `"rdna-3"`, `""` when unknown. */
82
104
  readonly architecture: string;
83
- /** A human-readable description of the device. May be empty; never undefined. */
105
+ /** A human-readable description of the device, `""` when unknown. Never undefined. */
84
106
  readonly description: string;
85
107
  }
86
108
  /**
@@ -115,9 +137,42 @@ export interface GraphAccelerator {
115
137
  }>;
116
138
  /** The arithmetic this accelerator computes in. Absent means {@link DEFAULT_ACCELERATOR_PRECISION}. */
117
139
  readonly precision?: AccelerationPrecision;
140
+ /**
141
+ * Proves this accelerator computes correctly, before any of the element's work is planned
142
+ * onto it.
143
+ *
144
+ * Hardware that answers is not the same thing as hardware that answers correctly. The
145
+ * software renderer that ships with Windows miscomputes shaders that pass a value across a
146
+ * workgroup barrier: it builds, it runs, it returns plausible numbers, and every prefix sum,
147
+ * sort and grid layout over one of them is wrong. Nothing errors. A backend that can tell
148
+ * the difference implements this; one that cannot omits it, and the element attaches it on
149
+ * the strength of the probe as before.
150
+ *
151
+ * Resolve when the hardware is trustworthy. Reject with a `GraphtyError` carrying
152
+ * `E_DEVICE_INCORRECT` when it is not, and the element reports acceleration unavailable with
153
+ * that code and runs the CPU path -- the same place a missing adapter reaches, because a
154
+ * device that lies is no more usable than a device that is not there.
155
+ *
156
+ * The element calls it once, on an accelerator it built from a registered factory, before
157
+ * attaching it. An accelerator handed over already built through `setAccelerator` is not
158
+ * asked -- the element did not construct it and does not own its lifetime, and whoever did
159
+ * both vouched for it by handing it over.
160
+ *
161
+ * It is NOT a way to report a failure part-way through a run: work that has already started
162
+ * on the accelerator and then fails is that work's failure and throws.
163
+ * @returns Resolves when the accelerator is fit to be given work.
164
+ */
165
+ verify?(): Promise<void>;
118
166
  /** Releases the hardware resources. Called by the element when it detaches this accelerator. */
119
167
  dispose?(): void;
120
- /** An accelerated algorithm or layout, looked up by name and feature-tested before use. */
168
+ /**
169
+ * An accelerated algorithm or layout, looked up by name and feature-tested before use.
170
+ *
171
+ * `release(snapshot)` is one of these rather than a declared member: an accelerator that keeps
172
+ * device buffers for a snapshot implements it, and the element calls it when that snapshot
173
+ * stops being the graph, while an accelerator with no residency to free simply has no such
174
+ * member. Both are feature-tested the same way, so neither has to pretend to be the other.
175
+ */
121
176
  [algorithmOrLayout: string]: unknown;
122
177
  }
123
178
  /** What the element tells a factory before the factory builds anything. */
@@ -131,6 +186,14 @@ export interface AcceleratorFactoryOptions {
131
186
  * that does not care ignores the parameter.
132
187
  */
133
188
  readonly exactMaxNodes?: number;
189
+ /**
190
+ * Whether a software adapter (SwiftShader, llvmpipe) is acceptable.
191
+ *
192
+ * Under `"auto"` it is not: a software rasteriser is slower than the element's own CPU
193
+ * path, and attaching it would make the graph slower while reporting "active". Under
194
+ * `"required"` it is: the consumer said "no CPU path", and a software device is a device.
195
+ */
196
+ readonly acceptSoftware?: boolean;
134
197
  }
135
198
  /**
136
199
  * Builds an accelerator, or declines.
@@ -161,11 +224,18 @@ export interface AccelerationStatus {
161
224
  readonly state: AccelerationState;
162
225
  /** The attached accelerator's backend, when one is attached. */
163
226
  readonly backend?: "webgpu" | (string & {});
164
- /** The hardware vendor, when the backend reported one. */
227
+ /**
228
+ * The hardware vendor, when the backend reported one. Absent otherwise, never `""`.
229
+ *
230
+ * The three device facts arrive from an accelerator as {@link AcceleratorDeviceInfo}, where
231
+ * they are always present and an unknown one is `""`. They are published here the other way
232
+ * round, so a consumer can test one with `??` or `!== undefined` and never render an empty
233
+ * string. `AccelerationController` is what converts.
234
+ */
165
235
  readonly vendor?: string;
166
- /** The device family, when the backend reported one. */
236
+ /** The device family, when the backend reported one. Absent otherwise, never `""`. */
167
237
  readonly architecture?: string;
168
- /** The device description, when the backend reported one. */
238
+ /** The device description, when the backend reported one. Absent otherwise, never `""`. */
169
239
  readonly device?: string;
170
240
  /** Why acceleration is unavailable or has stopped, in a sentence a person can read. */
171
241
  readonly reason?: string;
@@ -278,6 +348,17 @@ export declare const ACCELERATION_MIN_NODES_KEY = "acceleration.minNodes";
278
348
  *
279
349
  * Raise it when a graph is small enough that uploading it costs more than computing it. There
280
350
  * is no defensible non-zero default, because the crossover has to be measured on the machine
281
- * the graph is drawn on.
351
+ * the graph is drawn on -- and this zero is a measurement, not a guess. On the dev box
352
+ * (RTX 4070 SUPER, headless Chromium, 2026-09-22) the accelerated layout's frame time was at or
353
+ * below the CPU simulation's at every size measured, starting with the smallest: 50.0 against
354
+ * 50.0 ms at 500 nodes, 116.7 against 116.7 at 1,000 and 183.3 against 216.6 at 2,000, three runs
355
+ * of sixty working frames per arm, all at average degree 10. A fourth size, 5,000 nodes, read
356
+ * 466.6 against 566.7 -- but from ONE run of five frames, so read it as indicative and not as what
357
+ * the default rests on. The crossover is therefore below the smallest graph worth accelerating,
358
+ * and the default stays 0.
359
+ *
360
+ * `scripts/measure-min-nodes.mjs` is the measurement, protocol in its header; the table and what
361
+ * it does not cover are in section 3 of `graphty-element/docs/decisions/G6.md` IN THE REPOSITORY,
362
+ * which is not part of the published documentation site.
282
363
  */
283
364
  export declare const ACCELERATION_MIN_NODES_DEFAULT = 0;
@@ -1,5 +1,7 @@
1
- import type { Graph as AlgorithmGraph } from "@graphty/algorithms";
2
- import type { AlgorithmDescriptor, FieldDescriptor } from "../catalog/types";
1
+ import { type AcceleratedAlgorithms, type Graph as AlgorithmGraph } from "@graphty/algorithms";
2
+ import { type GraphSnapshot, type U32 } from "@graphty/graph-format";
3
+ import { type AccelerationPrecision } from "../acceleration/types";
4
+ import type { AlgorithmDescriptor, FieldDescriptor, NodeId } from "../catalog/types";
3
5
  import { type OptionsSchema as ZodOptionsSchema } from "../config";
4
6
  import { Graph } from "../Graph";
5
7
  import type { RunResult } from "../session/results";
@@ -70,6 +72,57 @@ export interface AlgorithmStatics {
70
72
  /** Check if this algorithm has a Zod-based options schema */
71
73
  hasZodOptions(): boolean;
72
74
  }
75
+ /**
76
+ * One piece of accelerable work, with the decision "accelerator or CPU" already taken.
77
+ *
78
+ * An adapter reads the snapshot it is over, runs the work through {@link run}, and writes ONE
79
+ * loop over an index-aligned result whichever path produced it. The precision that comes back is
80
+ * what the run publishes as `caveats.precision`: a result computed on an accelerator says `f32`
81
+ * and one computed on the CPU port says `f64`, and a reader comparing two numbers has the
82
+ * qualification that explains the difference.
83
+ *
84
+ * Exported only because it is the return type of a protected member, which declaration emit
85
+ * requires to be nameable. An adapter receives one from `Algorithm.accelerated`; nothing outside
86
+ * this module constructs one or needs to name it.
87
+ * @internal
88
+ */
89
+ export interface AcceleratedAlgorithmRun {
90
+ /**
91
+ * The snapshot the work runs over: the declared one for `"directed"`, the undirected view for
92
+ * `"undirected"`, in either case with every group of parallel edges collapsed to one edge
93
+ * carrying the group's summed weight. Its `ids` map is how a node id becomes the index every
94
+ * result is keyed by, and the node space is the declared one either way.
95
+ */
96
+ readonly snapshot: GraphSnapshot;
97
+ /**
98
+ * Declared edge index -> edge index in {@link snapshot}, or null when the edge space is the
99
+ * declared one.
100
+ *
101
+ * This is the direction an edge-carrying result is read in: an adapter walks the element's own
102
+ * edges, maps each one's `Edge.index` through this, and asks whether that index is in the
103
+ * result. Read the other way (`edgeOrigin`) a merged group names only its survivor, so every
104
+ * edge the reader declared but one would silently go unflagged -- both halves of a reciprocal
105
+ * pair the undirected view collapsed, and every member of a group of parallel edges.
106
+ */
107
+ readonly edgeRemap: U32 | null;
108
+ /**
109
+ * Runs the work, on the accelerator when the controller said so and on the CPU port when it
110
+ * did not.
111
+ *
112
+ * A property rather than a method, so an adapter may take it out of the object it came in --
113
+ * `const { run } = this.accelerated(...)` -- which is how every one of them reads.
114
+ * @param fn - The work, written once against the dispatcher.
115
+ * @returns What the work produced, and the arithmetic it was produced in.
116
+ * @throws Whatever the accelerator threw, with its code. A failure after the work started is
117
+ * the run's failure: nothing is recomputed on the CPU.
118
+ */
119
+ readonly run: <T>(fn: (dispatch: AcceleratedAlgorithms, snapshot: GraphSnapshot) => Promise<T>) => Promise<{
120
+ /** What `fn` returned. */
121
+ readonly value: T;
122
+ /** The arithmetic it was computed in. */
123
+ readonly precision: AccelerationPrecision;
124
+ }>;
125
+ }
73
126
  /**
74
127
  * Base class for all graph algorithms
75
128
  * @template TOptions - The options type for this algorithm (defaults to empty object)
@@ -151,6 +204,47 @@ export declare abstract class Algorithm<TOptions extends Record<string, unknown>
151
204
  * @returns a freshly built Graph for the algorithm package
152
205
  */
153
206
  protected algorithmGraph(mode: AlgorithmGraphMode): AlgorithmGraph;
207
+ /**
208
+ * The route an algorithm with an accelerated implementation takes.
209
+ *
210
+ * It is the counterpart of {@link algorithmGraph} for the algorithms `@graphty/algorithms`
211
+ * can dispatch: instead of copying the snapshot into an object graph, the work runs over the
212
+ * snapshot itself, on the attached accelerator or on the index-based CPU port, and the adapter
213
+ * writes one loop over an index-aligned result either way.
214
+ *
215
+ * THE DECISION IS TAKEN ONCE, HERE, BEFORE ANY WORK STARTS. The controller answers "the policy
216
+ * is off", "no accelerator", "below `acceleration.minNodes`" or "this accelerator does not
217
+ * implement that" up front, and under `acceleration="required"` it throws `E_NO_ACCELERATOR`
218
+ * rather than answering quietly. After the work has started there is no second decision: a
219
+ * failure from the accelerator propagates with its code and fails the run, because a number
220
+ * that silently came from somewhere else is worse than no number.
221
+ * @param capability - The accelerator member this work would use, such as `"pageRank"`.
222
+ * @param mode - The shape this algorithm needs; see {@link AlgorithmGraphMode}. `"undirected"`
223
+ * takes the snapshot's undirected view, which is what collapses a reciprocal pair into one
224
+ * edge.
225
+ * @returns The snapshot, the edge map onto it, and the runner.
226
+ * @example
227
+ * ```ts
228
+ * const { snapshot, run } = this.accelerated("connectedComponents", "undirected");
229
+ * const { value, precision } = await run((dispatch, s) => dispatch.connectedComponents(s));
230
+ * const group = value.labels[snapshot.ids.indexOf(nodeId)];
231
+ * ```
232
+ */
233
+ protected accelerated(capability: string, mode: AlgorithmGraphMode): AcceleratedAlgorithmRun;
234
+ /**
235
+ * The dense row of a node the reader named in an option.
236
+ *
237
+ * A search takes its source as an id and the snapshot answers in indices, so this is where the
238
+ * two meet -- and where an id that names no node in the graph is reported as what it is: an
239
+ * option whose value is outside the permitted range, carrying the option's name and what was
240
+ * passed, rather than a silent empty result or a search from row zero.
241
+ * @param snapshot - The graph the work runs over.
242
+ * @param option - The option the id came from, named in the error.
243
+ * @param id - The node id the reader gave.
244
+ * @returns The node's dense row.
245
+ * @throws A `GraphtyError` with `E_OPTION_RANGE` when the graph has no such node.
246
+ */
247
+ protected nodeIndex(snapshot: GraphSnapshot, option: string, id: NodeId): number;
154
248
  /**
155
249
  * Resolves and validates options against the schema
156
250
  * @param options - User-provided options (partial)
@@ -50,5 +50,14 @@ export declare class BFSAlgorithm extends DeclaredAlgorithm<BFSOptions> {
50
50
  * @returns The layered result, or null when there is nothing to walk.
51
51
  */
52
52
  compute(context: AlgorithmRunContext): Promise<AlgorithmOutput | null>;
53
+ /**
54
+ * Walk with an early stop at a target, on the CPU reference implementation.
55
+ * @param context - What the element gave the run.
56
+ * @param nodeIds - The nodes to publish for.
57
+ * @param source - Where the walk starts.
58
+ * @param targetNode - Where it stops.
59
+ * @returns The layered result, or null when the source is not in the graph.
60
+ */
61
+ private legacyWalk;
53
62
  }
54
63
  export {};
@@ -9,14 +9,14 @@ interface DijkstraOptions extends Record<string, unknown> {
9
9
  source: number | string | null;
10
10
  /** Destination node for shortest path (defaults to last node if not provided) */
11
11
  target: number | string | null;
12
- /** Use bidirectional search optimization for point-to-point queries */
12
+ /** Accepted and ignored; see the option's description. */
13
13
  bidirectional: boolean;
14
14
  }
15
15
  /**
16
16
  * Dijkstra's algorithm for finding shortest paths
17
17
  *
18
18
  * Computes shortest paths from a source node to all other nodes using
19
- * non-negative edge weights. Supports bidirectional search optimization.
19
+ * non-negative edge weights.
20
20
  */
21
21
  export declare class DijkstraAlgorithm extends DeclaredAlgorithm<DijkstraOptions> {
22
22
  static namespace: string;
@@ -53,11 +53,5 @@ export declare class DijkstraAlgorithm extends DeclaredAlgorithm<DijkstraOptions
53
53
  * @returns The route, or null when there are no nodes to search.
54
54
  */
55
55
  compute(context: AlgorithmRunContext): Promise<AlgorithmOutput | null>;
56
- /**
57
- * Get set of edge keys that are part of the path
58
- * @param path - Array of node IDs representing the path
59
- * @returns Set of edge keys in "srcId:dstId" format
60
- */
61
- private getPathEdges;
62
56
  }
63
57
  export {};
@@ -138,6 +138,14 @@ export declare class PageRankAlgorithm extends MetricAlgorithm<PageRankOptions>
138
138
  * Resolved options using the NEW Zod-based validation
139
139
  */
140
140
  private zodOptions;
141
+ /**
142
+ * The two Map-valued options, kept from what the caller passed.
143
+ *
144
+ * NEITHER SCHEMA CARRIES THEM -- a Map is not a value a form or a saved document can hold --
145
+ * and `resolveOptions` returns only the keys its schema declares, so reading them back off the
146
+ * resolved options found nothing and a personalized run quietly ran an unpersonalized one.
147
+ */
148
+ private readonly programmaticOptions;
141
149
  /**
142
150
  * Creates a new PageRank algorithm instance
143
151
  * @param g - The graph to run the algorithm on
@@ -15,6 +15,19 @@
15
15
  * @returns the lookup key
16
16
  */
17
17
  export declare function edgePairKey(source: string | number, target: string | number): string;
18
+ /**
19
+ * Refuse a node id option that names no node in the graph.
20
+ *
21
+ * `@graphty/algorithms` answers a query about a missing node with an empty result rather than an
22
+ * error, so without this check an unknown id publishes zeros as if they were a measurement.
23
+ * @param algorithm - The algorithm's key, for the message.
24
+ * @param option - The option name the id came in on.
25
+ * @param value - The id the caller passed.
26
+ * @param nodeIds - Every node id in the graph.
27
+ * @returns The id as the string the algorithms package keys nodes by.
28
+ * @throws A `GraphtyError` coded `E_OPTION_RANGE` when no node has that id.
29
+ */
30
+ export declare function requireNodeOption(algorithm: string, option: string, value: string | number, nodeIds: readonly (string | number)[]): string;
18
31
  /**
19
32
  * Minimal edge data interface required by graph utilities
20
33
  */
@@ -15,6 +15,7 @@ export interface OrbitConfig {
15
15
  * Provides trackball-style rotation and keyboard/touch controls.
16
16
  */
17
17
  export declare class OrbitCameraController {
18
+ #private;
18
19
  scene: Scene;
19
20
  camera: UniversalCamera;
20
21
  cameraDistance: number;
@@ -2,7 +2,7 @@
2
2
  * @file The layout catalogue: the arrangements the element offers, and the engines behind them.
3
3
  *
4
4
  * A public layout name says what the arrangement IS -- "force", "hierarchical", "circular" --
5
- * and never which library draws it. The element registers sixteen engines whose registered
5
+ * and never which library draws it. The element registers seventeen engines whose registered
6
6
  * names ARE their implementations ("ngraph", "d3", "forceatlas2"), and freezing those into the
7
7
  * public API makes swapping an implementation a rename every consumer can see. So the engine is
8
8
  * data on the descriptor instead: `LayoutDescriptor.engine` names the implementation the element
@@ -46,6 +46,18 @@ export interface LayoutImplementation {
46
46
  * catalogue cannot claim a weight channel an engine does not have.
47
47
  */
48
48
  honoursWeights: boolean;
49
+ /**
50
+ * What has to be true before this engine can run at all, in the same shape an algorithm
51
+ * declares it.
52
+ *
53
+ * `accelerator: true` means the engine is computed on hardware and has no processor
54
+ * implementation, so a picker greys the entry out when `capabilities.acceleration.state` says
55
+ * nothing is attached. It belongs to the ENGINE rather than to the arrangement: `force` is
56
+ * drawn by six engines, five of which need nothing.
57
+ */
58
+ requires?: {
59
+ accelerator?: boolean;
60
+ };
49
61
  }
50
62
  /** One semantic layout, with every engine that can draw it. */
51
63
  export interface LayoutCatalogEntry {
@@ -1,6 +1,17 @@
1
1
  import { z } from "zod/v4";
2
2
  import type { Graph } from "../Graph";
3
3
  import type { Node as GraphNode } from "../Node";
4
+ declare const GraphLayoutOpts: z.ZodObject<{
5
+ type: z.ZodDefault<z.ZodString>;
6
+ preSteps: z.ZodDefault<z.ZodNumber>;
7
+ stepMultiplier: z.ZodDefault<z.ZodNumber>;
8
+ minDelta: z.ZodDefault<z.ZodNumber>;
9
+ zoomStepInterval: z.ZodDefault<z.ZodNumber>;
10
+ iterationsPerStep: z.ZodOptional<z.ZodNumber>;
11
+ maxInFlight: z.ZodDefault<z.ZodNumber>;
12
+ }, z.core.$strict>;
13
+ /** How the element drives a layout, as the behaviour configuration resolves it. */
14
+ export type GraphLayoutBehavior = z.infer<typeof GraphLayoutOpts>;
4
15
  /** How the element drives the layout, as a caller supplies it: every field optional. */
5
16
  export type GraphBehaviorConfig = z.input<typeof GraphBehaviorOpts>;
6
17
  export declare const GraphBehaviorOpts: z.ZodObject<{
@@ -10,6 +21,8 @@ export declare const GraphBehaviorOpts: z.ZodObject<{
10
21
  stepMultiplier: z.ZodDefault<z.ZodNumber>;
11
22
  minDelta: z.ZodDefault<z.ZodNumber>;
12
23
  zoomStepInterval: z.ZodDefault<z.ZodNumber>;
24
+ iterationsPerStep: z.ZodOptional<z.ZodNumber>;
25
+ maxInFlight: z.ZodDefault<z.ZodNumber>;
13
26
  }, z.core.$strict>>;
14
27
  node: z.ZodPrefault<z.ZodObject<{
15
28
  pinOnDrag: z.ZodDefault<z.ZodBoolean>;
@@ -42,7 +42,7 @@ declare const GraphSelectionStyle: z.ZodObject<{
42
42
  /** How solid the halo is, in `[0, 1]`. Low enough to read as a highlight rather than a node. */
43
43
  opacity: z.ZodDefault<z.ZodNumber>;
44
44
  }, z.core.$strict>;
45
- /** What a selected node looks like, as it parses. See {@link GraphSelectionStyle}. */
45
+ /** What a selected node looks like, as it parses. See {@link GraphSelectionStyleOpts}. */
46
46
  export type GraphSelectionStyleConfig = z.infer<typeof GraphSelectionStyle>;
47
47
  /** What a caller may say about the selection highlight: every field optional. */
48
48
  export type GraphSelectionStyleInput = z.input<typeof GraphSelectionStyle>;
@@ -922,6 +922,8 @@ declare const StyleTemplateV1: z.ZodObject<{
922
922
  stepMultiplier: z.ZodDefault<z.ZodNumber>;
923
923
  minDelta: z.ZodDefault<z.ZodNumber>;
924
924
  zoomStepInterval: z.ZodDefault<z.ZodNumber>;
925
+ iterationsPerStep: z.ZodOptional<z.ZodNumber>;
926
+ maxInFlight: z.ZodDefault<z.ZodNumber>;
925
927
  }, z.core.$strict>>;
926
928
  node: z.ZodPrefault<z.ZodObject<{
927
929
  pinOnDrag: z.ZodDefault<z.ZodBoolean>;
@@ -1853,6 +1855,8 @@ export declare const StyleTemplate: z.ZodDiscriminatedUnion<[z.ZodObject<{
1853
1855
  stepMultiplier: z.ZodDefault<z.ZodNumber>;
1854
1856
  minDelta: z.ZodDefault<z.ZodNumber>;
1855
1857
  zoomStepInterval: z.ZodDefault<z.ZodNumber>;
1858
+ iterationsPerStep: z.ZodOptional<z.ZodNumber>;
1859
+ maxInFlight: z.ZodDefault<z.ZodNumber>;
1856
1860
  }, z.core.$strict>>;
1857
1861
  node: z.ZodPrefault<z.ZodObject<{
1858
1862
  pinOnDrag: z.ZodDefault<z.ZodBoolean>;
@@ -1,6 +1,7 @@
1
1
  import { type CSVVariant } from "./csv-variant-detection.js";
2
2
  import { BaseDataSourceConfig, DataSource, DataSourceChunk } from "./DataSource.js";
3
3
  interface CSVDataSourceConfig extends BaseDataSourceConfig {
4
+ /** The column separator. Worked out from the first line (comma, tab, semicolon or pipe) when unset. */
4
5
  delimiter?: string;
5
6
  variant?: CSVVariant;
6
7
  /**
@@ -10,6 +10,17 @@ export interface CSVVariantInfo {
10
10
  typeColumn?: string;
11
11
  interactionColumn?: string;
12
12
  }
13
+ /**
14
+ * Work out a delimited file's column separator from its first line.
15
+ *
16
+ * Papaparse's own guess is not used because it guesses from the rows it previews, and the one-row
17
+ * preview that reads the header row sees too little to tell a tab from a comma: it answers "," and
18
+ * the header `source<TAB>target` comes back as one column.
19
+ * @param content - The file, or at least its first line.
20
+ * @returns Whichever of comma, tab, semicolon and pipe appears most often outside quotes on the
21
+ * first line, or a comma when none does.
22
+ */
23
+ export declare function sniffDelimiter(content: string): string;
13
24
  /**
14
25
  * Detect CSV variant from headers and sample data
15
26
  * @param headers - Array of column header names
@@ -243,6 +243,19 @@ export type GraphtyErrorCode =
243
243
  * silence.
244
244
  */
245
245
  | "E_SOFTWARE_ONLY"
246
+ /**
247
+ * An adapter was found, it answered, and its answers are wrong. Before any of the element's
248
+ * work goes to an accelerator, the accelerator is asked to compute something whose answer is
249
+ * already known; a device that gets that wrong is refused, and the CPU path runs. The
250
+ * software renderer that ships with Windows is the device this exists for: it miscomputes
251
+ * shaders that pass a value across a workgroup barrier, so every prefix sum, sort and grid
252
+ * layout above one comes back wrong -- with plausible numbers and no error anywhere.
253
+ *
254
+ * `details` carry what the accelerator reported about the disagreement. Reported through
255
+ * `capabilities.acceleration` rather than thrown during ordinary use. Nothing the caller
256
+ * changes helps; a driver update might.
257
+ */
258
+ | "E_DEVICE_INCORRECT"
246
259
  /**
247
260
  * The GPU device was lost mid-session -- a driver reset, a tab suspension, or the browser
248
261
  * reclaiming the device. `details.reason` carries what the runtime said. The element reports
@@ -292,7 +305,7 @@ export declare const GRAPHTY_ERROR_CODES: readonly GraphtyErrorCode[];
292
305
  * This is the type of `capabilities.acceleration.code`, where a code is reported rather than
293
306
  * thrown: absence of acceleration is a state the consumer renders, not a failure it catches.
294
307
  */
295
- export type AccelerationErrorCode = "E_NO_WEBGPU" | "E_NO_ADAPTER" | "E_SOFTWARE_ONLY" | "E_DEVICE_LOST" | "E_TOO_LARGE";
308
+ export type AccelerationErrorCode = "E_NO_WEBGPU" | "E_NO_ADAPTER" | "E_SOFTWARE_ONLY" | "E_DEVICE_INCORRECT" | "E_DEVICE_LOST" | "E_TOO_LARGE";
296
309
  /**
297
310
  * Every code that can appear on `capabilities.acceleration.code`.
298
311
  */
@@ -13,7 +13,7 @@ export type GraphEventType = GraphEvent["type"];
13
13
  export type NodeEventType = NodeEvent["type"];
14
14
  export type EdgeEventType = EdgeEvent["type"];
15
15
  type AiEventType = AiEvent["type"];
16
- export type GraphEvent = GraphSettledEvent | GraphErrorEvent | GraphDataLoadedEvent | GraphDataAddedEvent | GraphSnapshotReplacedEvent | GraphLayoutInitializedEvent | CameraStateChangedEvent | GraphGenericEvent | DataLoadingProgressEvent | DataLoadingErrorEvent | DataLoadingErrorSummaryEvent | DataLoadingCompleteEvent | ElementsRemovedEvent | SelectionChangedEvent;
16
+ export type GraphEvent = GraphSettledEvent | GraphErrorEvent | GraphDataLoadedEvent | GraphDataAddedEvent | GraphSnapshotReplacedEvent | GraphSnapshotDroppedEvent | GraphLayoutInitializedEvent | CameraStateChangedEvent | GraphGenericEvent | DataLoadingProgressEvent | DataLoadingErrorEvent | DataLoadingErrorSummaryEvent | DataLoadingCompleteEvent | ElementsRemovedEvent | SelectionChangedEvent;
17
17
  /**
18
18
  * The graph event types that stay INSIDE the element: emitted on the internal graph observable so
19
19
  * the element's own managers can react, and never re-dispatched to the DOM.
@@ -69,9 +69,11 @@ export interface GraphDataAddedEvent {
69
69
  * Emitted by DataManager after every freeze, once the element's position column is attached to the
70
70
  * new snapshot (graph-format design 14.4 rule 11).
71
71
  *
72
- * Listeners release per-snapshot resources: at E1 `Graph` releases the accelerator's GPU buffers for
73
- * `previous` and its derived views, and caches drop their entries. Nothing a WeakMap can do for
74
- * them -- GPU memory is not garbage collected.
72
+ * Listeners release per-snapshot resources: `Graph` releases the accelerator's buffers for
73
+ * `previous` and for its undirected copy when that is a distinct snapshot (the release list of the
74
+ * WebGPU design 9.4 item 2), and caches drop their entries. Nothing a WeakMap can do for them --
75
+ * GPU memory is not garbage collected. A dataset that is cleared rather than replaced has no
76
+ * `next` to freeze and is announced by {@link GraphSnapshotDroppedEvent} instead.
75
77
  */
76
78
  export interface GraphSnapshotReplacedEvent {
77
79
  type: "snapshot-replaced";
@@ -84,6 +86,17 @@ export interface GraphSnapshotReplacedEvent {
84
86
  /** freezeWithReport's report, relative to the PREVIOUS freeze of the same builder. */
85
87
  report: FreezeReport;
86
88
  }
89
+ /**
90
+ * Emitted by DataManager when the dataset is cleared: the store and every snapshot it froze are
91
+ * discarded without a replacement, so no `snapshot-replaced` ever carries that boundary.
92
+ *
93
+ * Listeners drop their per-snapshot resources exactly as they do on a replacement -- `Graph`
94
+ * releases the accelerator's buffers for the snapshot it was showing. Emitted while the outgoing
95
+ * store is still usable, so a listener can still ask it for a derived view of what it is freeing.
96
+ */
97
+ export interface GraphSnapshotDroppedEvent {
98
+ type: "snapshot-dropped";
99
+ }
87
100
  export interface GraphLayoutInitializedEvent {
88
101
  type: "layout-initialized";
89
102
  layoutType: string;
@@ -122,7 +122,7 @@ export declare class Graphty extends LitElement {
122
122
  * properties can be used in style selectors and accessed via `node.data`.
123
123
  * @since 1.0.0
124
124
  * @see {@link edgeData} for edge data
125
- * @see {@link https://graphty.app/storybook/element/?path=/story/graphty--default | Basic Examples}
125
+ * @see {@link https://graphty.app/storybook/graphty-element/?path=/story/graphty--graphty | Basic Examples}
126
126
  * @example HTML attribute (JSON string)
127
127
  * ```html
128
128
  * <graphty-element
@@ -388,7 +388,7 @@ export declare class Graphty extends LitElement {
388
388
  * - `fixed`: Pre-defined positions from node data
389
389
  * @since 1.0.0
390
390
  * @see {@link layoutConfig} for layout-specific options
391
- * @see {@link https://graphty.app/storybook/element/?path=/story/layout--default | Layout Examples}
391
+ * @see {@link https://graphty.app/storybook/graphty-element/?path=/story/layout-3d--circular | Layout Examples}
392
392
  * @example
393
393
  * ```typescript
394
394
  * // Set force-directed layout
@@ -509,7 +509,7 @@ export declare class Graphty extends LitElement {
509
509
  *
510
510
  * VR and AR modes require WebXR support in the browser.
511
511
  * @since 1.0.0
512
- * @see {@link https://graphty.app/storybook/element/?path=/story/viewmode--default | View Mode Examples}
512
+ * @see {@link https://graphty.app/storybook/graphty-element/?path=/story/viewmode--switch-view-modes | View Mode Examples}
513
513
  * @example
514
514
  * ```typescript
515
515
  * element.viewMode = "2d"; // Switch to 2D orthographic view
@@ -1526,6 +1526,27 @@ export declare class Graphty extends LitElement {
1526
1526
  * ```
1527
1527
  */
1528
1528
  isRunning(): boolean;
1529
+ /**
1530
+ * Play or pause the layout.
1531
+ *
1532
+ * `setRunning(true)` on a layout that has already settled restarts it, so "play" is
1533
+ * something the reader can see; `setRunning(false)` stops the per-frame stepping and nothing
1534
+ * else -- work already handed to an accelerator lands, the scene keeps rendering, and the
1535
+ * camera, picking and styling stay live. There is no event for this: `isRunning()` reports
1536
+ * the state and `graph-settled` reports the arrangement coming to rest.
1537
+ *
1538
+ * A pause is not a mode the element remembers: anything that (re)starts a layout -- loading
1539
+ * more nodes, an accelerator attaching, setting another layout, dropping a dragged node --
1540
+ * runs it again, so pause it after those, not before.
1541
+ * @param running - True to run the layout, false to pause it.
1542
+ * @since 2.0.0
1543
+ * @example
1544
+ * ```typescript
1545
+ * element.setRunning(false); // pause
1546
+ * element.setRunning(true); // play again, from where it stopped
1547
+ * ```
1548
+ */
1549
+ setRunning(running: boolean): void;
1529
1550
  /**
1530
1551
  * Convert world coordinates to screen coordinates.
1531
1552
  * @param worldPos - Position in world space
@@ -1870,6 +1891,30 @@ export declare class Graphty extends LitElement {
1870
1891
  * healthy.
1871
1892
  */
1872
1893
  set acceleration(value: AccelerationPolicy);
1894
+ /**
1895
+ * The node count at or above which accelerated work uses the accelerator.
1896
+ *
1897
+ * Below it the element takes the CPU path even with an accelerator attached, and
1898
+ * `capabilities.acceleration.state` reads `"idle"`. Default 0: use the accelerator whenever
1899
+ * there is one. Raise it when the graphs you show are small enough that uploading costs more
1900
+ * than computing; the number is machine-specific, which is why the element does not guess.
1901
+ * @since 2.0.0
1902
+ * @example
1903
+ * ```html
1904
+ * <graphty-element acceleration-min-nodes="5000"></graphty-element>
1905
+ * ```
1906
+ * @returns The threshold in force.
1907
+ */
1908
+ get accelerationMinNodes(): number;
1909
+ /**
1910
+ * Sets the threshold and applies it immediately.
1911
+ *
1912
+ * A value that is not a whole number of 0 or more is reported and then ignored, leaving the
1913
+ * previous threshold in force, for the reason the `acceleration` setter states: Lit drives
1914
+ * this from `attributeChangedCallback`, and a throw there would leave the element unrendered.
1915
+ * @param value - The node count at or above which accelerated work uses the accelerator.
1916
+ */
1917
+ set accelerationMinNodes(value: number);
1873
1918
  }
1874
1919
  export type GraphtyElement = Graphty;
1875
1920
  declare global {