@fnndsc/orrery 0.1.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 (116) hide show
  1. package/README.md +12 -0
  2. package/dist/controls/cameraRig.d.ts +223 -0
  3. package/dist/controls/cameraRig.js +353 -0
  4. package/dist/controls/cameraRig.js.map +1 -0
  5. package/dist/controls/gestures.d.ts +133 -0
  6. package/dist/controls/gestures.js +282 -0
  7. package/dist/controls/gestures.js.map +1 -0
  8. package/dist/controls/index.d.ts +9 -0
  9. package/dist/controls/index.js +10 -0
  10. package/dist/controls/index.js.map +1 -0
  11. package/dist/controls/picker.d.ts +117 -0
  12. package/dist/controls/picker.js +167 -0
  13. package/dist/controls/picker.js.map +1 -0
  14. package/dist/controls/replay.d.ts +94 -0
  15. package/dist/controls/replay.js +147 -0
  16. package/dist/controls/replay.js.map +1 -0
  17. package/dist/draw/censusField.d.ts +113 -0
  18. package/dist/draw/censusField.js +241 -0
  19. package/dist/draw/censusField.js.map +1 -0
  20. package/dist/draw/constants.d.ts +13 -0
  21. package/dist/draw/constants.js +14 -0
  22. package/dist/draw/constants.js.map +1 -0
  23. package/dist/draw/geometry.d.ts +33 -0
  24. package/dist/draw/geometry.js +55 -0
  25. package/dist/draw/geometry.js.map +1 -0
  26. package/dist/draw/handoff.d.ts +11 -0
  27. package/dist/draw/handoff.js +12 -0
  28. package/dist/draw/handoff.js.map +1 -0
  29. package/dist/draw/handoffField.d.ts +74 -0
  30. package/dist/draw/handoffField.js +151 -0
  31. package/dist/draw/handoffField.js.map +1 -0
  32. package/dist/draw/index.d.ts +20 -0
  33. package/dist/draw/index.js +21 -0
  34. package/dist/draw/index.js.map +1 -0
  35. package/dist/draw/labelField.d.ts +63 -0
  36. package/dist/draw/labelField.js +149 -0
  37. package/dist/draw/labelField.js.map +1 -0
  38. package/dist/draw/lamps.d.ts +16 -0
  39. package/dist/draw/lamps.js +17 -0
  40. package/dist/draw/lamps.js.map +1 -0
  41. package/dist/draw/nebula.d.ts +8 -0
  42. package/dist/draw/nebula.js +28 -0
  43. package/dist/draw/nebula.js.map +1 -0
  44. package/dist/draw/palette.d.ts +41 -0
  45. package/dist/draw/palette.js +32 -0
  46. package/dist/draw/palette.js.map +1 -0
  47. package/dist/draw/sphereField.d.ts +98 -0
  48. package/dist/draw/sphereField.js +168 -0
  49. package/dist/draw/sphereField.js.map +1 -0
  50. package/dist/draw/starField.d.ts +127 -0
  51. package/dist/draw/starField.js +267 -0
  52. package/dist/draw/starField.js.map +1 -0
  53. package/dist/draw/stars.d.ts +65 -0
  54. package/dist/draw/stars.js +132 -0
  55. package/dist/draw/stars.js.map +1 -0
  56. package/dist/draw/timing.d.ts +11 -0
  57. package/dist/draw/timing.js +12 -0
  58. package/dist/draw/timing.js.map +1 -0
  59. package/dist/draw/tubeField.d.ts +131 -0
  60. package/dist/draw/tubeField.js +352 -0
  61. package/dist/draw/tubeField.js.map +1 -0
  62. package/dist/draw/tubes.d.ts +41 -0
  63. package/dist/draw/tubes.js +116 -0
  64. package/dist/draw/tubes.js.map +1 -0
  65. package/dist/index.d.ts +15 -0
  66. package/dist/index.js +15 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/layout/accretion.d.ts +31 -0
  69. package/dist/layout/accretion.js +384 -0
  70. package/dist/layout/accretion.js.map +1 -0
  71. package/dist/layout/constellations.d.ts +25 -0
  72. package/dist/layout/constellations.js +197 -0
  73. package/dist/layout/constellations.js.map +1 -0
  74. package/dist/layout/galaxy.d.ts +12 -0
  75. package/dist/layout/galaxy.js +99 -0
  76. package/dist/layout/galaxy.js.map +1 -0
  77. package/dist/layout/hierarchy.d.ts +45 -0
  78. package/dist/layout/hierarchy.js +464 -0
  79. package/dist/layout/hierarchy.js.map +1 -0
  80. package/dist/layout/index.d.ts +20 -0
  81. package/dist/layout/index.js +21 -0
  82. package/dist/layout/index.js.map +1 -0
  83. package/dist/layout/layoutInput.d.ts +29 -0
  84. package/dist/layout/layoutInput.js +45 -0
  85. package/dist/layout/layoutInput.js.map +1 -0
  86. package/dist/layout/molecule.d.ts +64 -0
  87. package/dist/layout/molecule.js +155 -0
  88. package/dist/layout/molecule.js.map +1 -0
  89. package/dist/layout/pull.d.ts +94 -0
  90. package/dist/layout/pull.js +137 -0
  91. package/dist/layout/pull.js.map +1 -0
  92. package/dist/layout/ranked.d.ts +75 -0
  93. package/dist/layout/ranked.js +148 -0
  94. package/dist/layout/ranked.js.map +1 -0
  95. package/dist/layout/registry.d.ts +23 -0
  96. package/dist/layout/registry.js +165 -0
  97. package/dist/layout/registry.js.map +1 -0
  98. package/dist/layout/seeded.d.ts +32 -0
  99. package/dist/layout/seeded.js +48 -0
  100. package/dist/layout/seeded.js.map +1 -0
  101. package/dist/layout/types.d.ts +81 -0
  102. package/dist/layout/types.js +14 -0
  103. package/dist/layout/types.js.map +1 -0
  104. package/dist/scene/index.d.ts +6 -0
  105. package/dist/scene/index.js +7 -0
  106. package/dist/scene/index.js.map +1 -0
  107. package/dist/scene/orrery.d.ts +592 -0
  108. package/dist/scene/orrery.js +1555 -0
  109. package/dist/scene/orrery.js.map +1 -0
  110. package/dist/types/encoding.d.ts +43 -0
  111. package/dist/types/encoding.js +7 -0
  112. package/dist/types/encoding.js.map +1 -0
  113. package/dist/types/space.d.ts +12 -0
  114. package/dist/types/space.js +10 -0
  115. package/dist/types/space.js.map +1 -0
  116. package/package.json +57 -0
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @file The ranked layout, declared once.
3
+ *
4
+ * A DAG drawn as the tree it is: every node hangs beneath its anchor parent
5
+ * (a join's extra parents are edges, not placement), a subtree occupies a
6
+ * contiguous span of leaf slots and its root sits over the middle of that
7
+ * span, tiers by depth from the roots. The same graph always lands the same
8
+ * way — sibling order is settled by id, so nothing depends on the order
9
+ * nodes happened to arrive in.
10
+ *
11
+ * This module exists because the layout was written twice. The stage drew a
12
+ * pipeline with the algorithm below; the preview card drew the same
13
+ * pipeline by spreading each tier evenly, and the two agreed on nothing —
14
+ * so a card and the detail it previewed were visibly different graphs. They
15
+ * were not made to differ; they were written separately and could not help
16
+ * it.
17
+ *
18
+ * The output is in LAYOUT UNITS — slot columns and tier rows — not in
19
+ * scene units or pixels. Each renderer scales them for the medium it
20
+ * paints: three.js on the stage, SVG in a card that cannot hold a WebGL
21
+ * context, since a grid of ninety previews would want ninety of them and a
22
+ * browser grants about a dozen.
23
+ *
24
+ * Deliberately dependency-free, so it can be unit tested where the scene
25
+ * itself cannot: three.js will not load under jest.
26
+ *
27
+ * @module
28
+ */
29
+ import { NODE_RADIUS } from './types.js';
30
+ /**
31
+ * Places a graph as ranked tiers.
32
+ *
33
+ * @param nodes - The graph. Parent ids naming absent nodes are ignored, so
34
+ * a partial graph still places.
35
+ * @returns Every node's slot and tier, with the extents to fit them by.
36
+ */
37
+ export function rankedLayout_compute(nodes) {
38
+ const byId = new Map(nodes.map((node) => [node.id, node]));
39
+ // Depth is the longest path from a root, so a join sits below everything
40
+ // it waits for rather than beside its shallowest parent.
41
+ const depths = new Map();
42
+ const depth_find = (node, trail) => {
43
+ const known = depths.get(node.id);
44
+ if (known !== undefined)
45
+ return known;
46
+ if (trail.has(node.id) || node.parentIds.length === 0) {
47
+ depths.set(node.id, 0);
48
+ return 0;
49
+ }
50
+ trail.add(node.id);
51
+ let deepest = 0;
52
+ for (const parentId of node.parentIds) {
53
+ const parent = byId.get(parentId);
54
+ if (parent)
55
+ deepest = Math.max(deepest, depth_find(parent, trail) + 1);
56
+ }
57
+ depths.set(node.id, deepest);
58
+ return deepest;
59
+ };
60
+ for (const node of nodes)
61
+ depth_find(node, new Set());
62
+ // The anchor tree: each node under its first parent present in the graph;
63
+ // anything without one is a root. Sibling order is settled by id so the
64
+ // same graph lands the same way whatever order it arrived in.
65
+ const children = new Map();
66
+ const roots = [];
67
+ const byIdSort = (a, b) => a.id.localeCompare(b.id, undefined, { numeric: true });
68
+ for (const node of nodes) {
69
+ const anchor = node.parentIds.find((id) => byId.has(id));
70
+ if (anchor === undefined) {
71
+ roots.push(node);
72
+ continue;
73
+ }
74
+ const siblings = children.get(anchor) ?? [];
75
+ siblings.push(node);
76
+ children.set(anchor, siblings);
77
+ }
78
+ roots.sort(byIdSort);
79
+ for (const siblings of children.values())
80
+ siblings.sort(byIdSort);
81
+ // Leaf slots: a subtree spans as many slots as it has leaves, and its
82
+ // root sits over the middle of that span. One walk assigns every x.
83
+ const xs = new Map();
84
+ let slot = 0;
85
+ const seen = new Set();
86
+ const place = (node) => {
87
+ seen.add(node.id);
88
+ const kids = (children.get(node.id) ?? [])
89
+ .filter((kid) => !seen.has(kid.id));
90
+ if (kids.length === 0) {
91
+ const x = slot++;
92
+ xs.set(node.id, x);
93
+ return [x, x];
94
+ }
95
+ let first = Number.POSITIVE_INFINITY;
96
+ let last = Number.NEGATIVE_INFINITY;
97
+ for (const kid of kids) {
98
+ const [low, high] = place(kid);
99
+ first = Math.min(first, low);
100
+ last = Math.max(last, high);
101
+ }
102
+ const x = (first + last) / 2;
103
+ xs.set(node.id, x);
104
+ return [first, last];
105
+ };
106
+ for (const root of roots)
107
+ place(root);
108
+ // A cycle leaves nodes the walk never reached; they still land.
109
+ for (const node of nodes)
110
+ if (!xs.has(node.id))
111
+ place(node);
112
+ const tierCount = Math.max(...Array.from(depths.values()), 0) + 1;
113
+ const width = Math.max(slot - 1, 0);
114
+ const placements = nodes.map((node) => ({
115
+ id: node.id,
116
+ x: xs.get(node.id) ?? 0,
117
+ tier: depths.get(node.id) ?? 0,
118
+ }));
119
+ return { placements, width, tierCount };
120
+ }
121
+ /** Distance between tiers, in scene units. */
122
+ const TIER_SPACING = 2.6;
123
+ /** Distance between sibling slots, in scene units. */
124
+ const SIBLING_SPACING = 2.0;
125
+ /**
126
+ * The ranked layout in scene units: tiers down the screen, the graph
127
+ * centred, every node's radius scaled by its metric (uniform when none
128
+ * arrived — a mode pill that changes nothing on screen reads as broken).
129
+ *
130
+ * @param nodes - The graph.
131
+ * @returns Every node's place and radius, in the input's order.
132
+ */
133
+ export function ranked_layout(nodes) {
134
+ const metrics = nodes.map((n) => n.metric ?? 0);
135
+ const metricPeak = Math.max(...metrics, 0);
136
+ const layout = rankedLayout_compute(nodes);
137
+ const slots = new Map(layout.placements.map((placement) => [placement.id, placement]));
138
+ return nodes.map((node) => {
139
+ const at = slots.get(node.id);
140
+ const x = ((at?.x ?? 0) - layout.width / 2) * SIBLING_SPACING;
141
+ const y = ((layout.tierCount - 1) / 2 - (at?.tier ?? 0)) * TIER_SPACING;
142
+ const metric = node.metric ?? 0;
143
+ const scale = metricPeak > 0 ? 0.55 + (metric / metricPeak) * 1.0 : 1;
144
+ const position = [x, y, 0];
145
+ return { id: node.id, position, radius: NODE_RADIUS * scale };
146
+ });
147
+ }
148
+ //# sourceMappingURL=ranked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranked.js","sourceRoot":"","sources":["../../src/layout/ranked.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { LayoutEngine, LayoutNode } from './types.js';
2
+ /**
3
+ * Every registered engine.
4
+ *
5
+ * @returns The engines, in offering order.
6
+ */
7
+ export declare function layoutEngines_list(): ReadonlyArray<LayoutEngine>;
8
+ /**
9
+ * One engine by name.
10
+ *
11
+ * @param id - The engine's id.
12
+ * @returns The engine, or undefined when none is registered by that name.
13
+ */
14
+ export declare function layoutEngine_get(id: string): LayoutEngine | undefined;
15
+ /**
16
+ * What an engine needs that the nodes do not carry: an attribute is missing
17
+ * when no node supplies it.
18
+ *
19
+ * @param engine - The engine.
20
+ * @param nodes - The nodes it would run on.
21
+ * @returns The missing attribute names; empty when the engine can run.
22
+ */
23
+ export declare function layoutNeeds_missing(engine: LayoutEngine, nodes: ReadonlyArray<LayoutNode>): string[];
@@ -0,0 +1,165 @@
1
+ /**
2
+ * @file The layout engines a surface can offer, by name.
3
+ *
4
+ * Every engine keeps the same contract (`LayoutEngine`): a pure function of
5
+ * nodes and physics, answering positions. A LAYOUT block lists what is
6
+ * registered; an engine whose `needs` the surface cannot meet is offered
7
+ * greyed with the reason, never run on missing data.
8
+ *
9
+ * @module
10
+ */
11
+ import { accretion_layout } from './accretion.js';
12
+ import { constellations_layout } from './constellations.js';
13
+ import { galaxy_layout } from './galaxy.js';
14
+ import { hierarchy_layout } from './hierarchy.js';
15
+ import { molecule_layout } from './molecule.js';
16
+ import { ranked_layout } from './ranked.js';
17
+ /** A layout node as the hierarchy engines read it. */
18
+ function hierarchyNode_of(node) {
19
+ const out = { id: node.id, parents: node.parents, radius: node.radius, group: node.group };
20
+ if (node.seed !== undefined)
21
+ out.seed = node.seed;
22
+ if (node.frozen !== undefined)
23
+ out.frozen = node.frozen;
24
+ return out;
25
+ }
26
+ /** A node's metric, when the surface supplied one. */
27
+ function metric_of(node) {
28
+ const metric = node.attrs?.['metric'];
29
+ return typeof metric === 'number' ? metric : undefined;
30
+ }
31
+ /** Positions from a list of places. */
32
+ function positions_of(places) {
33
+ const out = {};
34
+ for (const place of places)
35
+ out[place.id] = place.position;
36
+ return out;
37
+ }
38
+ /** The galaxy: the whole space finds its own rest, from the spokes arrangement. */
39
+ const galaxyEngine = {
40
+ id: 'galaxy',
41
+ label: 'GALAXY',
42
+ needs: [],
43
+ run: (input, progress) => ({ positions: galaxy_layout(input.nodes.map(hierarchyNode_of), input.physics, progress) }),
44
+ };
45
+ /** Spokes: every molecule a spoke from its anchor, its chain pointing out. */
46
+ const spokesEngine = {
47
+ id: 'spokes',
48
+ label: 'SPOKES',
49
+ needs: [],
50
+ run: (input, progress) => ({ positions: hierarchy_layout(input.nodes.map(hierarchyNode_of), input.physics, progress, 'spokes') }),
51
+ };
52
+ /** Clumps: the molecules packed round their anchor. */
53
+ const clumpsEngine = {
54
+ id: 'clumps',
55
+ label: 'CLUMPS',
56
+ needs: [],
57
+ run: (input, progress) => ({ positions: hierarchy_layout(input.nodes.map(hierarchyNode_of), input.physics, progress, 'clumps') }),
58
+ };
59
+ /** Ranked: tiers down the screen, the tree as a schematic. */
60
+ const rankedEngine = {
61
+ id: 'ranked',
62
+ label: 'RANKED',
63
+ needs: [],
64
+ run: (input, progress) => {
65
+ const nodes = input.nodes.map((node) => {
66
+ const out = { id: node.id, parentIds: node.parents };
67
+ const metric = metric_of(node);
68
+ if (metric !== undefined)
69
+ out.metric = metric;
70
+ return out;
71
+ });
72
+ const positions = positions_of(ranked_layout(nodes));
73
+ progress(1);
74
+ return { positions };
75
+ },
76
+ };
77
+ /** Molecule: one graph finding its own shape, sized by its metric. */
78
+ const moleculeEngine = {
79
+ id: 'molecule',
80
+ label: 'MOLECULE',
81
+ needs: [],
82
+ run: (input, progress) => {
83
+ const nodes = input.nodes.map((node) => {
84
+ const out = { id: node.id, parents: node.parents };
85
+ const metric = metric_of(node);
86
+ if (metric !== undefined)
87
+ out.metric = metric;
88
+ return out;
89
+ });
90
+ const seed = new Map();
91
+ const frozen = new Set();
92
+ for (const node of input.nodes) {
93
+ if (node.seed !== undefined)
94
+ seed.set(node.id, node.seed);
95
+ if (node.frozen === true)
96
+ frozen.add(node.id);
97
+ }
98
+ const positions = positions_of(molecule_layout(nodes, 3, seed, input.physics, frozen));
99
+ progress(1);
100
+ return { positions };
101
+ },
102
+ };
103
+ /**
104
+ * Constellations: every plugin a star placed by what runs with what, every
105
+ * feed's stages pulled to their plugins' stars. Needs each stage's plugin.
106
+ */
107
+ const constellationsEngine = {
108
+ id: 'constellations',
109
+ label: 'CONSTELLATIONS',
110
+ needs: ['plugin'],
111
+ run: (input, progress) => ({ positions: constellations_layout(input.nodes, input.physics, progress) }),
112
+ };
113
+ /**
114
+ * Hubs: the galaxy's forces on a space hung from a tree of hubs the surface
115
+ * names (a hub under a hub, feeds under the deepest). The same settle as
116
+ * the galaxy, kept under its own name so a surface remembers each apart.
117
+ */
118
+ const hubsEngine = {
119
+ id: 'hubs',
120
+ label: 'HUBS',
121
+ needs: [],
122
+ run: (input, progress) => ({ positions: galaxy_layout(input.nodes.map(hierarchyNode_of), input.physics, progress) }),
123
+ };
124
+ /**
125
+ * Accretion: feeds arrive oldest first and wander until they stick, to kin
126
+ * more readily than to strangers — the space grown as a coral. Needs each
127
+ * stage's plugin; a feed's creation time orders the growth when supplied.
128
+ */
129
+ const accretionEngine = {
130
+ id: 'accretion',
131
+ label: 'ACCRETION',
132
+ needs: ['plugin'],
133
+ run: (input, progress) => accretion_layout(input.nodes, input.physics, progress),
134
+ };
135
+ /** Every engine, in the order a LAYOUT block offers them. */
136
+ const ENGINES = [galaxyEngine, spokesEngine, clumpsEngine, constellationsEngine, hubsEngine, accretionEngine, rankedEngine, moleculeEngine];
137
+ /**
138
+ * Every registered engine.
139
+ *
140
+ * @returns The engines, in offering order.
141
+ */
142
+ export function layoutEngines_list() {
143
+ return ENGINES;
144
+ }
145
+ /**
146
+ * One engine by name.
147
+ *
148
+ * @param id - The engine's id.
149
+ * @returns The engine, or undefined when none is registered by that name.
150
+ */
151
+ export function layoutEngine_get(id) {
152
+ return ENGINES.find((engine) => engine.id === id);
153
+ }
154
+ /**
155
+ * What an engine needs that the nodes do not carry: an attribute is missing
156
+ * when no node supplies it.
157
+ *
158
+ * @param engine - The engine.
159
+ * @param nodes - The nodes it would run on.
160
+ * @returns The missing attribute names; empty when the engine can run.
161
+ */
162
+ export function layoutNeeds_missing(engine, nodes) {
163
+ return engine.needs.filter((need) => !nodes.some((node) => node.attrs?.[need] !== undefined));
164
+ }
165
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/layout/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @file Chance that comes out the same every time.
3
+ *
4
+ * A layout that turns each molecule at random, so like feeds do not stand
5
+ * as clones, still owes the operator the same space on every device and
6
+ * every visit. The turn is seeded by the molecule itself — a hash of its
7
+ * key — so it is fixed for that molecule, and a molecule arriving later
8
+ * turns no other.
9
+ *
10
+ * @module
11
+ */
12
+ /**
13
+ * A 32-bit FNV-1a hash of a string.
14
+ *
15
+ * @param text - What to hash.
16
+ * @returns The hash, an unsigned 32-bit integer.
17
+ */
18
+ export declare function hash_of(text: string): number;
19
+ /**
20
+ * A seeded source of numbers in [0, 1): a linear congruential generator.
21
+ *
22
+ * @param seed - The seed.
23
+ * @returns The next number each time it is called.
24
+ */
25
+ export declare function random_seeded(seed: number): () => number;
26
+ /**
27
+ * The source a molecule draws its chance from: seeded by its own key.
28
+ *
29
+ * @param key - The molecule's key (its group).
30
+ * @returns A source that runs the same way every time for that key.
31
+ */
32
+ export declare function randomFor_key(key: string): () => number;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @file Chance that comes out the same every time.
3
+ *
4
+ * A layout that turns each molecule at random, so like feeds do not stand
5
+ * as clones, still owes the operator the same space on every device and
6
+ * every visit. The turn is seeded by the molecule itself — a hash of its
7
+ * key — so it is fixed for that molecule, and a molecule arriving later
8
+ * turns no other.
9
+ *
10
+ * @module
11
+ */
12
+ /**
13
+ * A 32-bit FNV-1a hash of a string.
14
+ *
15
+ * @param text - What to hash.
16
+ * @returns The hash, an unsigned 32-bit integer.
17
+ */
18
+ export function hash_of(text) {
19
+ let hash = 0x811c9dc5;
20
+ for (let i = 0; i < text.length; i++) {
21
+ hash ^= text.charCodeAt(i);
22
+ hash = Math.imul(hash, 0x01000193);
23
+ }
24
+ return hash >>> 0;
25
+ }
26
+ /**
27
+ * A seeded source of numbers in [0, 1): a linear congruential generator.
28
+ *
29
+ * @param seed - The seed.
30
+ * @returns The next number each time it is called.
31
+ */
32
+ export function random_seeded(seed) {
33
+ let state = seed >>> 0;
34
+ return () => {
35
+ state = (Math.imul(state, 1664525) + 1013904223) >>> 0;
36
+ return state / 4294967296;
37
+ };
38
+ }
39
+ /**
40
+ * The source a molecule draws its chance from: seeded by its own key.
41
+ *
42
+ * @param key - The molecule's key (its group).
43
+ * @returns A source that runs the same way every time for that key.
44
+ */
45
+ export function randomFor_key(key) {
46
+ return random_seeded(hash_of(key));
47
+ }
48
+ //# sourceMappingURL=seeded.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seeded.js","sourceRoot":"","sources":["../../src/layout/seeded.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,IAAI,IAAI,GAAW,UAAU,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,KAAK,GAAW,IAAI,KAAK,CAAC,CAAC;IAC/B,OAAO,GAAW,EAAE;QAClB,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QACvD,OAAO,KAAK,GAAG,UAAU,CAAC;IAC5B,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @file The layout layer's vocabulary: a point in the space, the physics a
3
+ * settle honours, and the contract every layout engine keeps.
4
+ *
5
+ * Nothing here knows what a node stands for. A surface translates its own
6
+ * domain into these shapes; an engine answers with positions.
7
+ *
8
+ * @module
9
+ */
10
+ import type { Positions, Vec3 } from '../types/space.js';
11
+ export type { Positions, Vec3 };
12
+ /**
13
+ * The terms a settle honours.
14
+ *
15
+ * @property charge - Nodes repel, heavier ones harder.
16
+ * @property link - An edge holds its ends at the sum of their radii.
17
+ * @property collide - Nodes do not overlap.
18
+ * @property gravity - A mass-weighted pull to the centre.
19
+ * @property reach - How far a node's repulsion carries; unbounded when
20
+ * absent. A sparse graph settles as wide as its charge carries, so a
21
+ * bounded reach lets a small molecule hug itself while a crowd spreads.
22
+ */
23
+ export interface PhysicsTerms {
24
+ charge: boolean;
25
+ link: boolean;
26
+ collide: boolean;
27
+ gravity: boolean;
28
+ reach?: number;
29
+ }
30
+ /** The terms a settle takes when nobody says otherwise. */
31
+ export declare const PHYSICS_DEFAULT: PhysicsTerms;
32
+ /** The radius a node's size is scaled against. */
33
+ export declare const NODE_RADIUS: number;
34
+ /**
35
+ * One node an engine places.
36
+ *
37
+ * @property id - Its id.
38
+ * @property parents - Its parents' ids, joins included.
39
+ * @property radius - The room it takes.
40
+ * @property group - The molecule it belongs to, or null for a node that
41
+ * stands alone (an anchor).
42
+ * @property seed - Where it stood last, if anywhere.
43
+ * @property frozen - Holds still at its seed.
44
+ * @property attrs - What an engine that `needs` more reads: plugins, data
45
+ * kind, creation time — whatever the surface supplied.
46
+ */
47
+ export interface LayoutNode {
48
+ id: string;
49
+ parents: string[];
50
+ radius: number;
51
+ group: string | null;
52
+ seed?: Vec3;
53
+ frozen?: boolean;
54
+ attrs?: Record<string, number | string | string[]>;
55
+ }
56
+ /** What an engine is given. */
57
+ export interface LayoutInput {
58
+ nodes: LayoutNode[];
59
+ physics: PhysicsTerms;
60
+ }
61
+ /** What an engine answers: every node's place, and optionally when each arrived. */
62
+ export interface LayoutResult {
63
+ positions: Positions;
64
+ /** The moment each node joined, for a replay; absent for a layout with no history. */
65
+ arrival?: Record<string, number>;
66
+ }
67
+ /**
68
+ * A layout engine: a pure function of its input, run off the page.
69
+ *
70
+ * @property id - Its name on the LAYOUT block and in `layout <id>`.
71
+ * @property label - What the block shows.
72
+ * @property needs - Node attributes it reads; an engine whose needs the
73
+ * surface cannot meet is offered greyed, with the reason, never run.
74
+ * @property run - Places every node, telling `progress` how far it has come.
75
+ */
76
+ export interface LayoutEngine {
77
+ id: string;
78
+ label: string;
79
+ needs: ReadonlyArray<string>;
80
+ run(input: LayoutInput, progress: (fraction: number) => void): LayoutResult;
81
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @file The layout layer's vocabulary: a point in the space, the physics a
3
+ * settle honours, and the contract every layout engine keeps.
4
+ *
5
+ * Nothing here knows what a node stands for. A surface translates its own
6
+ * domain into these shapes; an engine answers with positions.
7
+ *
8
+ * @module
9
+ */
10
+ /** The terms a settle takes when nobody says otherwise. */
11
+ export const PHYSICS_DEFAULT = { charge: true, link: true, collide: true, gravity: false };
12
+ /** The radius a node's size is scaled against. */
13
+ export const NODE_RADIUS = 0.55;
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/layout/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAEzG,kDAAkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAW,IAAI,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @file The scene's public face: the orrery a surface mounts.
3
+ *
4
+ * @module
5
+ */
6
+ export * from './orrery.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @file The scene's public face: the orrery a surface mounts.
3
+ *
4
+ * @module
5
+ */
6
+ export * from './orrery.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scene/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,aAAa,CAAC"}