@graphty/webgpu-graph-algorithms 0.0.0 → 0.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 (269) hide show
  1. package/README.md +344 -23
  2. package/dist/browser.d.ts +1 -0
  3. package/dist/browser.js +32 -0
  4. package/dist/browser.js.map +1 -0
  5. package/dist/chunks/context-E6iKaeuJ.js +3136 -0
  6. package/dist/chunks/context-E6iKaeuJ.js.map +1 -0
  7. package/dist/node.d.ts +1 -0
  8. package/dist/node.js +131 -0
  9. package/dist/node.js.map +1 -0
  10. package/dist/src/accelerator.d.ts +26 -0
  11. package/dist/src/accelerator.d.ts.map +1 -0
  12. package/dist/src/accelerator.js +101 -0
  13. package/dist/src/accelerator.js.map +1 -0
  14. package/dist/src/algorithms/degree.d.ts +35 -0
  15. package/dist/src/algorithms/degree.d.ts.map +1 -0
  16. package/dist/src/algorithms/degree.js +119 -0
  17. package/dist/src/algorithms/degree.js.map +1 -0
  18. package/dist/src/browser/index.d.ts +23 -0
  19. package/dist/src/browser/index.d.ts.map +1 -0
  20. package/dist/src/browser/index.js +48 -0
  21. package/dist/src/browser/index.js.map +1 -0
  22. package/dist/src/constants.d.ts +92 -0
  23. package/dist/src/constants.d.ts.map +1 -0
  24. package/dist/src/constants.js +92 -0
  25. package/dist/src/constants.js.map +1 -0
  26. package/dist/src/context.d.ts +84 -0
  27. package/dist/src/context.d.ts.map +1 -0
  28. package/dist/src/context.js +304 -0
  29. package/dist/src/context.js.map +1 -0
  30. package/dist/src/device/acquire.d.ts +57 -0
  31. package/dist/src/device/acquire.d.ts.map +1 -0
  32. package/dist/src/device/acquire.js +232 -0
  33. package/dist/src/device/acquire.js.map +1 -0
  34. package/dist/src/device/caps.d.ts +43 -0
  35. package/dist/src/device/caps.d.ts.map +1 -0
  36. package/dist/src/device/caps.js +104 -0
  37. package/dist/src/device/caps.js.map +1 -0
  38. package/dist/src/device/error-scope.d.ts +75 -0
  39. package/dist/src/device/error-scope.d.ts.map +1 -0
  40. package/dist/src/device/error-scope.js +152 -0
  41. package/dist/src/device/error-scope.js.map +1 -0
  42. package/dist/src/device/lost.d.ts +51 -0
  43. package/dist/src/device/lost.d.ts.map +1 -0
  44. package/dist/src/device/lost.js +130 -0
  45. package/dist/src/device/lost.js.map +1 -0
  46. package/dist/src/device/webgpu-constants.d.ts +31 -0
  47. package/dist/src/device/webgpu-constants.d.ts.map +1 -0
  48. package/dist/src/device/webgpu-constants.js +31 -0
  49. package/dist/src/device/webgpu-constants.js.map +1 -0
  50. package/dist/src/errors.d.ts +56 -0
  51. package/dist/src/errors.d.ts.map +1 -0
  52. package/dist/src/errors.js +57 -0
  53. package/dist/src/errors.js.map +1 -0
  54. package/dist/src/index.d.ts +29 -0
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +27 -0
  57. package/dist/src/index.js.map +1 -0
  58. package/dist/src/kernel/batch.d.ts +116 -0
  59. package/dist/src/kernel/batch.d.ts.map +1 -0
  60. package/dist/src/kernel/batch.js +335 -0
  61. package/dist/src/kernel/batch.js.map +1 -0
  62. package/dist/src/kernel/dispatch.d.ts +59 -0
  63. package/dist/src/kernel/dispatch.d.ts.map +1 -0
  64. package/dist/src/kernel/dispatch.js +139 -0
  65. package/dist/src/kernel/dispatch.js.map +1 -0
  66. package/dist/src/kernel/kernel.d.ts +84 -0
  67. package/dist/src/kernel/kernel.d.ts.map +1 -0
  68. package/dist/src/kernel/kernel.js +239 -0
  69. package/dist/src/kernel/kernel.js.map +1 -0
  70. package/dist/src/kernel/pipeline-cache.d.ts +90 -0
  71. package/dist/src/kernel/pipeline-cache.d.ts.map +1 -0
  72. package/dist/src/kernel/pipeline-cache.js +251 -0
  73. package/dist/src/kernel/pipeline-cache.js.map +1 -0
  74. package/dist/src/kernel/prelude.d.ts +35 -0
  75. package/dist/src/kernel/prelude.d.ts.map +1 -0
  76. package/dist/src/kernel/prelude.js +211 -0
  77. package/dist/src/kernel/prelude.js.map +1 -0
  78. package/dist/src/kernel/profiler.d.ts +64 -0
  79. package/dist/src/kernel/profiler.d.ts.map +1 -0
  80. package/dist/src/kernel/profiler.js +120 -0
  81. package/dist/src/kernel/profiler.js.map +1 -0
  82. package/dist/src/kernel/struct-block.d.ts +122 -0
  83. package/dist/src/kernel/struct-block.d.ts.map +1 -0
  84. package/dist/src/kernel/struct-block.js +353 -0
  85. package/dist/src/kernel/struct-block.js.map +1 -0
  86. package/dist/src/kernel/uniform-ring.d.ts +70 -0
  87. package/dist/src/kernel/uniform-ring.d.ts.map +1 -0
  88. package/dist/src/kernel/uniform-ring.js +146 -0
  89. package/dist/src/kernel/uniform-ring.js.map +1 -0
  90. package/dist/src/kernel/wgsl.d.ts +88 -0
  91. package/dist/src/kernel/wgsl.d.ts.map +1 -0
  92. package/dist/src/kernel/wgsl.js +390 -0
  93. package/dist/src/kernel/wgsl.js.map +1 -0
  94. package/dist/src/kernels.d.ts +81 -0
  95. package/dist/src/kernels.d.ts.map +1 -0
  96. package/dist/src/kernels.js +417 -0
  97. package/dist/src/kernels.js.map +1 -0
  98. package/dist/src/layouts/force-simulation.d.ts +498 -0
  99. package/dist/src/layouts/force-simulation.d.ts.map +1 -0
  100. package/dist/src/layouts/force-simulation.js +1650 -0
  101. package/dist/src/layouts/force-simulation.js.map +1 -0
  102. package/dist/src/layouts/forceatlas2.d.ts +210 -0
  103. package/dist/src/layouts/forceatlas2.d.ts.map +1 -0
  104. package/dist/src/layouts/forceatlas2.js +759 -0
  105. package/dist/src/layouts/forceatlas2.js.map +1 -0
  106. package/dist/src/layouts/inputs.d.ts +40 -0
  107. package/dist/src/layouts/inputs.d.ts.map +1 -0
  108. package/dist/src/layouts/inputs.js +185 -0
  109. package/dist/src/layouts/inputs.js.map +1 -0
  110. package/dist/src/layouts/repulsion-exact.d.ts +85 -0
  111. package/dist/src/layouts/repulsion-exact.d.ts.map +1 -0
  112. package/dist/src/layouts/repulsion-exact.js +134 -0
  113. package/dist/src/layouts/repulsion-exact.js.map +1 -0
  114. package/dist/src/layouts/seed.d.ts +56 -0
  115. package/dist/src/layouts/seed.d.ts.map +1 -0
  116. package/dist/src/layouts/seed.js +173 -0
  117. package/dist/src/layouts/seed.js.map +1 -0
  118. package/dist/src/memory/buffer-pool.d.ts +73 -0
  119. package/dist/src/memory/buffer-pool.d.ts.map +1 -0
  120. package/dist/src/memory/buffer-pool.js +170 -0
  121. package/dist/src/memory/buffer-pool.js.map +1 -0
  122. package/dist/src/memory/lease.d.ts +53 -0
  123. package/dist/src/memory/lease.d.ts.map +1 -0
  124. package/dist/src/memory/lease.js +85 -0
  125. package/dist/src/memory/lease.js.map +1 -0
  126. package/dist/src/memory/readback.d.ts +143 -0
  127. package/dist/src/memory/readback.d.ts.map +1 -0
  128. package/dist/src/memory/readback.js +375 -0
  129. package/dist/src/memory/readback.js.map +1 -0
  130. package/dist/src/memory/residency.d.ts +83 -0
  131. package/dist/src/memory/residency.d.ts.map +1 -0
  132. package/dist/src/memory/residency.js +573 -0
  133. package/dist/src/memory/residency.js.map +1 -0
  134. package/dist/src/memory/upload-plan.d.ts +101 -0
  135. package/dist/src/memory/upload-plan.d.ts.map +1 -0
  136. package/dist/src/memory/upload-plan.js +265 -0
  137. package/dist/src/memory/upload-plan.js.map +1 -0
  138. package/dist/src/node/index.d.ts +64 -0
  139. package/dist/src/node/index.d.ts.map +1 -0
  140. package/dist/src/node/index.js +183 -0
  141. package/dist/src/node/index.js.map +1 -0
  142. package/dist/src/primitives/reduce.d.ts +57 -0
  143. package/dist/src/primitives/reduce.d.ts.map +1 -0
  144. package/dist/src/primitives/reduce.js +161 -0
  145. package/dist/src/primitives/reduce.js.map +1 -0
  146. package/dist/src/primitives/segmented-reduce.d.ts +38 -0
  147. package/dist/src/primitives/segmented-reduce.d.ts.map +1 -0
  148. package/dist/src/primitives/segmented-reduce.js +211 -0
  149. package/dist/src/primitives/segmented-reduce.js.map +1 -0
  150. package/dist/src/types/accelerator.d.ts +209 -0
  151. package/dist/src/types/accelerator.d.ts.map +1 -0
  152. package/dist/src/types/accelerator.js +8 -0
  153. package/dist/src/types/accelerator.js.map +1 -0
  154. package/dist/src/types/context.d.ts +114 -0
  155. package/dist/src/types/context.d.ts.map +1 -0
  156. package/dist/src/types/context.js +7 -0
  157. package/dist/src/types/context.js.map +1 -0
  158. package/dist/src/types/layout.d.ts +95 -0
  159. package/dist/src/types/layout.d.ts.map +1 -0
  160. package/dist/src/types/layout.js +6 -0
  161. package/dist/src/types/layout.js.map +1 -0
  162. package/dist/src/types/memory.d.ts +22 -0
  163. package/dist/src/types/memory.d.ts.map +1 -0
  164. package/dist/src/types/memory.js +7 -0
  165. package/dist/src/types/memory.js.map +1 -0
  166. package/dist/src/types/options.d.ts +78 -0
  167. package/dist/src/types/options.d.ts.map +1 -0
  168. package/dist/src/types/options.js +7 -0
  169. package/dist/src/types/options.js.map +1 -0
  170. package/dist/src/types/run.d.ts +13 -0
  171. package/dist/src/types/run.d.ts.map +1 -0
  172. package/dist/src/types/run.js +6 -0
  173. package/dist/src/types/run.js.map +1 -0
  174. package/dist/src/wgsl/degree.wgsl.d.ts +10 -0
  175. package/dist/src/wgsl/degree.wgsl.d.ts.map +1 -0
  176. package/dist/src/wgsl/degree.wgsl.js +25 -0
  177. package/dist/src/wgsl/degree.wgsl.js.map +1 -0
  178. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +12 -0
  179. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -0
  180. package/dist/src/wgsl/fa2-attraction.wgsl.js +37 -0
  181. package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -0
  182. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +13 -0
  183. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -0
  184. package/dist/src/wgsl/fa2-integrate.wgsl.js +69 -0
  185. package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -0
  186. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +12 -0
  187. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -0
  188. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +79 -0
  189. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -0
  190. package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts +15 -0
  191. package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts.map +1 -0
  192. package/dist/src/wgsl/fa2-speed-finalize.wgsl.js +54 -0
  193. package/dist/src/wgsl/fa2-speed-finalize.wgsl.js.map +1 -0
  194. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +14 -0
  195. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -0
  196. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +57 -0
  197. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -0
  198. package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts +11 -0
  199. package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts.map +1 -0
  200. package/dist/src/wgsl/fa2-to-scene.wgsl.js +19 -0
  201. package/dist/src/wgsl/fa2-to-scene.wgsl.js.map +1 -0
  202. package/dist/src/wgsl/fill.wgsl.d.ts +7 -0
  203. package/dist/src/wgsl/fill.wgsl.d.ts.map +1 -0
  204. package/dist/src/wgsl/fill.wgsl.js +14 -0
  205. package/dist/src/wgsl/fill.wgsl.js.map +1 -0
  206. package/dist/src/wgsl/reduce.wgsl.d.ts +10 -0
  207. package/dist/src/wgsl/reduce.wgsl.d.ts.map +1 -0
  208. package/dist/src/wgsl/reduce.wgsl.js +63 -0
  209. package/dist/src/wgsl/reduce.wgsl.js.map +1 -0
  210. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +13 -0
  211. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -0
  212. package/dist/src/wgsl/segmented-reduce.wgsl.js +35 -0
  213. package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -0
  214. package/dist/tsconfig.build.tsbuildinfo +1 -0
  215. package/dist/webgpu-graph-algorithms.d.ts +1 -0
  216. package/dist/webgpu-graph-algorithms.js +4454 -0
  217. package/dist/webgpu-graph-algorithms.js.map +1 -0
  218. package/package.json +108 -17
  219. package/src/accelerator.ts +117 -0
  220. package/src/algorithms/degree.ts +142 -0
  221. package/src/browser/index.ts +57 -0
  222. package/src/constants.ts +116 -0
  223. package/src/context.ts +399 -0
  224. package/src/device/acquire.ts +256 -0
  225. package/src/device/caps.ts +122 -0
  226. package/src/device/error-scope.ts +171 -0
  227. package/src/device/lost.ts +142 -0
  228. package/src/device/webgpu-constants.ts +44 -0
  229. package/src/errors.ts +94 -0
  230. package/src/index.ts +102 -0
  231. package/src/kernel/batch.ts +427 -0
  232. package/src/kernel/dispatch.ts +162 -0
  233. package/src/kernel/kernel.ts +311 -0
  234. package/src/kernel/pipeline-cache.ts +288 -0
  235. package/src/kernel/prelude.ts +229 -0
  236. package/src/kernel/profiler.ts +148 -0
  237. package/src/kernel/struct-block.ts +439 -0
  238. package/src/kernel/uniform-ring.ts +184 -0
  239. package/src/kernel/wgsl.ts +490 -0
  240. package/src/kernels.ts +511 -0
  241. package/src/layouts/force-simulation.ts +2111 -0
  242. package/src/layouts/forceatlas2.ts +942 -0
  243. package/src/layouts/inputs.ts +252 -0
  244. package/src/layouts/repulsion-exact.ts +183 -0
  245. package/src/layouts/seed.ts +198 -0
  246. package/src/memory/buffer-pool.ts +204 -0
  247. package/src/memory/lease.ts +93 -0
  248. package/src/memory/readback.ts +429 -0
  249. package/src/memory/residency.ts +753 -0
  250. package/src/memory/upload-plan.ts +350 -0
  251. package/src/node/index.ts +230 -0
  252. package/src/primitives/reduce.ts +233 -0
  253. package/src/primitives/segmented-reduce.ts +270 -0
  254. package/src/types/accelerator.ts +236 -0
  255. package/src/types/context.ts +135 -0
  256. package/src/types/layout.ts +103 -0
  257. package/src/types/memory.ts +23 -0
  258. package/src/types/options.ts +84 -0
  259. package/src/types/run.ts +13 -0
  260. package/src/wgsl/degree.wgsl.ts +24 -0
  261. package/src/wgsl/fa2-attraction.wgsl.ts +37 -0
  262. package/src/wgsl/fa2-integrate.wgsl.ts +69 -0
  263. package/src/wgsl/fa2-repulsion-exact.wgsl.ts +78 -0
  264. package/src/wgsl/fa2-speed-finalize.wgsl.ts +53 -0
  265. package/src/wgsl/fa2-stats-finalize.wgsl.ts +57 -0
  266. package/src/wgsl/fa2-to-scene.wgsl.ts +19 -0
  267. package/src/wgsl/fill.wgsl.ts +13 -0
  268. package/src/wgsl/reduce.wgsl.ts +62 -0
  269. package/src/wgsl/segmented-reduce.wgsl.ts +35 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Capability capture (spec 2.2 step 4, 3.3, 5.1, 5.2; contract 3.4): the GpuCaps record of a DEVICE (its
3
+ * limits and features, never the adapter's), the zero-cost variant for an adopted device, the two planner
4
+ * facts asserted at create(), and the workgroup size a device runs.
5
+ */
6
+
7
+ import { MAX_WORKGROUPS_PER_DIM, WORKGROUP_SIZE } from "../constants.js";
8
+ import { WebGpuGraphError } from "../errors.js";
9
+ import type { AdapterInfoLike, GpuCaps, PlanCaps } from "../types/context.js";
10
+ import { isSoftwareAdapter } from "./acquire.js";
11
+
12
+ /**
13
+ * Step 4 of create(): the GpuCaps of a DEVICE (device.limits, never adapter.limits) with the adapter info
14
+ * and the runtime tag. The subgroup sizes are the adapter's only when the device has the "subgroups"
15
+ * feature, else 0 (spec 3.3).
16
+ * @param device - the device the caps describe
17
+ * @param info - the adapter's info (vendor, architecture, subgroup sizes)
18
+ * @param runtime - the tag the creating entry sets ("unknown" for consumers of the core)
19
+ * @param wgslFeatures - navigator.gpu.wgslLanguageFeatures or the Dawn equivalent (informational)
20
+ * @returns the capability record
21
+ */
22
+ export function captureCaps(
23
+ device: GPUDevice,
24
+ info: AdapterInfoLike,
25
+ runtime: "browser" | "node" | "unknown",
26
+ wgslFeatures: Iterable<string>,
27
+ ): GpuCaps {
28
+ const features: ReadonlySet<string> = new Set(device.features);
29
+ const subgroups = features.has("subgroups");
30
+ return {
31
+ limits: device.limits,
32
+ features,
33
+ wgslFeatures: new Set(wgslFeatures),
34
+ subgroupMinSize: subgroups ? (info.subgroupMinSize ?? 0) : 0,
35
+ subgroupMaxSize: subgroups ? (info.subgroupMaxSize ?? 0) : 0,
36
+ software: isSoftwareAdapter(info),
37
+ runtime,
38
+ vendor: info.vendor,
39
+ architecture: info.architecture,
40
+ device: info.device,
41
+ description: info.description,
42
+ };
43
+ }
44
+
45
+ /**
46
+ * GpuContext.from(device, info?): caps from device.limits / device.features and the partial info given;
47
+ * software false and runtime "unknown" unless given; the subgroup sizes are honoured only when the device
48
+ * has the feature.
49
+ * @param device - the adopted device
50
+ * @param info - what the caller knows about the adapter, if anything
51
+ * @returns the capability record
52
+ */
53
+ export function capsFromDevice(device: GPUDevice, info: Partial<GpuCaps> | undefined): GpuCaps {
54
+ const features: ReadonlySet<string> = new Set(device.features);
55
+ const subgroups = features.has("subgroups");
56
+ return {
57
+ limits: device.limits,
58
+ features,
59
+ wgslFeatures: info?.wgslFeatures ?? new Set<string>(),
60
+ subgroupMinSize: subgroups ? (info?.subgroupMinSize ?? 0) : 0,
61
+ subgroupMaxSize: subgroups ? (info?.subgroupMaxSize ?? 0) : 0,
62
+ software: info?.software ?? false,
63
+ runtime: info?.runtime ?? "unknown",
64
+ vendor: info?.vendor ?? "",
65
+ architecture: info?.architecture ?? "",
66
+ device: info?.device ?? "",
67
+ description: info?.description ?? "",
68
+ };
69
+ }
70
+
71
+ /**
72
+ * The workgroup size a device runs: min(WORKGROUP_SIZE, caps.limits.maxComputeInvocationsPerWorkgroup) rounded
73
+ * down to a power of two (spec 5.1; the formula of contract 3.2 / 3.4). maxComputeWorkgroupSizeX is not a term:
74
+ * every adapter supports its 256 default (WebGPU 3.6.2), so the result never exceeds it. Rounds down by doubling
75
+ * (no bitwise operator).
76
+ * @param caps - the capability record (a GpuCaps is a PlanCaps)
77
+ * @returns the workgroup size
78
+ */
79
+ export function workgroupSizeFor(caps: PlanCaps): number {
80
+ const cap = Math.min(WORKGROUP_SIZE, caps.limits.maxComputeInvocationsPerWorkgroup);
81
+ let size = 1;
82
+ while (size * 2 <= cap) {
83
+ size *= 2;
84
+ }
85
+ return size;
86
+ }
87
+
88
+ /**
89
+ * Asserts the two facts the planners bake in: maxComputeWorkgroupsPerDimension === MAX_WORKGROUPS_PER_DIM
90
+ * (the prelude's linear_id and plan1d / plan2d use the constant) and WG is a power of two >= 64 (spec 2.2,
91
+ * 5.2). The limit is never requested, so a device reports the spec default whatever its adapter says.
92
+ * @param caps - the capability record of the device
93
+ */
94
+ export function assertPlanLimits(caps: GpuCaps): void {
95
+ const perDim = caps.limits.maxComputeWorkgroupsPerDimension;
96
+ if (perDim !== MAX_WORKGROUPS_PER_DIM) {
97
+ throw new WebGpuGraphError(
98
+ "E_NO_DEVICE",
99
+ `maxComputeWorkgroupsPerDimension is ${perDim}; the dispatch planner and the WGSL prelude bake ${MAX_WORKGROUPS_PER_DIM}`,
100
+ {
101
+ reason: "maxComputeWorkgroupsPerDimension",
102
+ adapter: null,
103
+ requested: MAX_WORKGROUPS_PER_DIM,
104
+ available: perDim,
105
+ },
106
+ );
107
+ }
108
+ const wg = workgroupSizeFor(caps);
109
+ if (wg < 64) {
110
+ throw new WebGpuGraphError(
111
+ "E_NO_DEVICE",
112
+ `the device allows a workgroup of ${wg} invocations; the kernels need a power of two >= 64`,
113
+ {
114
+ reason: "limit",
115
+ adapter: null,
116
+ limit: "maxComputeInvocationsPerWorkgroup",
117
+ requested: 64,
118
+ available: wg,
119
+ },
120
+ );
121
+ }
122
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Error scopes (spec 5.7; contract 3.4): a validation scope that turns a captured GPUValidationError into
3
+ * E_VALIDATION { label, message }, the compilation-info formatter with body-relative line numbers, and the
4
+ * AllocationTracker that wraps large createBuffer calls in an out-of-memory scope and keeps the resident-byte
5
+ * bookkeeping the residency, the pool and the staging ring share (it is owned by the context).
6
+ */
7
+
8
+ import { OOM_SCOPE_THRESHOLD_BYTES } from "../constants.js";
9
+ import { WebGpuGraphError } from "../errors.js";
10
+
11
+ /**
12
+ * Runs `fn` inside pushErrorScope("validation"); a captured error becomes E_VALIDATION { label, message }
13
+ * thrown from the returned promise (spec 5.7). An error `fn` itself throws is rethrown unchanged after the
14
+ * scope is popped, so the device's scope stack stays balanced.
15
+ * @param device - the device
16
+ * @param label - names the operation in the error (every object the package creates is labelled)
17
+ * @param fn - the work; may return a promise
18
+ * @returns the value of `fn`
19
+ */
20
+ export async function withValidationScope<T>(device: GPUDevice, label: string, fn: () => Promise<T> | T): Promise<T> {
21
+ device.pushErrorScope("validation");
22
+ let result: T;
23
+ try {
24
+ result = await fn();
25
+ } catch (err) {
26
+ await device.popErrorScope().catch(() => null);
27
+ throw err;
28
+ }
29
+ const error = await device.popErrorScope();
30
+ if (error !== null) {
31
+ throw new WebGpuGraphError("E_VALIDATION", `${label}: ${error.message}`, { label, message: error.message });
32
+ }
33
+ return result;
34
+ }
35
+
36
+ /**
37
+ * Formats GPUCompilationInfo messages with line numbers relative to the kernel BODY: `preludeLines` (the
38
+ * lines the composer emitted before the body) is subtracted, a message located inside those lines is
39
+ * reported as `prelude:<line>`, and a message without a location (lineNum 0) carries no position (spec 5.1).
40
+ * @param info - the compilation info of the shader module
41
+ * @param preludeLines - the number of emitted lines before the body's first line
42
+ * @returns one string per message: `<type> <line>:<column> <message>`
43
+ */
44
+ export function formatCompilationInfo(info: GPUCompilationInfo, preludeLines: number): string[] {
45
+ return info.messages.map((m) => {
46
+ if (m.lineNum === 0) {
47
+ return `${m.type} ${m.message}`;
48
+ }
49
+ const line = m.lineNum - preludeLines;
50
+ if (line >= 1) {
51
+ return `${m.type} ${line}:${m.linePos} ${m.message}`;
52
+ }
53
+ return `${m.type} prelude:${m.lineNum}:${m.linePos} ${m.message}`;
54
+ });
55
+ }
56
+
57
+ /**
58
+ * Creates buffers, wrapping sizes >= OOM_SCOPE_THRESHOLD_BYTES in an "out-of-memory" scope whose pop is
59
+ * collected; `check()` surfaces the first OOM (spec 4.4, 5.7). Owned by the context, shared by the
60
+ * residency and the pool.
61
+ */
62
+ export class AllocationTracker {
63
+ private readonly device: GPUDevice;
64
+ private readonly threshold: number;
65
+ private readonly live = new Map<GPUBuffer, number>();
66
+ private residentBytes = 0;
67
+ private pending: Promise<void>[] = [];
68
+ private failure: WebGpuGraphError | null = null;
69
+ private serial = 0;
70
+
71
+ /**
72
+ * Creates a tracker over one device.
73
+ * @param device - the device buffers are created on
74
+ * @param thresholdBytes - the byte size from which createBuffer runs inside an out-of-memory scope (default OOM_SCOPE_THRESHOLD_BYTES)
75
+ */
76
+ constructor(device: GPUDevice, thresholdBytes?: number) {
77
+ this.device = device;
78
+ this.threshold = thresholdBytes ?? OOM_SCOPE_THRESHOLD_BYTES;
79
+ }
80
+
81
+ /**
82
+ * createBuffer with the scope rule; every buffer is labelled (an unlabelled descriptor becomes `buffer-<n>`).
83
+ * @param descriptor - the buffer descriptor
84
+ * @returns the buffer
85
+ */
86
+ createBuffer(descriptor: GPUBufferDescriptor): GPUBuffer {
87
+ this.serial += 1;
88
+ const label =
89
+ descriptor.label === undefined || descriptor.label === "" ? `buffer-${this.serial}` : descriptor.label;
90
+ const { size } = descriptor;
91
+ const scoped = size >= this.threshold;
92
+ if (scoped) {
93
+ this.device.pushErrorScope("out-of-memory");
94
+ }
95
+ const buffer = this.device.createBuffer({ ...descriptor, label });
96
+ this.live.set(buffer, size);
97
+ this.residentBytes += size;
98
+ if (scoped) {
99
+ const pop = this.device.popErrorScope().then(
100
+ (error) => {
101
+ if (error === null) {
102
+ return;
103
+ }
104
+ if (this.live.has(buffer)) {
105
+ this.live.delete(buffer);
106
+ this.residentBytes -= size;
107
+ }
108
+ if (this.failure === null) {
109
+ this.failure = new WebGpuGraphError(
110
+ "E_OUT_OF_MEMORY",
111
+ `out of memory creating "${label}" (${size} bytes, ${this.residentBytes} resident): ${error.message}`,
112
+ { requested: size, resident: this.residentBytes, label },
113
+ );
114
+ }
115
+ },
116
+ () => undefined,
117
+ );
118
+ this.pending.push(pop);
119
+ }
120
+ return buffer;
121
+ }
122
+
123
+ /**
124
+ * Destroys a buffer created here and decrements `resident`; a buffer the tracker does not know is destroyed
125
+ * without touching the bookkeeping, so destroying twice is harmless.
126
+ * @param buffer - the buffer to destroy
127
+ */
128
+ destroy(buffer: GPUBuffer): void {
129
+ const size = this.live.get(buffer);
130
+ if (size !== undefined) {
131
+ this.live.delete(buffer);
132
+ this.residentBytes -= size;
133
+ }
134
+ buffer.destroy();
135
+ }
136
+
137
+ /**
138
+ * Awaits every outstanding scope pop; the first OOM -> E_OUT_OF_MEMORY { requested, resident, label }; later
139
+ * calls after a failure throw the same error again until `reset()`.
140
+ */
141
+ async check(): Promise<void> {
142
+ while (this.pending.length > 0) {
143
+ const batch = this.pending.splice(0);
144
+ await Promise.all(batch);
145
+ }
146
+ if (this.failure !== null) {
147
+ throw this.failure;
148
+ }
149
+ }
150
+
151
+ /** Forgets a recorded OOM after the caller released what it allocated. */
152
+ reset(): void {
153
+ this.failure = null;
154
+ }
155
+
156
+ /**
157
+ * Bytes of live buffers created through this tracker.
158
+ * @returns the resident byte count
159
+ */
160
+ get resident(): number {
161
+ return this.residentBytes;
162
+ }
163
+
164
+ /**
165
+ * Number of live buffers created through this tracker.
166
+ * @returns the live buffer count
167
+ */
168
+ get liveBuffers(): number {
169
+ return this.live.size;
170
+ }
171
+ }
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Device-loss and uncaptured-error plumbing (spec 5.7, 2.2 step 5; contract 3.4): the pending-error slot a
3
+ * context throws from its next public call, the uncapturederror listener that routes each event to the
4
+ * caller's sink or to the slot, the device.lost watcher and the E_DEVICE_LOST constructor. Nothing here
5
+ * throws; errors are constructed and handed on.
6
+ */
7
+
8
+ import { WebGpuGraphError } from "../errors.js";
9
+
10
+ /** The context's pending-error slot (spec 5.7): the last uncaptured error not yet delivered; `take()` clears it. */
11
+ export class PendingErrorSlot {
12
+ private readonly queue: WebGpuGraphError[] = [];
13
+
14
+ /**
15
+ * Stores an error; a second error before `take()` is kept as `details.next` of the first.
16
+ * @param error - the error to hold until the next public call
17
+ */
18
+ set(error: WebGpuGraphError): void {
19
+ this.queue.push(error);
20
+ }
21
+
22
+ /**
23
+ * Returns and clears the pending error, or null. With several errors queued the FIRST is returned and
24
+ * each later one is chained as `details.next` of its predecessor (a copy: `details` is frozen).
25
+ * @returns the first pending error with the chain attached, or null
26
+ */
27
+ take(): WebGpuGraphError | null {
28
+ if (this.queue.length === 0) {
29
+ return null;
30
+ }
31
+ const errors = this.queue.splice(0);
32
+ let chained: WebGpuGraphError | null = null;
33
+ for (let i = errors.length - 1; i >= 0; i -= 1) {
34
+ const error = errors[i];
35
+ chained =
36
+ chained === null
37
+ ? error
38
+ : new WebGpuGraphError(error.code, error.message, { ...error.details, next: chained });
39
+ }
40
+ return chained;
41
+ }
42
+
43
+ /**
44
+ * True when an error is pending.
45
+ * @returns whether `take()` would return an error
46
+ */
47
+ get pending(): boolean {
48
+ return this.queue.length > 0;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * The WebGpuGraphError for one uncaptured GPUError: E_OUT_OF_MEMORY for a GPUOutOfMemoryError (recognised
54
+ * by its class name so no global is read, spec 2.1 rule 1), E_VALIDATION otherwise.
55
+ * @param error - the event's error
56
+ * @param label - the device label the error is attributed to
57
+ * @returns the wrapped error
58
+ */
59
+ function uncapturedError(error: GPUError, label: string): WebGpuGraphError {
60
+ const { message } = error;
61
+ if (error.constructor.name === "GPUOutOfMemoryError") {
62
+ // the documented shape is { requested, resident, label } (contract 3.1); the event names no size and the
63
+ // sink tracks no residency, so both are 0 and the runtime's text lives in the message only
64
+ return new WebGpuGraphError("E_OUT_OF_MEMORY", `uncaptured out-of-memory error on "${label}": ${message}`, {
65
+ requested: 0,
66
+ resident: 0,
67
+ label,
68
+ });
69
+ }
70
+ return new WebGpuGraphError("E_VALIDATION", `uncaptured validation error on "${label}": ${message}`, {
71
+ label,
72
+ message,
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Installs the uncapturederror listener: each event becomes E_VALIDATION { label, message } (or
78
+ * E_OUT_OF_MEMORY for GPUOutOfMemoryError) routed to `onError`, else stored in `slot`. Returns the
79
+ * uninstaller. `label` is the device's label (the descriptor label create() gave it).
80
+ * @param device - the device to listen on
81
+ * @param slot - where errors go when no sink is given
82
+ * @param onError - the caller's sink, or null
83
+ * @returns a function that removes the listener
84
+ */
85
+ export function installUncapturedErrorSink(
86
+ device: GPUDevice,
87
+ slot: PendingErrorSlot,
88
+ onError: ((error: WebGpuGraphError) => void) | null,
89
+ ): () => void {
90
+ let installed = true;
91
+ const label = device.label ?? "";
92
+ const listener = (event: GPUUncapturedErrorEvent): void => {
93
+ if (!installed) {
94
+ return;
95
+ }
96
+ const wrapped = uncapturedError(event.error, label);
97
+ if (onError !== null) {
98
+ onError(wrapped);
99
+ } else {
100
+ slot.set(wrapped);
101
+ }
102
+ };
103
+ device.addEventListener("uncapturederror", listener);
104
+ return () => {
105
+ installed = false;
106
+ if (typeof device.removeEventListener === "function") {
107
+ device.removeEventListener("uncapturederror", listener);
108
+ }
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Chains device.lost into `onLost` exactly once; returns the promise the context exposes as `ctx.lost`.
114
+ * @param device - the device whose loss is watched
115
+ * @param onLost - called once with the lost info
116
+ * @returns the lost info, after `onLost` ran
117
+ */
118
+ export function watchDeviceLost(
119
+ device: GPUDevice,
120
+ onLost: (info: GPUDeviceLostInfo) => void,
121
+ ): Promise<GPUDeviceLostInfo> {
122
+ let delivered = false;
123
+ return device.lost.then((info) => {
124
+ if (!delivered) {
125
+ delivered = true;
126
+ onLost(info);
127
+ }
128
+ return info;
129
+ });
130
+ }
131
+
132
+ /**
133
+ * The E_DEVICE_LOST error for a lost-info record.
134
+ * @param info - the device.lost result
135
+ * @returns E_DEVICE_LOST { reason, message }
136
+ */
137
+ export function deviceLostError(info: GPUDeviceLostInfo): WebGpuGraphError {
138
+ return new WebGpuGraphError("E_DEVICE_LOST", `device lost (${info.reason}): ${info.message}`, {
139
+ reason: info.reason,
140
+ message: info.message,
141
+ });
142
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * GPUBufferUsage / GPUMapMode / GPUShaderStage as numbers (spec 2.1 rule 1; contract 3.4): under Dawn-node the
3
+ * global namespaces do not exist until `Object.assign(globalThis, dawn.globals)` has run, so the core never reads
4
+ * them at module top level and keeps its own copies here. Each field names the WebGPU spec constant it mirrors;
5
+ * test/device/constants.test.ts compares every field with the runtime globals so a drift is caught.
6
+ */
7
+
8
+ /** GPUBufferUsage bits as numbers so the core never reads the global at module top level (spec 2.1 rule 1). */
9
+ export const BufferUsage: Readonly<{
10
+ MAP_READ: 0x0001;
11
+ MAP_WRITE: 0x0002;
12
+ COPY_SRC: 0x0004;
13
+ COPY_DST: 0x0008;
14
+ INDEX: 0x0010;
15
+ VERTEX: 0x0020;
16
+ UNIFORM: 0x0040;
17
+ STORAGE: 0x0080;
18
+ INDIRECT: 0x0100;
19
+ QUERY_RESOLVE: 0x0200;
20
+ }> = Object.freeze({
21
+ MAP_READ: 0x0001, // GPUBufferUsage.MAP_READ
22
+ MAP_WRITE: 0x0002, // GPUBufferUsage.MAP_WRITE
23
+ COPY_SRC: 0x0004, // GPUBufferUsage.COPY_SRC
24
+ COPY_DST: 0x0008, // GPUBufferUsage.COPY_DST
25
+ INDEX: 0x0010, // GPUBufferUsage.INDEX
26
+ VERTEX: 0x0020, // GPUBufferUsage.VERTEX
27
+ UNIFORM: 0x0040, // GPUBufferUsage.UNIFORM
28
+ STORAGE: 0x0080, // GPUBufferUsage.STORAGE
29
+ INDIRECT: 0x0100, // GPUBufferUsage.INDIRECT
30
+ QUERY_RESOLVE: 0x0200, // GPUBufferUsage.QUERY_RESOLVE
31
+ });
32
+
33
+ /** GPUMapMode bits. */
34
+ export const MapMode: Readonly<{ READ: 0x0001; WRITE: 0x0002 }> = Object.freeze({
35
+ READ: 0x0001, // GPUMapMode.READ
36
+ WRITE: 0x0002, // GPUMapMode.WRITE
37
+ });
38
+
39
+ /** GPUShaderStage bits. */
40
+ export const ShaderStage: Readonly<{ VERTEX: 0x1; FRAGMENT: 0x2; COMPUTE: 0x4 }> = Object.freeze({
41
+ VERTEX: 0x1, // GPUShaderStage.VERTEX
42
+ FRAGMENT: 0x2, // GPUShaderStage.FRAGMENT
43
+ COMPUTE: 0x4, // GPUShaderStage.COMPUTE
44
+ });
package/src/errors.ts ADDED
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The error class and the closed code set of @graphty/webgpu-graph-algorithms (spec 3.3, 5.7; contract 3.1).
3
+ *
4
+ * Every condition the package detects itself is thrown as a WebGpuGraphError carrying a stable `code` and a
5
+ * frozen shallow copy of the `details` the thrower supplied. Errors raised by @graphty/graph-format accessors
6
+ * the package calls on the caller's behalf pass through unchanged (D12); PASSTHROUGH_FORMAT_CODES lists the
7
+ * codes a public call may let escape. Constructors never throw. Messages are plain ASCII.
8
+ *
9
+ * `details` keys per code (contract 3.1, so tests can assert them): E_NO_WEBGPU { reason, hint };
10
+ * E_NO_ADAPTER { reason }; E_NO_DEVICE { reason, adapter, limit?, requested?, available? } (reason "consumed" |
11
+ * "requestDevice" | "limit" | "feature" | "maxComputeWorkgroupsPerDimension"); E_SOFTWARE_ONLY { adapter };
12
+ * E_DEVICE_LOST { reason, message }; E_DISPOSED { label }; E_VALIDATION { label, message, batchId? };
13
+ * E_SHADER_COMPILE { id, stage: "compose" | "compile", slot?, messages? }; E_OUT_OF_MEMORY { requested, resident,
14
+ * label }; E_TOO_LARGE { needed, limit, path, algorithm }; E_UNSUPPORTED { feature? | option?, hint? } (exactly
15
+ * one of feature / option); E_INVALID_ARGUMENT { argument, value, expected? }; E_SNAPSHOT { reason, serial };
16
+ * E_RELEASED { serial }; E_NOT_LOADED { state }; E_ABORTED { batchId? }.
17
+ */
18
+
19
+ /** Every condition the package detects itself carries one of these codes (spec 3.3). */
20
+ export type WebGpuGraphErrorCode =
21
+ | "E_NO_WEBGPU"
22
+ | "E_NO_ADAPTER"
23
+ | "E_NO_DEVICE"
24
+ | "E_SOFTWARE_ONLY"
25
+ | "E_DEVICE_LOST"
26
+ | "E_DISPOSED"
27
+ | "E_VALIDATION"
28
+ | "E_SHADER_COMPILE"
29
+ | "E_OUT_OF_MEMORY"
30
+ | "E_TOO_LARGE"
31
+ | "E_UNSUPPORTED"
32
+ | "E_INVALID_ARGUMENT"
33
+ | "E_SNAPSHOT"
34
+ | "E_RELEASED"
35
+ | "E_NOT_LOADED"
36
+ | "E_ABORTED";
37
+
38
+ /** The graph-format error codes a public call lets propagate unchanged (D12, spec 5.7): raised by accessors the package calls on the caller's behalf. */
39
+ export const PASSTHROUGH_FORMAT_CODES: readonly [
40
+ "E_GPU_INELIGIBLE",
41
+ "E_UNKNOWN_NODE",
42
+ "E_UNKNOWN_COLUMN",
43
+ "E_COLUMN_LENGTH",
44
+ ] = Object.freeze(["E_GPU_INELIGIBLE", "E_UNKNOWN_NODE", "E_UNKNOWN_COLUMN", "E_COLUMN_LENGTH"] as const);
45
+
46
+ const EMPTY_DETAILS: Readonly<Record<string, unknown>> = Object.freeze({});
47
+
48
+ /** The one error class the package throws for conditions it detects itself: a stable `code` and frozen `details` (spec 3.3). */
49
+ export class WebGpuGraphError extends Error {
50
+ /** The stable code. */
51
+ readonly code: WebGpuGraphErrorCode;
52
+
53
+ /** Frozen shallow copy of the details given to the constructor (`{}` when none). */
54
+ readonly details: Readonly<Record<string, unknown>>;
55
+
56
+ /** `name` is always "WebGpuGraphError". */
57
+ override readonly name: "WebGpuGraphError";
58
+
59
+ /**
60
+ * Create a WebGpuGraphError.
61
+ * @param code - the stable code the caller can branch on
62
+ * @param message - a plain-ASCII human-readable message naming the offending label, limit or value
63
+ * @param details - optional machine-readable context; copied shallowly and frozen
64
+ */
65
+ constructor(code: WebGpuGraphErrorCode, message: string, details?: Record<string, unknown>) {
66
+ super(message);
67
+ this.name = "WebGpuGraphError";
68
+ this.code = code;
69
+ this.details = details === undefined ? EMPTY_DETAILS : Object.freeze({ ...details });
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Brand check that survives two package copies: `name === "WebGpuGraphError"` and a string `code`.
75
+ * @param x - anything, typically a caught value
76
+ * @returns true when `x` is structurally a WebGpuGraphError (instanceof is NOT required)
77
+ */
78
+ export function isWebGpuGraphError(x: unknown): x is WebGpuGraphError {
79
+ if (typeof x !== "object" || x === null) {
80
+ return false;
81
+ }
82
+ const candidate = x as { readonly name?: unknown; readonly code?: unknown };
83
+ return candidate.name === "WebGpuGraphError" && typeof candidate.code === "string";
84
+ }
85
+
86
+ /**
87
+ * Brand check that survives two package copies: `code === x.code` for an `isWebGpuGraphError(x)`.
88
+ * @param x - anything, typically a caught value
89
+ * @param code - the code to test for
90
+ * @returns true when `x` is a WebGpuGraphError carrying `code`
91
+ */
92
+ export function hasErrorCode(x: unknown, code: WebGpuGraphErrorCode): boolean {
93
+ return isWebGpuGraphError(x) && x.code === code;
94
+ }
package/src/index.ts ADDED
@@ -0,0 +1,102 @@
1
+ /// <reference types="@webgpu/types" preserve="true" />
2
+ /**
3
+ * The public barrel of @graphty/webgpu-graph-algorithms (spec 2.5, 3.3; contract 3.15): explicit named exports only,
4
+ * values and `export type`, no star re-exports, no default export, nothing from src/browser/** or src/node/** (their
5
+ * own entries; imported by nothing else in src/, 2.4) and nothing of the internal surface (GraphResidency,
6
+ * BufferPool, Readback, Lease, PipelineCache, Kernel, CommandBatch, UniformRing, UniformBlock, composeWgsl, KERNELS,
7
+ * ForceSimulation, ForceAtlas2Model: tests import them from their files). P0: the error class, the constants and
8
+ * isSoftwareAdapter. P1 adds GpuContext and degree (values) and the context / run / profiler types. P2 adds nothing
9
+ * (Lease, CommandBatch, UniformRing are internal). P3 adds the layout factory, the accelerator, the two default
10
+ * tables, the seeder and the layout / accelerator types. test/index.test.ts pins the value list and
11
+ * test/types/public-api.test-d.ts the type list; P4+ extends both. This comment must never spell the internal
12
+ * JSDoc tag: it is the leading comment of the first export statement, and stripInternal would drop that statement
13
+ * from the emitted declarations.
14
+ */
15
+
16
+ // ==================== constants and errors (P0; FA2_DEFAULTS / LAYOUT_TUNING_DEFAULTS public from P3)
17
+ export {
18
+ ARC_WINDOW_ALIGN,
19
+ EXACT_MAX_NODES,
20
+ FA2_DEFAULTS,
21
+ LAYOUT_TUNING_DEFAULTS,
22
+ MAX_1D_ITEMS,
23
+ MAX_WORKGROUPS_PER_DIM,
24
+ STORAGE_ALIGN,
25
+ WORKGROUP_SIZE,
26
+ } from "./constants.js";
27
+ export {
28
+ hasErrorCode,
29
+ isWebGpuGraphError,
30
+ PASSTHROUGH_FORMAT_CODES,
31
+ WebGpuGraphError,
32
+ type WebGpuGraphErrorCode,
33
+ } from "./errors.js";
34
+
35
+ // ==================== context, adapter classifier, profiler (P0 / P1)
36
+ export { GpuContext } from "./context.js";
37
+ export { isSoftwareAdapter } from "./device/acquire.js";
38
+ export type { PassTiming, Profiler } from "./kernel/profiler.js";
39
+
40
+ // ==================== algorithms (P1: the walking-skeleton diagnostic, spec 3.3)
41
+ export { degree } from "./algorithms/degree.js";
42
+
43
+ // ==================== layouts and the accelerator (P3)
44
+ export { createAccelerator } from "./accelerator.js";
45
+ export { createForceAtlas2 } from "./layouts/forceatlas2.js";
46
+ export { seedPositions } from "./layouts/seed.js";
47
+
48
+ // ==================== types: the accelerator surface and the CPU-package mirrors (spec 9.2, 9.3; D27)
49
+ export type {
50
+ AcceleratorOptions,
51
+ AlgorithmAccelerator,
52
+ ApspResultLike,
53
+ BellmanFordResultLike,
54
+ BfsResultLike,
55
+ CommunityResultLike,
56
+ CorenessResultLike,
57
+ CpuAlgorithmOptions,
58
+ EdgeScoresResultLike,
59
+ GpuAccelerator,
60
+ HitsResultLike,
61
+ LabelResultLike,
62
+ LayoutAccelerator,
63
+ LayoutSimulation,
64
+ MstResultLike,
65
+ PageRankResultLike,
66
+ ScoresResultLike,
67
+ SsspResultLike,
68
+ } from "./types/accelerator.js";
69
+
70
+ // ==================== types: context and capabilities (P0 / P1)
71
+ export type {
72
+ AdapterInfoLike,
73
+ AdapterSummary,
74
+ GpuCaps,
75
+ GpuContextOptions,
76
+ LimitPolicy,
77
+ PlanCaps,
78
+ PlanLimits,
79
+ ProbeOptions,
80
+ ProbeResult,
81
+ RaisableLimit,
82
+ } from "./types/context.js";
83
+
84
+ // ==================== types: layouts (P3)
85
+ export type {
86
+ ForceAtlas2Stats,
87
+ ForceAtlas2TraceRecord,
88
+ GpuLayoutSimulation,
89
+ GpuLayoutTuning,
90
+ LayoutStatsBase,
91
+ RunOptions,
92
+ } from "./types/layout.js";
93
+ export type {
94
+ CommonLayoutOptions,
95
+ ForceAtlas2Options,
96
+ FruchtermanReingoldOptions,
97
+ SimulationOptions,
98
+ SpringElectricalOptions,
99
+ } from "./types/options.js";
100
+
101
+ // ==================== types: run options (P1)
102
+ export type { GpuRunOptions } from "./types/run.js";