@ai-gui/plugin-bigscreen 0.36.3 → 0.37.1

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/dist/index.d.ts CHANGED
@@ -79,7 +79,92 @@ interface GlobePanel extends PanelBase {
79
79
  }>;
80
80
  rotate?: boolean;
81
81
  }
82
- type Panel = KpiPanel | GaugePanel | RankPanel | ChartPanel | Chart3dPanel | GlobePanel;
82
+ /** One swim-lane of a timeline: a source, an outlet, a system — whatever the rows stand for. */
83
+ interface TimelineLane {
84
+ id: string;
85
+ /** The name written down the left. At most 40 characters. */
86
+ name: string;
87
+ /** The lane's colour, as a hex string. Default: from the palette, by lane order. */
88
+ color?: string;
89
+ }
90
+ /** One point on a timeline. `id` is only needed for a lane an item is linked from or to. */
91
+ interface TimelineItem {
92
+ id?: string;
93
+ /** The `id` of the lane the point sits on. */
94
+ lane: string;
95
+ /** When it happened, as ISO 8601. */
96
+ at: string;
97
+ /** The one line beside the point. At most 120 characters. */
98
+ label: string;
99
+ /** What the tooltip adds. At most 400 characters. */
100
+ detail?: string;
101
+ /** Opened on click, unless the host took the click. `http` or `https` only. */
102
+ url?: string;
103
+ /** How big the point is drawn, relative to the other points. */
104
+ value?: number;
105
+ }
106
+ /**
107
+ * A line drawn between two points.
108
+ *
109
+ * `contradicts` is the one this panel exists for: two claims that cannot both be true, drawn in
110
+ * the palette's danger red across the lanes that made them.
111
+ */
112
+ interface TimelineLink {
113
+ from: string;
114
+ to: string;
115
+ /** Default `follows`. */
116
+ kind?: "contradicts" | "follows" | "same";
117
+ }
118
+ /** Lanes down the side, time across, one point per thing that happened, links between them. */
119
+ interface TimelinePanel extends PanelBase {
120
+ kind: "timeline";
121
+ lanes: TimelineLane[];
122
+ items: TimelineItem[];
123
+ links?: TimelineLink[];
124
+ /** The window drawn, as ISO 8601. Default: the items' own range with 5% on each side. */
125
+ from?: string;
126
+ to?: string;
127
+ }
128
+ /** One entity in a knowledge graph. */
129
+ interface Graph3dNode {
130
+ id: string;
131
+ /** At most 80 characters. */
132
+ name: string;
133
+ /** What kind of thing it is; the colour follows from this. At most 32 characters. */
134
+ type?: string;
135
+ /** How big it is drawn. Default: its degree. */
136
+ value?: number;
137
+ }
138
+ /** One typed edge. Both ends must be node ids. */
139
+ interface Graph3dEdge {
140
+ from: string;
141
+ to: string;
142
+ /** At most 32 characters. */
143
+ type?: string;
144
+ }
145
+ /**
146
+ * Entities and typed edges as a knowledge graph.
147
+ *
148
+ * `orbit`, the default, is a real three-dimensional model: the entities are laid out in space by
149
+ * a spring-electrical simulation and the camera turns around them. `flat` is echarts-gl's own
150
+ * `graphGL` — force-atlas2 on the GPU, drawn on a plane with an orthographic camera — which draws
151
+ * more nodes at once and is the mode to reach for when a graph is big enough that the third
152
+ * dimension costs more than it shows.
153
+ */
154
+ interface Graph3dPanel extends PanelBase {
155
+ kind: "graph3d";
156
+ nodes: Graph3dNode[];
157
+ edges: Graph3dEdge[];
158
+ /** Type name to hex colour, overriding the palette's own assignment. At most 32 entries. */
159
+ types?: Record<string, string>;
160
+ /** The id of the node to highlight and always label. */
161
+ focus?: string;
162
+ /** How it is drawn: a turning 3D model, or the flat GPU layout. Default "orbit". */
163
+ mode?: "orbit" | "flat";
164
+ /** Whether the graph moves at all — settling, and turning. Default true. */
165
+ rotate?: boolean;
166
+ }
167
+ type Panel = KpiPanel | GaugePanel | RankPanel | ChartPanel | Chart3dPanel | GlobePanel | TimelinePanel | Graph3dPanel;
83
168
  type PanelKind = Panel["kind"];
84
169
  interface ScreenDefinition {
85
170
  title?: string;
@@ -91,6 +176,85 @@ interface ScreenDefinition {
91
176
  columns: number;
92
177
  panels: Panel[];
93
178
  }
179
+ /**
180
+ * The bit of GeoJSON a globe needs: WGS84 rings, in longitude/latitude order.
181
+ *
182
+ * Deliberately not the whole of RFC 7946. Only the two polygon geometries are drawn, and
183
+ * everything else on a feature is ignored, so a host can hand over `world-atlas` straight out of
184
+ * `topojson-client` without a type assertion and without this package taking a GeoJSON
185
+ * dependency.
186
+ */
187
+ type GlobeGeometry = {
188
+ type: "Polygon";
189
+ coordinates: number[][][];
190
+ } | {
191
+ type: "MultiPolygon";
192
+ coordinates: number[][][][];
193
+ } | {
194
+ type: string;
195
+ coordinates?: unknown;
196
+ };
197
+ interface GlobeFeatureCollection {
198
+ type: "FeatureCollection";
199
+ features: Array<{
200
+ type?: string;
201
+ geometry?: GlobeGeometry | null;
202
+ properties?: Record<string, unknown> | null;
203
+ }>;
204
+ }
205
+ /**
206
+ * What the host wants the planet to look like.
207
+ *
208
+ * The fence says where the events are; this says what they are drawn on, and it is host
209
+ * configuration rather than a panel field on purpose: a texture is a URL, and a URL a model
210
+ * wrote is a request a page would be making on the model's say-so.
211
+ *
212
+ * Precedence is `baseTexture`, then `countries`, then the painted graticule the plugin has
213
+ * always drawn — so a host that sets none of this gets exactly the globe it got before.
214
+ */
215
+ interface GlobeSkin {
216
+ /** An equirectangular (2:1) day texture, as a URL or a data URL the host serves itself. */
217
+ baseTexture?: string;
218
+ /** An equirectangular height map, for bump shading. Optional. */
219
+ heightTexture?: string;
220
+ /** Country outlines to rasterise onto a 2:1 canvas when there is no `baseTexture`. */
221
+ countries?: GlobeFeatureCollection;
222
+ /** Fill for land. Default: from the palette. */
223
+ land?: string;
224
+ /** Fill for sea. Default: from the palette. */
225
+ ocean?: string;
226
+ /** Stroke for country borders. Default: from the palette. */
227
+ border?: string;
228
+ /** How the sphere is lit. Default "lambert" once a skin is given. */
229
+ shading?: "color" | "lambert" | "realistic";
230
+ /** The glow around the rim. Default true. */
231
+ atmosphere?: boolean;
232
+ /**
233
+ * The sun.
234
+ *
235
+ * `time` is what echarts-gl puts the main light at, so the terminator falls where the sun
236
+ * actually is; the default is now. `ambient` is how much the night side still shows,
237
+ * 0–1; the default 0.5 keeps coastlines readable, a host whose photograph has dark oceans
238
+ * raises it.
239
+ */
240
+ light?: {
241
+ intensity?: number;
242
+ ambient?: number;
243
+ time?: Date | string;
244
+ };
245
+ }
246
+ /**
247
+ * What the host wants to happen when a reader clicks something.
248
+ *
249
+ * A timeline item carries a `url`, and without a handler the plugin opens it in a new tab. A host
250
+ * that has its own idea of what a claim is — a drawer, a route, a second panel — passes
251
+ * `onItemClick` and takes the click instead, `url` and all. There is no default for a graph node:
252
+ * a node is not a link, so a host that wants a click to mean something has to say so.
253
+ */
254
+ interface BigscreenEvents {
255
+ onItemClick?: (item: TimelineItem) => void;
256
+ onNodeClick?: (node: Graph3dNode) => void;
257
+ }
94
258
  interface BigscreenOptions {
95
259
  /** Refuse a screen with more panels than this. Default 24. */
96
260
  maxPanels?: number;
@@ -100,6 +264,10 @@ interface BigscreenOptions {
100
264
  animate?: boolean;
101
265
  /** Host override for the palette; a screen's own `theme` wins when set in the fence. */
102
266
  theme?: ScreenTheme;
267
+ /** Host override for what a globe panel's planet looks like. Unset draws the graticule. */
268
+ globe?: GlobeSkin;
269
+ /** What a click on a timeline item or a graph node does. */
270
+ events?: BigscreenEvents;
103
271
  }
104
272
  interface BigscreenError {
105
273
  code: "invalid-json" | "invalid-definition" | "too-large";
@@ -129,6 +297,31 @@ declare function bigscreenPromptSpec(locale?: string): string;
129
297
 
130
298
  //#endregion
131
299
  //#region src/parse.d.ts
300
+ /**
301
+ * Every limit the parser enforces, named.
302
+ *
303
+ * Exported because a limit the parser checks and nothing states is a trap: the prompt spec has to
304
+ * name the same numbers, and a host building a fence of its own needs to know where the cliff is.
305
+ * Overrunning any of them voids the whole block, so they are all deliberately generous — generous
306
+ * enough that the biggest of them are not reachable under the default 64 KiB source cap: five
307
+ * thousand edges is around a hundred kilobytes of JSON, so a host that really wants a graph that
308
+ * size has to raise `maxSourceBytes` as well.
309
+ */
310
+ declare const MAX_POINTS = 5000;
311
+ declare const MAX_ITEMS = 50;
312
+ declare const MAX_ARCS = 300;
313
+ declare const MAX_LANES = 24;
314
+ declare const MAX_TIMELINE_ITEMS = 500;
315
+ declare const MAX_LINKS = 500;
316
+ declare const MAX_NODES = 2000;
317
+ declare const MAX_EDGES = 5000;
318
+ declare const MAX_TYPES = 32;
319
+ declare const MAX_LANE_NAME = 40;
320
+ declare const MAX_ITEM_LABEL = 120;
321
+ declare const MAX_ITEM_DETAIL = 400;
322
+ declare const MAX_URL = 400;
323
+ declare const MAX_NODE_NAME = 80;
324
+ declare const MAX_TYPE_NAME = 32;
132
325
  /** Validate one `bigscreen` fence, or explain why it cannot be shown. */
133
326
  declare function parseBigscreen(source: string, options?: {
134
327
  maxPanels?: number;
@@ -182,10 +375,447 @@ declare function chart3dOption(panel: Chart3dPanel, c: Palette, animate: boolean
182
375
  *
183
376
  * ECharts' globe wants a texture, and the usual one is an image fetched from somewhere — which a
184
377
  * page must not do on a model's say-so. So the texture is painted here: a deep sphere with a
185
- * graticule, which is what a data wall's globe looks like anyway. Arcs get a moving trail.
378
+ * graticule, which is what a data wall's globe looks like anyway. A host that wants a real earth
379
+ * says so in `BigscreenOptions.globe` and `earth.ts` takes over; this stays the fallback.
380
+ */
381
+ declare function globeTexture(c: Palette, theme: "dark" | "light"): string | undefined;
382
+ /**
383
+ * The sphere itself, with and without a host-supplied earth.
384
+ *
385
+ * Without one, everything below the `skin` branch is the globe this plugin has always drawn: a
386
+ * flat-lit ball with a graticule on it, every point labelled. A wire grid needs no sun — there is
387
+ * nothing on it a shadow would tell you about — and `shading: "color"` with the light turned down
388
+ * is what keeps it evenly readable while it turns.
389
+ *
390
+ * With one, the ball is a planet: lambert (or the host's choice) so the terminator falls where the
391
+ * sun actually is, an atmosphere at the rim, and labels only on the points worth reading from
392
+ * across a room. `postEffect` stays off — bloom and depth of field on one of six panels is a
393
+ * frame budget spent on the wrong thing.
186
394
  */
395
+ declare function globeOption(panel: GlobePanel, c: Palette, animate: boolean, texture: string | undefined, skin?: GlobeSkin): EChartsCoreOption;
187
396
 
188
- declare function globeOption(panel: GlobePanel, c: Palette, animate: boolean, texture: string | undefined): EChartsCoreOption;
397
+ //#endregion
398
+ //#region src/earth.d.ts
399
+ /** The three colours a painted world is made of, defaulted from the screen's palette. */
400
+ interface EarthColours {
401
+ ocean: string;
402
+ land: string;
403
+ border: string;
404
+ }
405
+ declare function earthColours(c: Palette, theme: ScreenTheme, skin?: GlobeSkin): EarthColours;
406
+ /**
407
+ * Rasterise a world onto a 2:1 canvas and hand it over as a data URL.
408
+ *
409
+ * A data URL rather than the canvas element: that is the path echarts-gl treats as an image to
410
+ * decode, and it involves no request. A canvas element handed to `baseTexture` is a white ball.
411
+ *
412
+ * Rings are filled even-odd so that a country drawn as an outer ring plus holes — Lesotho inside
413
+ * South Africa, the lakes inside Canada — comes out with the holes in it whichever way round the
414
+ * source wound them.
415
+ */
416
+ declare function countriesTexture(countries: GlobeFeatureCollection, colours: EarthColours): string | undefined;
417
+ /**
418
+ * The texture a globe panel wears, by the host's precedence.
419
+ *
420
+ * `baseTexture` wins because a host that has a photograph has already decided; `countries` is
421
+ * next because outlines a host bundled are still the host's map; and with neither there is the
422
+ * graticule, which is what this plugin has always drawn and what every consumer that never heard
423
+ * of a `globe` option keeps getting.
424
+ */
425
+ declare function earthTexture(c: Palette, theme: ScreenTheme, skin?: GlobeSkin): string | undefined;
426
+
427
+ //#endregion
428
+ //#region src/timeline.d.ts
429
+ /**
430
+ * A timeline of claims, one lane per source.
431
+ *
432
+ * The panel exists for the line nobody else draws: two outlets said things that cannot both be
433
+ * true, and the red segment between their two points is the whole point of the picture. So the
434
+ * lanes stay in the order they were given (a reader compares row against row, and a chart that
435
+ * reorders them silently answers a different question), time runs across, and every claim is one
436
+ * point that can be clicked back to the page it came from.
437
+ *
438
+ * Pure: the option is a function of the panel and the palette, so it can be tested without a
439
+ * canvas and so the same claims draw the same picture on every screen.
440
+ */
441
+ /** How many claims carry a written label; the rest are on the tooltip. */
442
+ declare const TIMELINE_LABELS = 12;
443
+ /**
444
+ * The window drawn, in epoch milliseconds.
445
+ *
446
+ * The panel's own `from` and `to` win where they are given. Otherwise it is the claims' own range
447
+ * with 5% on each side, because a point exactly on the axis reads as clipped rather than as first.
448
+ * A single claim has no range to take a fraction of, so it gets an hour either way — enough for
449
+ * the point to sit somewhere rather than in the middle of nothing.
450
+ */
451
+ declare function timelineWindow(panel: TimelinePanel): [number, number];
452
+ /**
453
+ * Which claims have room for a label, as indexes into `panel.items`.
454
+ *
455
+ * A label is drawn beside its point, on its own lane, so what decides whether it can be read is
456
+ * the empty time on either side of it within that lane — not how important the claim is and not
457
+ * what order it was written in. Twelve labels on a wall panel is about where a reader stops
458
+ * reading them anyway, and the rest are one hover away.
459
+ */
460
+ declare function spacedItems(panel: TimelinePanel, max?: number): Set<number>;
461
+ /**
462
+ * How tall a timeline of this many lanes has to be.
463
+ *
464
+ * 320 is the default panel, and it holds a handful of lanes comfortably. Past that the lanes get
465
+ * a floor of 28 pixels each: below that the points of two neighbouring outlets touch, and a
466
+ * contradiction drawn between them stops being a line between two rows.
467
+ */
468
+ declare function timelineHeight(lanes: number): number;
469
+ declare function timelineOption(panel: TimelinePanel, c: Palette, animate: boolean): EChartsCoreOption;
470
+
471
+ //#endregion
472
+ //#region src/graph3d.d.ts
473
+ /**
474
+ * The vocabulary every knowledge graph panel is drawn in, and the flat mode's own option.
475
+ *
476
+ * A type's colour, a node's degree, the legend in the corner and the tooltip are the same in both
477
+ * modes and live here. `orbit.ts` — the default — turns the entities into a model in space;
478
+ * `graph3dOption` below is `flat`, echarts-gl's `graphGL`: force-atlas2 on the GPU, drawn on a
479
+ * plane with an orthographic camera. It draws more nodes at once than the model does, which is
480
+ * the reason it is still here.
481
+ *
482
+ * Pure: the option is a function of the panel and the palette.
483
+ */
484
+ /** How many entities carry a written label. The rest are one hover away. */
485
+ declare const GRAPH_LABELS = 20;
486
+ /**
487
+ * How the layout is run.
488
+ *
489
+ * `steps` is iterations per frame and `maxSteps` is where the layout stops. Settling takes
490
+ * `maxSteps / steps` frames — 125 of them, a shade over two seconds at sixty frames a second,
491
+ * which is long enough to watch a graph of five hundred entities pull itself apart and short
492
+ * enough that nobody waits for it. When nothing is meant to move, the same thousand iterations
493
+ * are spent four frames deep and the reader gets the settled graph instead of the settling.
494
+ *
495
+ * (echarts-gl 2.x bounds the layout with `maxSteps`; there is no convergence threshold to set.)
496
+ */
497
+ declare const GRAPH_SETTLE_STEPS = 8;
498
+ declare const GRAPH_MAX_STEPS = 1000;
499
+ /** How many types the corner legend lists before it would start covering the graph. */
500
+ declare const GRAPH_LEGEND_ROWS = 12;
501
+ /**
502
+ * The colour of a type.
503
+ *
504
+ * Hashed rather than handed out in order of appearance, because two graph panels on one wall must
505
+ * colour `outlet` the same way, and the order the types happen to appear in is different in each
506
+ * of them. A hash means two types can land on the same colour, which is what the legend in the
507
+ * corner is for; a panel that cares says so in `types`.
508
+ *
509
+ * Only the first seven series colours are in the ring. The eighth is a second cyan a shade off
510
+ * the accent, and two types a reader cannot tell apart is worse than two types sharing a colour
511
+ * the legend admits to sharing.
512
+ *
513
+ * A node with no type gets the muted colour: it is not a category, so it does not get one of the
514
+ * colours the categories are being told apart by.
515
+ */
516
+ declare function typeColour(type: string | undefined, c: Palette, overrides?: Record<string, string>): string;
517
+ /** How many edges touch each node. Both ends count, so a self-edge counts twice. */
518
+ declare function degrees(panel: Graph3dPanel): Map<string, number>;
519
+ interface GraphLegendEntry {
520
+ label: string;
521
+ colour: string;
522
+ shape: "node" | "edge";
523
+ }
524
+ /**
525
+ * The key drawn in the panel's corner: every type that appears, once, in its own colour.
526
+ *
527
+ * Nodes first, then edges, each in the order it first appears — which is the order the model
528
+ * wrote them in, and therefore the order it was thinking in. An untyped graph gets no legend at
529
+ * all rather than an empty box.
530
+ */
531
+ declare function graphLegend(panel: Graph3dPanel, c: Palette): GraphLegendEntry[];
532
+ /**
533
+ * What an entity or an edge says on hover, in both modes.
534
+ *
535
+ * Escaped by hand: ECharts renders a formatter's return as HTML and every name here was written
536
+ * by a model. An edge is told apart by `dataType` in the flat series and by carrying its own
537
+ * `coords` in the orbit one, which is the only thing the two series disagree about.
538
+ */
539
+ declare function graphTooltip(params: {
540
+ dataType?: string;
541
+ data?: unknown;
542
+ }): string;
543
+ /**
544
+ * The `flat` mode: `graphGL`, laid out by force-atlas2 on the GPU.
545
+ *
546
+ * Unchanged since it was written, byte for byte, and pinned by a test that says so — a panel that
547
+ * asked for this mode asked for exactly this picture. The 3D model is `graphOrbitOption`, which
548
+ * takes positions rather than computing them, because it is stepped in front of the reader.
549
+ */
550
+ declare function graph3dOption(panel: Graph3dPanel, c: Palette, animate: boolean): EChartsCoreOption;
551
+
552
+ //#endregion
553
+ //#region src/layout3d.d.ts
554
+ /**
555
+ * A spring–electrical layout in three dimensions.
556
+ *
557
+ * Fruchterman–Reingold's forces, one dimension further: every pair of entities pushes apart with
558
+ * `k²/d`, every edge pulls its ends together with `d²/k`, a weak spring holds the whole thing to
559
+ * the origin, and a falling temperature caps how far a node may move in one step so the graph
560
+ * cools into a shape instead of oscillating around one.
561
+ *
562
+ * Written here rather than taken from a dependency for two reasons. The panel needs positions in
563
+ * three dimensions and echarts-gl's own layouts are two-dimensional; and the layout has to be
564
+ * *steppable* — a few steps per animation frame — so the reader watches the graph pull itself
565
+ * apart rather than being handed a settled picture. A library that runs to convergence behind a
566
+ * promise cannot do that.
567
+ *
568
+ * Deterministic on purpose: the starting positions are a hash of the node ids on a sphere, so the
569
+ * same knowledge graph draws the same picture twice running, and a screenshot test means
570
+ * something. Nothing here calls `Math.random`.
571
+ *
572
+ * Complexity is O(n²) per step, which is why `layoutSteps` spends fewer steps on a bigger graph.
573
+ */
574
+ /** The distance an edge settles at: the unit everything else here is measured in. */
575
+ declare const LAYOUT_SPRING = 1;
576
+ /**
577
+ * The pull to the origin, per unit of distance from it.
578
+ *
579
+ * Without it a knowledge graph with two unconnected components is unbounded: nothing attracts
580
+ * them to each other, the repulsion between them is never opposed, and one of them leaves the
581
+ * panel and keeps going.
582
+ */
583
+ declare const LAYOUT_GRAVITY = 0.08;
584
+ /**
585
+ * FNV-1a.
586
+ *
587
+ * The one hash in this package: the same function that decides a type's colour decides where a
588
+ * node starts, so both are a function of the name and of nothing else.
589
+ */
590
+ declare function hash(value: string): number;
591
+ declare function layoutSteps(n: number): number;
592
+ /**
593
+ * How many steps are spent per animation frame while the graph settles in front of the reader.
594
+ *
595
+ * Small enough to leave the frame time for drawing, and large enough that a six-entity graph —
596
+ * which is given three hundred steps — is finished in well under a second rather than in five.
597
+ * At a few hundred entities a single step already costs most of a frame, so it drops to one and
598
+ * the graph settles at whatever pace the machine can manage.
599
+ */
600
+ declare function layoutChunk(n: number): number;
601
+ /**
602
+ * The radius a graph of `n` entities settles inside, which is also where it is started.
603
+ *
604
+ * A cube root, not a square root. Inside a ball of charge the repulsion at radius `r` comes only
605
+ * from what is enclosed — `n(r/R)³` of it, over `r²` — so balancing it against a gravity of `g·r`
606
+ * gives `R = k·∛(n/g)`. Guessing `sqrt` instead put a two-thousand-entity graph's starting sphere
607
+ * five times too wide, and the first half of its forty steps went on collapsing rather than on
608
+ * laying anything out.
609
+ */
610
+ declare function layoutRadius(n: number): number;
611
+ type Vec3 = readonly [number, number, number];
612
+ /**
613
+ * Where every node starts, as `[x, y, z]` per node in the order the ids were given.
614
+ *
615
+ * A node the caller remembers keeps exactly the position it had, which is what stops a graph that
616
+ * gained three entities from reshuffling the twenty that were already there. Everything else is
617
+ * placed on a sphere by the hash of its id — a Fibonacci-like spiral from two independent hashes,
618
+ * so ids that are one character apart do not end up next to each other — scaled to the cloud the
619
+ * remembered nodes already occupy, or to the graph's own settling radius when there is nothing to
620
+ * remember.
621
+ */
622
+ declare function seedPositions(ids: readonly string[], seed?: ReadonlyMap<string, Vec3>): Float32Array;
623
+ interface Layout {
624
+ /** Run `count` more steps, or one. Steps past `steps` do nothing. */
625
+ step(count?: number): void;
626
+ /**
627
+ * The current positions, as `[x, y, z]` per node in the order the nodes were given.
628
+ *
629
+ * The live buffer, not a copy: the render loop reads it every frame and must not allocate.
630
+ * A caller keeping the positions past the next `step` has to copy them itself.
631
+ */
632
+ positions(): Float32Array;
633
+ /** Whether the layout has spent all its steps. */
634
+ readonly done: boolean;
635
+ /** How many steps it will spend in total. */
636
+ readonly steps: number;
637
+ /** How many it has spent. */
638
+ readonly taken: number;
639
+ }
640
+ /**
641
+ * A layout over `nodes` and `edges`, ready to be stepped.
642
+ *
643
+ * `seed` is the positions the same graph settled into last time, by node id; the ids it does not
644
+ * mention are placed by their hash. An edge naming a node that is not there is skipped rather
645
+ * than refused — the parser has already rejected those, and a layout is not the place to raise.
646
+ */
647
+ declare function createLayout(nodes: readonly Graph3dNode[], edges: readonly Graph3dEdge[], seed?: ReadonlyMap<string, Vec3>): Layout;
648
+
649
+ //#endregion
650
+ //#region src/orbit.d.ts
651
+ /**
652
+ * The knowledge graph as a model you look at, rather than a picture you look down on.
653
+ *
654
+ * `layout3d.ts` puts the entities in space; this puts a camera in there with them. A `grid3D`
655
+ * holds the coordinate system, a `scatter3D` draws the entities and a `line3D` draws the edges,
656
+ * and the box the three of them share is deliberately invisible: a knowledge graph has no axes
657
+ * to read, and the only thing an axis would add is furniture.
658
+ *
659
+ * Pure: the option is a function of the panel, the palette and the positions. The positions come
660
+ * from outside because the layout is stepped — the mount loop hands the same builder a slightly
661
+ * different set of coordinates every frame while the graph settles.
662
+ */
663
+ /**
664
+ * The half-width of the space the graph is drawn in, in the box's own units.
665
+ *
666
+ * Everything about the camera — the distance it sits at, how big a node reads at that distance —
667
+ * is a constant, so the graph has to be scaled to it rather than the other way round. The layout
668
+ * works in units of its own spring length and a graph of two thousand is naturally four times
669
+ * wider than a graph of six; `orbitScale` divides that difference out, and this is what is left.
670
+ */
671
+ declare const ORBIT_EXTENT = 50;
672
+ /** The cube the coordinate system is drawn in. Equal on all three sides, or the shape is a lie. */
673
+ declare const ORBIT_BOX = 140;
674
+ /**
675
+ * The camera: how far out it sits, how fast it goes round, and the field of view it does it with.
676
+ *
677
+ * The distance is not a matter of taste. The graph is fitted to the box, so its furthest entity
678
+ * sits half a box from the middle — and as the camera turns, that entity comes round to the near
679
+ * side, where the perspective divide is over a distance of `ORBIT_DISTANCE - ORBIT_BOX / 2`
680
+ * rather than `ORBIT_DISTANCE`. A camera framed for the middle therefore crops the graph twice a
681
+ * revolution, which is exactly what it did at 180: an entity and its edge walked off the bottom
682
+ * of the panel and back. So the distance is set from the near face, with room left over for the
683
+ * labels, which stick out further than the entities they belong to.
684
+ *
685
+ * echarts-gl's grid3D camera has a vertical field of view of 50 degrees and is not configurable
686
+ * through `viewControl`, so it is written down here rather than passed.
687
+ */
688
+ declare const ORBIT_FOV = 50;
689
+ declare const ORBIT_DISTANCE = 260;
690
+ /** Where the layout has to be moved to, and what it has to be multiplied by, to fill the box. */
691
+ interface OrbitFrame {
692
+ centre: [number, number, number];
693
+ scale: number;
694
+ }
695
+ /**
696
+ * The graph's own bounding box, as the transform that puts it in the middle of the panel.
697
+ *
698
+ * Its box, not its bounding sphere, and its centre, not the origin. A settled graph is rarely a
699
+ * ball: the eight-entity example comes out about 72 units wide, 26 tall and 40 deep, centred six
700
+ * units left of where it started. Scaling that by its largest radius left it filling a fifth of
701
+ * the panel and sitting off to one side — correct, and unreadable. Fitting the longest of the
702
+ * three spans instead fills the frame in whichever direction the graph is actually long, and
703
+ * because every other span is shorter by definition, nothing lands outside the box.
704
+ */
705
+ declare function orbitFrame(positions: Float32Array): OrbitFrame;
706
+ /** One entity, as `scatter3D` reads it. */
707
+ interface OrbitNode {
708
+ id: string;
709
+ name: string;
710
+ /** `[x, y, z, size]`: the first three place it, the fourth is what `symbolSize` reads. */
711
+ value: [number, number, number, number];
712
+ itemStyle: {
713
+ color: string;
714
+ opacity: number;
715
+ };
716
+ /** Whether the name is written beside it. The rest are one hover away. */
717
+ labelled: boolean;
718
+ /** Carried for the tooltip and the host's click; `type` is taken by ECharts. */
719
+ nodeType: string | undefined;
720
+ degree: number;
721
+ node: Graph3dNode;
722
+ }
723
+ /**
724
+ * One vertex of the single polyline every edge is drawn on.
725
+ *
726
+ * echarts-gl has no series that draws many separate lines in a `grid3D`: `lines3D` lays out only
727
+ * on a globe, a geo3D or a mapbox, and on a cartesian3D it throws for want of a layout. `line3D`
728
+ * does work there, but it is one polyline through every point it is given — so the edges are
729
+ * strung together into one, and the joins between them are made to disappear by giving both their
730
+ * ends an opacity of zero. Four vertices per edge: the start twice and the end twice, transparent
731
+ * on the outside and the edge's own colour on the inside.
732
+ *
733
+ * A(0) -> A(c) -> B(c) -> B(0) -> A'(0) -> A'(c) -> ...
734
+ * \_____________/ the edge \__ the join, transparent at
735
+ * both ends and so invisible
736
+ *
737
+ * The doubled points are what the shader's own `position == positionPrev` branch is for, so they
738
+ * cost two degenerate quads and no artefacts.
739
+ *
740
+ * `lineStyle`, not `itemStyle`: `line3D` declares `visualStyleAccessPath: "lineStyle"`, so a
741
+ * colour written under `itemStyle` is read by nothing and every edge quietly comes out in the
742
+ * series' one colour — with the joins between them drawn in it too, which turns a knowledge graph
743
+ * into a ball of wool.
744
+ */
745
+ interface OrbitEdgePoint {
746
+ value: [number, number, number];
747
+ lineStyle: {
748
+ color: string;
749
+ opacity: number;
750
+ };
751
+ }
752
+ /** How many vertices one edge contributes to that polyline. */
753
+ declare const EDGE_VERTICES = 4;
754
+ interface OrbitData {
755
+ nodes: OrbitNode[];
756
+ edges: OrbitEdgePoint[];
757
+ }
758
+ /**
759
+ * The two series' data, from the panel and wherever the layout has got to.
760
+ *
761
+ * Built as one thing because the edges have to agree with the nodes: an edge is drawn between two
762
+ * points, not between two ids, so a frame that moved the nodes and left the edges behind would
763
+ * detach every line from both its ends.
764
+ */
765
+ declare function graphOrbitData(panel: Graph3dPanel, c: Palette, positions: Float32Array): OrbitData;
766
+ /**
767
+ * The whole scene.
768
+ *
769
+ * `animate` is the host's word and `panel.rotate` is the fence's; either one saying no stops the
770
+ * camera. ECharts' own animation is off throughout — on each series as well as at the root,
771
+ * because echarts-gl's vertex animation asks the *series* whether it may animate and does not
772
+ * fall back to the screen's answer. While the graph settles this option's data is replaced every
773
+ * frame, and an animated transition would spend that frame interpolating towards positions the
774
+ * next frame has already superseded.
775
+ */
776
+ declare function graphOrbitOption(panel: Graph3dPanel, c: Palette, animate: boolean, positions: Float32Array): EChartsCoreOption;
777
+
778
+ //#endregion
779
+ //#region src/positions.d.ts
780
+ /**
781
+ * Where each graph settled last time it was drawn.
782
+ *
783
+ * A streamed answer re-renders the same fence as the model writes it: a graph of twenty entities
784
+ * becomes the same graph of twenty-three, and the reconciler tears the panel down and mounts a
785
+ * new one. Without a memory the new layout starts from the hash again, every node lands somewhere
786
+ * else, and the reader — who was reading it — watches the picture they had just understood
787
+ * dissolve because three names arrived.
788
+ *
789
+ * So the positions are kept by node id, under a key that deliberately does *not* depend on the
790
+ * node set: the ids that are still there resume exactly where they were, and only the new ones
791
+ * have to find a place. It is module-level state, which is what makes it survive the remount; it
792
+ * is bounded so a long conversation full of graphs cannot grow it without limit, and it is
793
+ * forgettable so tests do not leak into each other.
794
+ */
795
+ /** How many graphs are remembered at once. Beyond this the least recently used one is dropped. */
796
+ declare const REMEMBERED_GRAPHS = 8;
797
+ /**
798
+ * What identifies a graph across a re-render.
799
+ *
800
+ * The title, because that is the one thing a model rewriting its own fence keeps stable while the
801
+ * entities underneath it change. A panel with no title falls back to its first entity, which is
802
+ * the next most stable thing there is — a graph usually keeps the entity it was drawn around.
803
+ * The prefix keeps a panel titled `kyiv` from colliding with an untitled one whose first node is
804
+ * `kyiv`.
805
+ */
806
+ declare function graphKey(panel: Graph3dPanel): string;
807
+ /** The positions this graph settled into last time, by node id, or nothing. */
808
+ declare function recallPositions(key: string): ReadonlyMap<string, Vec3> | undefined;
809
+ /**
810
+ * Remember where a graph settled.
811
+ *
812
+ * The positions are copied out of the buffer rather than kept by reference: `Layout.positions()`
813
+ * hands back the live array, and a layout that is still running would otherwise have this
814
+ * remember whatever it became several frames later.
815
+ */
816
+ declare function rememberPositions(key: string, ids: readonly string[], positions: Float32Array): void;
817
+ /** Drop every remembered graph. For tests, and for a host tearing a page down. */
818
+ declare function forgetPositions(): void;
189
819
 
190
820
  //#endregion
191
821
  //#region src/index.d.ts
@@ -202,4 +832,4 @@ declare const bigscreenCss: string;
202
832
  declare function bigscreen(options?: BigscreenOptions): AIGuiPlugin;
203
833
 
204
834
  //#endregion
205
- export { BigscreenError, BigscreenOptions, BigscreenResult, Chart3dPanel, ChartPanel, GaugePanel, GlobePanel, KpiPanel, Panel, PanelKind, RankPanel, ScreenDefinition, ScreenTheme, bigscreen, bigscreenCss, bigscreenPromptSpec, chart3dOption, chartOption, formatNumber, gaugeColour, gaugeOption, globeOption, palette, parseBigscreen, withAlpha };
835
+ export { BigscreenError, BigscreenEvents, BigscreenOptions, BigscreenResult, Chart3dPanel, ChartPanel, EDGE_VERTICES, EarthColours, GRAPH_LABELS, GRAPH_LEGEND_ROWS, GRAPH_MAX_STEPS, GRAPH_SETTLE_STEPS, GaugePanel, GlobeFeatureCollection, GlobeGeometry, GlobePanel, GlobeSkin, Graph3dEdge, Graph3dNode, Graph3dPanel, GraphLegendEntry, KpiPanel, LAYOUT_GRAVITY, LAYOUT_SPRING, Layout, MAX_ARCS, MAX_EDGES, MAX_ITEMS, MAX_ITEM_DETAIL, MAX_ITEM_LABEL, MAX_LANES, MAX_LANE_NAME, MAX_LINKS, MAX_NODES, MAX_NODE_NAME, MAX_POINTS, MAX_TIMELINE_ITEMS, MAX_TYPES, MAX_TYPE_NAME, MAX_URL, ORBIT_BOX, ORBIT_DISTANCE, ORBIT_EXTENT, ORBIT_FOV, OrbitData, OrbitEdgePoint, OrbitFrame, OrbitNode, Panel, PanelKind, REMEMBERED_GRAPHS, RankPanel, ScreenDefinition, ScreenTheme, TIMELINE_LABELS, TimelineItem, TimelineLane, TimelineLink, TimelinePanel, Vec3, bigscreen, bigscreenCss, bigscreenPromptSpec, chart3dOption, chartOption, countriesTexture, createLayout, degrees, earthColours, earthTexture, forgetPositions, formatNumber, gaugeColour, gaugeOption, globeOption, globeTexture, graph3dOption, graphKey, graphLegend, graphOrbitData, graphOrbitOption, graphTooltip, hash, layoutChunk, layoutRadius, layoutSteps, orbitFrame, palette, parseBigscreen, recallPositions, rememberPositions, seedPositions, spacedItems, timelineHeight, timelineOption, timelineWindow, typeColour, withAlpha };