@pibbl/core 0.0.2 → 0.0.3-alpha.90.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.
Files changed (285) hide show
  1. package/THIRD_PARTY_NOTICES.txt +81 -0
  2. package/dist/features/textures/index.d.ts +12 -2
  3. package/dist/features/textures/index.js +33 -1
  4. package/dist/features/textures/index.js.map +2 -2
  5. package/dist/features/textures/lib/chemical-field.d.ts +56 -0
  6. package/dist/features/textures/lib/chemical-field.js +154 -0
  7. package/dist/features/textures/lib/chemical-field.js.map +7 -0
  8. package/dist/features/textures/lib/chemical-recipes.d.ts +119 -0
  9. package/dist/features/textures/lib/chemical-recipes.js +275 -0
  10. package/dist/features/textures/lib/chemical-recipes.js.map +7 -0
  11. package/dist/features/textures/lib/definitions.d.ts +3 -18
  12. package/dist/features/textures/lib/definitions.js +15 -20
  13. package/dist/features/textures/lib/definitions.js.map +2 -2
  14. package/dist/features/textures/lib/geometric-patterns.d.ts +149 -0
  15. package/dist/features/textures/lib/geometric-patterns.js +305 -0
  16. package/dist/features/textures/lib/geometric-patterns.js.map +7 -0
  17. package/dist/features/textures/lib/gray-scott.d.ts +55 -0
  18. package/dist/features/textures/lib/gray-scott.js +39 -0
  19. package/dist/features/textures/lib/gray-scott.js.map +7 -0
  20. package/dist/features/textures/lib/patterns.d.ts +123 -0
  21. package/dist/features/textures/lib/patterns.js +344 -0
  22. package/dist/features/textures/lib/patterns.js.map +7 -0
  23. package/dist/features/textures/lib/reaction-diffusion.d.ts +3 -2
  24. package/dist/features/textures/lib/reaction-diffusion.js +9 -20
  25. package/dist/features/textures/lib/reaction-diffusion.js.map +2 -2
  26. package/dist/features/textures/lib/simulation.d.ts +10 -4
  27. package/dist/features/textures/lib/simulation.js +23 -13
  28. package/dist/features/textures/lib/simulation.js.map +2 -2
  29. package/dist/features/viz/index.d.ts +68 -6
  30. package/dist/features/viz/index.js +164 -2
  31. package/dist/features/viz/index.js.map +2 -2
  32. package/dist/features/viz/inspection/bar.d.ts +79 -0
  33. package/dist/features/viz/inspection/bar.js +49 -0
  34. package/dist/features/viz/inspection/bar.js.map +7 -0
  35. package/dist/features/viz/inspection/candle.d.ts +156 -0
  36. package/dist/features/viz/inspection/candle.js +120 -0
  37. package/dist/features/viz/inspection/candle.js.map +7 -0
  38. package/dist/features/viz/inspection/capture-types.d.ts +65 -0
  39. package/dist/features/viz/inspection/capture.d.ts +16 -0
  40. package/dist/features/viz/inspection/capture.js +49 -0
  41. package/dist/features/viz/inspection/capture.js.map +7 -0
  42. package/dist/features/viz/inspection/handler.d.ts +36 -0
  43. package/dist/features/viz/inspection/handler.js +91 -0
  44. package/dist/features/viz/inspection/handler.js.map +7 -0
  45. package/dist/features/viz/inspection/ohlc-bar.d.ts +132 -0
  46. package/dist/features/viz/inspection/ohlc-bar.js +118 -0
  47. package/dist/features/viz/inspection/ohlc-bar.js.map +7 -0
  48. package/dist/features/viz/inspection/owned-ref.d.ts +16 -0
  49. package/dist/features/viz/inspection/owned-ref.js +99 -0
  50. package/dist/features/viz/inspection/owned-ref.js.map +7 -0
  51. package/dist/features/viz/inspection/painted-point.d.ts +22 -0
  52. package/dist/features/viz/inspection/painted-point.js +29 -0
  53. package/dist/features/viz/inspection/painted-point.js.map +7 -0
  54. package/dist/features/viz/inspection/queries.d.ts +100 -0
  55. package/dist/features/viz/inspection/queries.js +192 -0
  56. package/dist/features/viz/inspection/queries.js.map +7 -0
  57. package/dist/features/viz/inspection/query-types.d.ts +177 -0
  58. package/dist/features/viz/inspection/volume.d.ts +104 -0
  59. package/dist/features/viz/inspection/volume.js +95 -0
  60. package/dist/features/viz/inspection/volume.js.map +7 -0
  61. package/dist/features/viz/inspection.d.ts +19 -0
  62. package/dist/features/viz/inspection.js +54 -0
  63. package/dist/features/viz/inspection.js.map +7 -0
  64. package/dist/features/viz/inspection.mjs +1 -0
  65. package/dist/features/viz/lib/area-series.d.ts +62 -0
  66. package/dist/features/viz/lib/area-series.js +120 -0
  67. package/dist/features/viz/lib/area-series.js.map +7 -0
  68. package/dist/features/viz/lib/axis.js +1 -1
  69. package/dist/features/viz/lib/axis.js.map +2 -2
  70. package/dist/features/viz/lib/bar-series.d.ts +3 -1
  71. package/dist/features/viz/lib/bar-series.js +16 -1
  72. package/dist/features/viz/lib/bar-series.js.map +2 -2
  73. package/dist/features/viz/lib/baseline-series.d.ts +55 -0
  74. package/dist/features/viz/lib/baseline-series.js +136 -0
  75. package/dist/features/viz/lib/baseline-series.js.map +7 -0
  76. package/dist/features/viz/lib/candlestick-series.d.ts +62 -0
  77. package/dist/features/viz/lib/candlestick-series.js +150 -0
  78. package/dist/features/viz/lib/candlestick-series.js.map +7 -0
  79. package/dist/features/viz/lib/censored-point-series.d.ts +71 -0
  80. package/dist/features/viz/lib/censored-point-series.js +129 -0
  81. package/dist/features/viz/lib/censored-point-series.js.map +7 -0
  82. package/dist/features/viz/lib/color-context.d.ts +4 -0
  83. package/dist/features/viz/lib/color-context.js +41 -0
  84. package/dist/features/viz/lib/color-context.js.map +7 -0
  85. package/dist/features/viz/lib/color-math.d.ts +4 -0
  86. package/dist/features/viz/lib/color-math.js +31 -0
  87. package/dist/features/viz/lib/color-math.js.map +7 -0
  88. package/dist/features/viz/lib/color-types.d.ts +53 -0
  89. package/dist/features/viz/lib/curve-definition.d.ts +49 -0
  90. package/dist/features/viz/lib/curve-definition.js +148 -0
  91. package/dist/features/viz/lib/curve-definition.js.map +7 -0
  92. package/dist/features/viz/lib/diverging-color-scale.d.ts +11 -0
  93. package/dist/features/viz/lib/diverging-color-scale.js +51 -0
  94. package/dist/features/viz/lib/diverging-color-scale.js.map +7 -0
  95. package/dist/features/viz/lib/domain-navigation.d.ts +40 -0
  96. package/dist/features/viz/lib/domain-navigation.js +77 -0
  97. package/dist/features/viz/lib/domain-navigation.js.map +7 -0
  98. package/dist/features/viz/lib/editable-chart-elements.d.ts +178 -0
  99. package/dist/features/viz/lib/editable-chart-elements.js +733 -0
  100. package/dist/features/viz/lib/editable-chart-elements.js.map +7 -0
  101. package/dist/features/viz/lib/financial-aggregation.d.ts +127 -0
  102. package/dist/features/viz/lib/financial-aggregation.js +116 -0
  103. package/dist/features/viz/lib/financial-aggregation.js.map +7 -0
  104. package/dist/features/viz/lib/financial-autoscale.d.ts +64 -0
  105. package/dist/features/viz/lib/financial-autoscale.js +61 -0
  106. package/dist/features/viz/lib/financial-autoscale.js.map +7 -0
  107. package/dist/features/viz/lib/financial-comparison.d.ts +62 -0
  108. package/dist/features/viz/lib/financial-comparison.js +98 -0
  109. package/dist/features/viz/lib/financial-comparison.js.map +7 -0
  110. package/dist/features/viz/lib/financial-geometry.d.ts +77 -0
  111. package/dist/features/viz/lib/financial-geometry.js +67 -0
  112. package/dist/features/viz/lib/financial-geometry.js.map +7 -0
  113. package/dist/features/viz/lib/financial-indicators.d.ts +114 -0
  114. package/dist/features/viz/lib/financial-indicators.js +135 -0
  115. package/dist/features/viz/lib/financial-indicators.js.map +7 -0
  116. package/dist/features/viz/lib/financial-oscillators.d.ts +171 -0
  117. package/dist/features/viz/lib/financial-oscillators.js +265 -0
  118. package/dist/features/viz/lib/financial-oscillators.js.map +7 -0
  119. package/dist/features/viz/lib/graph/bipartite.d.ts +14 -0
  120. package/dist/features/viz/lib/graph/bipartite.js +250 -0
  121. package/dist/features/viz/lib/graph/bipartite.js.map +7 -0
  122. package/dist/features/viz/lib/graph/chord.d.ts +44 -0
  123. package/dist/features/viz/lib/graph/chord.js +348 -0
  124. package/dist/features/viz/lib/graph/chord.js.map +7 -0
  125. package/dist/features/viz/lib/graph/dependency.d.ts +26 -0
  126. package/dist/features/viz/lib/graph/dependency.js +141 -0
  127. package/dist/features/viz/lib/graph/dependency.js.map +7 -0
  128. package/dist/features/viz/lib/graph/force.d.ts +28 -0
  129. package/dist/features/viz/lib/graph/force.js +580 -0
  130. package/dist/features/viz/lib/graph/force.js.map +7 -0
  131. package/dist/features/viz/lib/graph/hierarchy.d.ts +21 -0
  132. package/dist/features/viz/lib/graph/hierarchy.js +112 -0
  133. package/dist/features/viz/lib/graph/hierarchy.js.map +7 -0
  134. package/dist/features/viz/lib/graph/icicle.d.ts +16 -0
  135. package/dist/features/viz/lib/graph/icicle.js +153 -0
  136. package/dist/features/viz/lib/graph/icicle.js.map +7 -0
  137. package/dist/features/viz/lib/graph/matrix.d.ts +30 -0
  138. package/dist/features/viz/lib/graph/matrix.js +243 -0
  139. package/dist/features/viz/lib/graph/matrix.js.map +7 -0
  140. package/dist/features/viz/lib/graph/neighborhood.d.ts +11 -0
  141. package/dist/features/viz/lib/graph/neighborhood.js +281 -0
  142. package/dist/features/viz/lib/graph/neighborhood.js.map +7 -0
  143. package/dist/features/viz/lib/graph/routes.d.ts +35 -0
  144. package/dist/features/viz/lib/graph/routes.js +102 -0
  145. package/dist/features/viz/lib/graph/routes.js.map +7 -0
  146. package/dist/features/viz/lib/graph/sankey.d.ts +44 -0
  147. package/dist/features/viz/lib/graph/sankey.js +341 -0
  148. package/dist/features/viz/lib/graph/sankey.js.map +7 -0
  149. package/dist/features/viz/lib/graph/shared.d.ts +59 -0
  150. package/dist/features/viz/lib/graph/shared.js +296 -0
  151. package/dist/features/viz/lib/graph/shared.js.map +7 -0
  152. package/dist/features/viz/lib/graph/tree.d.ts +11 -0
  153. package/dist/features/viz/lib/graph/tree.js +232 -0
  154. package/dist/features/viz/lib/graph/tree.js.map +7 -0
  155. package/dist/features/viz/lib/graph/treemap.d.ts +20 -0
  156. package/dist/features/viz/lib/graph/treemap.js +227 -0
  157. package/dist/features/viz/lib/graph/treemap.js.map +7 -0
  158. package/dist/features/viz/lib/graph/types.d.ts +1097 -0
  159. package/dist/features/viz/lib/hover-data.d.ts +1 -1
  160. package/dist/features/viz/lib/hover-data.js +5 -2
  161. package/dist/features/viz/lib/hover-data.js.map +2 -2
  162. package/dist/features/viz/lib/interval-band-series.d.ts +49 -0
  163. package/dist/features/viz/lib/interval-band-series.js +136 -0
  164. package/dist/features/viz/lib/interval-band-series.js.map +7 -0
  165. package/dist/features/viz/lib/interval-diamond-series.d.ts +43 -0
  166. package/dist/features/viz/lib/interval-diamond-series.js +124 -0
  167. package/dist/features/viz/lib/interval-diamond-series.js.map +7 -0
  168. package/dist/features/viz/lib/interval-series.d.ts +79 -0
  169. package/dist/features/viz/lib/interval-series.js +158 -0
  170. package/dist/features/viz/lib/interval-series.js.map +7 -0
  171. package/dist/features/viz/lib/line-series.d.ts +1 -1
  172. package/dist/features/viz/lib/line-series.js +47 -28
  173. package/dist/features/viz/lib/line-series.js.map +2 -2
  174. package/dist/features/viz/lib/linear-scale.js +1 -1
  175. package/dist/features/viz/lib/linear-scale.js.map +2 -2
  176. package/dist/features/viz/lib/monotone-curve.d.ts +11 -0
  177. package/dist/features/viz/lib/monotone-curve.js +63 -0
  178. package/dist/features/viz/lib/monotone-curve.js.map +7 -0
  179. package/dist/features/viz/lib/numeric-range-interpolation.d.ts +15 -0
  180. package/dist/features/viz/lib/numeric-range-interpolation.js +36 -0
  181. package/dist/features/viz/lib/numeric-range-interpolation.js.map +7 -0
  182. package/dist/features/viz/lib/ohlc-bar-series.d.ts +55 -0
  183. package/dist/features/viz/lib/ohlc-bar-series.js +168 -0
  184. package/dist/features/viz/lib/ohlc-bar-series.js.map +7 -0
  185. package/dist/features/viz/lib/paired-series.d.ts +44 -0
  186. package/dist/features/viz/lib/paired-series.js +93 -0
  187. package/dist/features/viz/lib/paired-series.js.map +7 -0
  188. package/dist/features/viz/lib/plot-series.js +11 -6
  189. package/dist/features/viz/lib/plot-series.js.map +2 -2
  190. package/dist/features/viz/lib/plot-types.d.ts +4 -3
  191. package/dist/features/viz/lib/point-series.d.ts +1 -1
  192. package/dist/features/viz/lib/point-series.js +36 -9
  193. package/dist/features/viz/lib/point-series.js.map +2 -2
  194. package/dist/features/viz/lib/point-types.d.ts +5 -2
  195. package/dist/features/viz/lib/scale-context.d.ts +1 -1
  196. package/dist/features/viz/lib/scale-ticks.js +21 -6
  197. package/dist/features/viz/lib/scale-ticks.js.map +2 -2
  198. package/dist/features/viz/lib/sequential-color-scale.d.ts +11 -0
  199. package/dist/features/viz/lib/sequential-color-scale.js +49 -0
  200. package/dist/features/viz/lib/sequential-color-scale.js.map +7 -0
  201. package/dist/features/viz/lib/series-position.d.ts +12 -0
  202. package/dist/features/viz/lib/series-position.js +44 -0
  203. package/dist/features/viz/lib/series-position.js.map +7 -0
  204. package/dist/features/viz/lib/step-curves.d.ts +19 -0
  205. package/dist/features/viz/lib/step-curves.js +53 -0
  206. package/dist/features/viz/lib/step-curves.js.map +7 -0
  207. package/dist/features/viz/lib/threshold-color-scale.d.ts +43 -0
  208. package/dist/features/viz/lib/threshold-color-scale.js +59 -0
  209. package/dist/features/viz/lib/threshold-color-scale.js.map +7 -0
  210. package/dist/features/viz/lib/trading-time-mapping.d.ts +32 -0
  211. package/dist/features/viz/lib/trading-time-mapping.js +89 -0
  212. package/dist/features/viz/lib/trading-time-mapping.js.map +7 -0
  213. package/dist/features/viz/lib/trading-time-scale.d.ts +83 -0
  214. package/dist/features/viz/lib/trading-time-scale.js +96 -0
  215. package/dist/features/viz/lib/trading-time-scale.js.map +7 -0
  216. package/dist/features/viz/lib/trajectory-series.d.ts +71 -0
  217. package/dist/features/viz/lib/trajectory-series.js +111 -0
  218. package/dist/features/viz/lib/trajectory-series.js.map +7 -0
  219. package/dist/features/viz/lib/types.d.ts +20 -4
  220. package/dist/features/viz/lib/use-continuous-scale.js +6 -1
  221. package/dist/features/viz/lib/use-continuous-scale.js.map +2 -2
  222. package/dist/features/viz/lib/volume-series.d.ts +59 -0
  223. package/dist/features/viz/lib/volume-series.js +117 -0
  224. package/dist/features/viz/lib/volume-series.js.map +7 -0
  225. package/dist/features/viz/lib/weighted-point-series.d.ts +71 -0
  226. package/dist/features/viz/lib/weighted-point-series.js +169 -0
  227. package/dist/features/viz/lib/weighted-point-series.js.map +7 -0
  228. package/dist/filters/backdrop-contrast-gpu.d.ts +5 -0
  229. package/dist/filters/backdrop-contrast-gpu.js +33 -0
  230. package/dist/filters/backdrop-contrast-gpu.js.map +7 -0
  231. package/dist/filters/backdrop-contrast.d.ts +21 -0
  232. package/dist/filters/backdrop-contrast.js +61 -0
  233. package/dist/filters/backdrop-contrast.js.map +7 -0
  234. package/dist/filters/emboss-gpu.d.ts +4 -0
  235. package/dist/filters/emboss-gpu.js +39 -0
  236. package/dist/filters/emboss-gpu.js.map +7 -0
  237. package/dist/filters/emboss.d.ts +32 -0
  238. package/dist/filters/emboss.js +106 -0
  239. package/dist/filters/emboss.js.map +7 -0
  240. package/dist/filters/filter-executor.d.ts +11 -4
  241. package/dist/filters/filter-executor.js +104 -49
  242. package/dist/filters/filter-executor.js.map +2 -2
  243. package/dist/filters/reflection-gpu.d.ts +3 -1
  244. package/dist/filters/reflection-gpu.js +5 -2
  245. package/dist/filters/reflection-gpu.js.map +2 -2
  246. package/dist/filters/render-backdrop-contrast-boundary.d.ts +31 -0
  247. package/dist/filters/render-backdrop-contrast-boundary.js +116 -0
  248. package/dist/filters/render-backdrop-contrast-boundary.js.map +7 -0
  249. package/dist/filters/render-emboss-boundary.d.ts +13 -0
  250. package/dist/filters/render-emboss-boundary.js +131 -0
  251. package/dist/filters/render-emboss-boundary.js.map +7 -0
  252. package/dist/filters.d.ts +9 -5
  253. package/dist/filters.js +4 -0
  254. package/dist/filters.js.map +2 -2
  255. package/dist/index.d.ts +2 -0
  256. package/dist/index.js +3 -0
  257. package/dist/index.js.map +2 -2
  258. package/dist/internal.d.ts +2 -0
  259. package/dist/internal.js +4 -0
  260. package/dist/internal.js.map +2 -2
  261. package/dist/lib/events/event-facade.d.ts +13 -0
  262. package/dist/lib/events/event-facade.js +23 -0
  263. package/dist/lib/events/event-facade.js.map +2 -2
  264. package/dist/lib/events/propagation.js +19 -14
  265. package/dist/lib/events/propagation.js.map +2 -2
  266. package/dist/lib/execute-render.js +13 -0
  267. package/dist/lib/execute-render.js.map +2 -2
  268. package/dist/lib/recording/recording.d.ts +43 -0
  269. package/dist/lib/recording/recording.js +555 -0
  270. package/dist/lib/recording/recording.js.map +7 -0
  271. package/dist/lib/recording/types.d.ts +118 -0
  272. package/dist/lib/recording/wasm-bytes.d.ts +1 -0
  273. package/dist/lib/recording/wasm-bytes.js +5 -0
  274. package/dist/lib/recording/wasm-bytes.js.map +7 -0
  275. package/dist/lib/recording/worker-source.d.ts +1 -0
  276. package/dist/lib/recording/worker-source.js +5 -0
  277. package/dist/lib/recording/worker-source.js.map +7 -0
  278. package/dist/lib/render-transaction.d.ts +5 -2
  279. package/dist/lib/render-transaction.js +23 -1
  280. package/dist/lib/render-transaction.js.map +2 -2
  281. package/dist/lib/series-inspection-frame.d.ts +18 -0
  282. package/dist/lib/series-inspection-frame.js +70 -0
  283. package/dist/lib/series-inspection-frame.js.map +7 -0
  284. package/dist/lib/types.d.ts +6 -0
  285. package/package.json +10 -2
@@ -0,0 +1,555 @@
1
+ import { GLOBAL_STATE } from "../global-state.js";
2
+ import { update } from "../update.js";
3
+ import { workerSource } from "./worker-source.js";
4
+ import { bytes } from "./wasm-bytes.js";
5
+ const recordingResources = {
6
+ workers: 0,
7
+ urls: 0,
8
+ observers: 0,
9
+ timers: 0,
10
+ abortListeners: 0,
11
+ requests: 0,
12
+ exports: 0
13
+ };
14
+ const owners = /* @__PURE__ */ new WeakMap();
15
+ function aborted(message = "Recording cancelled.") {
16
+ return new DOMException(message, "AbortError");
17
+ }
18
+ function positive(value, name) {
19
+ if (!Number.isFinite(value) || value <= 0)
20
+ throw new RangeError(`${name} must be finite and greater than zero.`);
21
+ }
22
+ function listen(signal, callback) {
23
+ if (!signal) return () => {
24
+ };
25
+ let attached = true;
26
+ signal.addEventListener("abort", callback, { once: true });
27
+ recordingResources.abortListeners++;
28
+ return () => {
29
+ if (!attached) return;
30
+ attached = false;
31
+ signal.removeEventListener("abort", callback);
32
+ recordingResources.abortListeners--;
33
+ };
34
+ }
35
+ class RecordingClient {
36
+ worker;
37
+ closed = false;
38
+ url;
39
+ nextId = 0;
40
+ pending = /* @__PURE__ */ new Map();
41
+ exporting = false;
42
+ onmessage = () => {
43
+ };
44
+ onerror = () => {
45
+ };
46
+ async initialize(frameBytes, estimatedBytes) {
47
+ await Promise.resolve();
48
+ if (this.closed) return;
49
+ const source = workerSource;
50
+ this.url = URL.createObjectURL(
51
+ new Blob([source], { type: "text/javascript" })
52
+ );
53
+ recordingResources.urls++;
54
+ try {
55
+ this.worker = new Worker(this.url, { name: "Pibbl frame recording" });
56
+ recordingResources.workers++;
57
+ this.worker.onmessage = ({ data }) => {
58
+ if (this.closed) return;
59
+ if (data.type === "ready") this.revoke();
60
+ if (data.type === "fatal") {
61
+ this.onerror(new Error(data.message));
62
+ return;
63
+ }
64
+ const request = this.pending.get(data.id);
65
+ if (request) {
66
+ if (data.type === "progress" && !request.error) {
67
+ try {
68
+ request.progress?.(data.progress);
69
+ } catch (error) {
70
+ this.cancelExport(data.id, error);
71
+ }
72
+ } else if (data.type === "result") {
73
+ if (request.gif) request.result = data.buffer;
74
+ else this.settle(data.id, data.buffer);
75
+ } else if (data.type === "error") {
76
+ this.settle(data.id, void 0, new Error(data.message));
77
+ } else if (data.type === "exportReleased") {
78
+ this.settle(data.id, request.result, request.error);
79
+ }
80
+ }
81
+ this.onmessage(data);
82
+ };
83
+ this.worker.onerror = (event) => this.onerror(new Error(event.message || "Recording worker failed."));
84
+ this.worker.onmessageerror = () => this.onerror(
85
+ new Error("Recording worker message could not be decoded.")
86
+ );
87
+ const buffer = Uint8Array.from(
88
+ atob(bytes),
89
+ (char) => char.charCodeAt(0)
90
+ ).buffer;
91
+ this.send({ type: "start", bytes: buffer, frameBytes, estimatedBytes }, [
92
+ buffer
93
+ ]);
94
+ } catch (error) {
95
+ this.revoke();
96
+ throw error;
97
+ }
98
+ }
99
+ send(data, transfer = []) {
100
+ if (this.closed || !this.worker)
101
+ throw aborted("Recording has been disposed.");
102
+ this.worker.postMessage(data, transfer);
103
+ }
104
+ request(data, options) {
105
+ if (this.closed)
106
+ return Promise.reject(aborted("Recording has been disposed."));
107
+ if (options?.signal?.aborted)
108
+ return Promise.reject(aborted("GIF export cancelled."));
109
+ const gif = data.type === "gif";
110
+ if (gif && this.exporting)
111
+ return Promise.reject(
112
+ new Error("A GIF export is already running for this recording.")
113
+ );
114
+ const id = ++this.nextId;
115
+ if (gif) {
116
+ this.exporting = true;
117
+ recordingResources.exports++;
118
+ }
119
+ return new Promise((resolve, reject) => {
120
+ const request = {
121
+ gif,
122
+ resolve,
123
+ reject,
124
+ cleanup: () => {
125
+ },
126
+ progress: options?.onProgress
127
+ };
128
+ this.pending.set(id, request);
129
+ recordingResources.requests++;
130
+ request.cleanup = listen(
131
+ options?.signal,
132
+ () => this.cancelExport(id, aborted("GIF export cancelled."))
133
+ );
134
+ try {
135
+ this.send({ ...data, id });
136
+ } catch (error) {
137
+ this.settle(id, void 0, error);
138
+ }
139
+ });
140
+ }
141
+ cancelExport(id, error) {
142
+ const request = this.pending.get(id);
143
+ if (!request || request.error) return;
144
+ request.error = error;
145
+ request.cleanup();
146
+ try {
147
+ this.send({ type: "cancelExport", id });
148
+ } catch {
149
+ this.settle(id, void 0, error);
150
+ }
151
+ }
152
+ settle(id, result, error) {
153
+ const request = this.pending.get(id);
154
+ if (!request) return;
155
+ this.pending.delete(id);
156
+ request.cleanup();
157
+ recordingResources.requests--;
158
+ if (request.gif) {
159
+ this.exporting = false;
160
+ recordingResources.exports--;
161
+ }
162
+ if (error !== void 0) request.reject(error);
163
+ else if (result) request.resolve(result);
164
+ else request.reject(new Error("Recording worker returned no result."));
165
+ }
166
+ revoke() {
167
+ if (!this.url) return;
168
+ URL.revokeObjectURL(this.url);
169
+ this.url = void 0;
170
+ recordingResources.urls--;
171
+ }
172
+ dispose(error = aborted("Recording has been disposed.")) {
173
+ if (this.closed) return;
174
+ this.closed = true;
175
+ if (this.worker) {
176
+ this.worker.onmessage = this.worker.onerror = this.worker.onmessageerror = null;
177
+ this.worker.terminate();
178
+ this.worker = void 0;
179
+ recordingResources.workers--;
180
+ }
181
+ this.revoke();
182
+ for (const id of this.pending.keys()) this.settle(id, void 0, error);
183
+ this.onmessage = this.onerror = () => {
184
+ };
185
+ }
186
+ }
187
+ function retainRecording(client, frames, duration) {
188
+ const result = Object.freeze({
189
+ duration,
190
+ frames,
191
+ async readFrame(index) {
192
+ if (!Number.isInteger(index) || index < 0 || index >= frames.length)
193
+ throw new RangeError("Frame index is out of range.");
194
+ const buffer = await client.request({ type: "read", index });
195
+ return { ...frames[index], data: new Uint8ClampedArray(buffer) };
196
+ },
197
+ dispose() {
198
+ client.dispose();
199
+ }
200
+ });
201
+ owners.set(result, client);
202
+ client.onmessage = () => {
203
+ };
204
+ client.onerror = (error) => client.dispose(error);
205
+ return result;
206
+ }
207
+ function recordFrames(canvas, options) {
208
+ positive(options.duration, "duration");
209
+ const frameRate = options.frameRate ?? 60;
210
+ const headroom = options.memoryHeadroom ?? 1.15;
211
+ positive(frameRate, "frameRate");
212
+ positive(headroom, "memoryHeadroom");
213
+ if (headroom < 1)
214
+ throw new RangeError("memoryHeadroom must be at least one.");
215
+ if (options.duration > 2147483647)
216
+ throw new RangeError("duration exceeds the supported timer range.");
217
+ let instance = GLOBAL_STATE.pibblInstances.get(canvas);
218
+ if (!instance || instance.parent || instance.mainTeardowns.closed)
219
+ throw new Error("recordFrames requires a live Pibbl root canvas.");
220
+ let target = canvas;
221
+ const client = new RecordingClient();
222
+ const metadata = [];
223
+ let phase = "starting";
224
+ let initializing = false;
225
+ let workerReady = false, stopRequested = false;
226
+ let started = 0, last = -Infinity, duration = 0, pendingFrames = 0;
227
+ let width = 0, height = 0;
228
+ let pendingRenderGeneration = 0;
229
+ let lastNotifiedGeneration = 0;
230
+ let timer;
231
+ let sampleTimer;
232
+ let removeAbort = () => {
233
+ };
234
+ let resolveReady, rejectReady;
235
+ let resolveFinished, rejectFinished;
236
+ const ready = new Promise((resolve, reject) => {
237
+ resolveReady = resolve;
238
+ rejectReady = reject;
239
+ });
240
+ const finished = new Promise((resolve, reject) => {
241
+ resolveFinished = resolve;
242
+ rejectFinished = reject;
243
+ });
244
+ void ready.catch(() => {
245
+ });
246
+ void finished.catch(() => {
247
+ });
248
+ function clearSampleTimer() {
249
+ if (sampleTimer === void 0) return;
250
+ clearTimeout(sampleTimer);
251
+ sampleTimer = void 0;
252
+ recordingResources.timers--;
253
+ }
254
+ function detach() {
255
+ clearSampleTimer();
256
+ if (timer !== void 0) {
257
+ clearTimeout(timer);
258
+ timer = void 0;
259
+ recordingResources.timers--;
260
+ }
261
+ removeAbort();
262
+ removeAbort = () => {
263
+ };
264
+ if (instance) {
265
+ instance.mainTeardowns.remove(rootDisposed);
266
+ if (instance.rootFrameObservers?.delete(observe))
267
+ recordingResources.observers--;
268
+ if (!instance.rootFrameObservers?.size)
269
+ instance.rootFrameObservers = void 0;
270
+ }
271
+ instance = void 0;
272
+ target = void 0;
273
+ }
274
+ function fail(error) {
275
+ if (phase === "finished" || phase === "cancelled") return;
276
+ phase = "cancelled";
277
+ detach();
278
+ client.dispose(error);
279
+ metadata.length = 0;
280
+ rejectReady(error);
281
+ rejectFinished(error);
282
+ }
283
+ function rootDisposed() {
284
+ fail(aborted("Pibbl mount disposed during recording."));
285
+ }
286
+ function stop() {
287
+ if (phase === "starting") {
288
+ stopRequested = true;
289
+ return;
290
+ }
291
+ if (phase !== "capturing") return;
292
+ duration = Math.min(options.duration, performance.now() - started);
293
+ phase = "finishing";
294
+ detach();
295
+ try {
296
+ client.send({ type: "finish" });
297
+ } catch (error) {
298
+ fail(error);
299
+ }
300
+ }
301
+ function capture(renderGeneration) {
302
+ if (!target) return;
303
+ if (!Number.isSafeInteger(renderGeneration) || renderGeneration <= 0)
304
+ throw new Error("Recording requires a committed render generation.");
305
+ if (target.width !== width || target.height !== height)
306
+ throw new Error("Canvas backing size changed during recording.");
307
+ const now = performance.now();
308
+ const initial = phase === "starting";
309
+ const timestamp = initial ? 0 : now - started;
310
+ if (!initial && timestamp >= options.duration) {
311
+ stop();
312
+ return;
313
+ }
314
+ if (!initial && timestamp - last < 1e3 / frameRate) {
315
+ if (sampleTimer === void 0) {
316
+ sampleTimer = setTimeout(
317
+ () => {
318
+ sampleTimer = void 0;
319
+ recordingResources.timers--;
320
+ if (phase !== "capturing") return;
321
+ try {
322
+ capture(pendingRenderGeneration);
323
+ } catch (error) {
324
+ fail(error);
325
+ }
326
+ },
327
+ Math.ceil(1e3 / frameRate - (timestamp - last))
328
+ );
329
+ recordingResources.timers++;
330
+ }
331
+ return;
332
+ }
333
+ clearSampleTimer();
334
+ if (pendingFrames >= 3)
335
+ throw new Error(
336
+ "Recording capture queue overflow; no frames were silently dropped."
337
+ );
338
+ const context = target.getContext("2d");
339
+ if (!context)
340
+ throw new Error("Recording requires a readable Canvas 2D surface.");
341
+ const pixels = context.getImageData(0, 0, width, height);
342
+ client.send({ type: "frame", timestamp, buffer: pixels.data.buffer }, [
343
+ pixels.data.buffer
344
+ ]);
345
+ pendingFrames++;
346
+ const info = Object.freeze({ timestamp, width, height, renderGeneration });
347
+ metadata.push(info);
348
+ options.onFrameCaptured?.(info);
349
+ if (phase !== "starting" && phase !== "capturing") return;
350
+ last = timestamp;
351
+ if (initial) {
352
+ started = now;
353
+ phase = "capturing";
354
+ timer = setTimeout(stop, options.duration);
355
+ recordingResources.timers++;
356
+ resolveReady();
357
+ if (stopRequested) stop();
358
+ }
359
+ }
360
+ function observe(success, renderGeneration) {
361
+ if (phase === "finished" || phase === "cancelled") return;
362
+ if (renderGeneration > lastNotifiedGeneration) {
363
+ lastNotifiedGeneration = renderGeneration;
364
+ const completion = success ? { status: "committed", generation: renderGeneration } : { status: "failed", generation: renderGeneration };
365
+ try {
366
+ options.onRenderComplete?.(Object.freeze(completion));
367
+ } catch (error) {
368
+ fail(error);
369
+ return;
370
+ }
371
+ }
372
+ if (!success) {
373
+ fail(new Error("Pibbl render failed during recording."));
374
+ return;
375
+ }
376
+ if (phase !== "starting" && phase !== "capturing") return;
377
+ pendingRenderGeneration = renderGeneration;
378
+ if (!workerReady) {
379
+ initialize();
380
+ return;
381
+ }
382
+ try {
383
+ capture(renderGeneration);
384
+ } catch (error) {
385
+ fail(error);
386
+ }
387
+ }
388
+ client.onerror = (error) => {
389
+ fail(error);
390
+ client.dispose(error);
391
+ };
392
+ client.onmessage = (data) => {
393
+ if (data.type === "ready") {
394
+ workerReady = true;
395
+ if (!instance || phase !== "starting") return;
396
+ if (instance.committedRenderGeneration && instance.committedRenderGeneration === instance.renderGeneration)
397
+ observe(true, instance.committedRenderGeneration);
398
+ else update(instance.canvas);
399
+ } else if (data.type === "ack") pendingFrames--;
400
+ else if (data.type === "finished" && phase === "finishing") {
401
+ phase = "finished";
402
+ const frames = Object.freeze(metadata.splice(0));
403
+ const result = retainRecording(client, frames, duration);
404
+ resolveFinished(result);
405
+ }
406
+ };
407
+ const session = Object.freeze({
408
+ ready,
409
+ finished,
410
+ stop,
411
+ cancel: () => fail(aborted())
412
+ });
413
+ if (options.signal?.aborted) {
414
+ fail(aborted());
415
+ return session;
416
+ }
417
+ instance.rootFrameObservers ??= /* @__PURE__ */ new Set();
418
+ instance.rootFrameObservers.add(observe);
419
+ recordingResources.observers++;
420
+ instance.mainTeardowns.add(rootDisposed);
421
+ removeAbort = listen(options.signal, () => fail(aborted()));
422
+ if (instance.surface.kind === "root" && (instance.surface.display.width <= 0 || instance.surface.display.height <= 0)) {
423
+ fail(new Error("Recording requires a nonzero display surface."));
424
+ } else if (instance.committedRenderGeneration && instance.committedRenderGeneration === instance.renderGeneration)
425
+ initialize();
426
+ else update(instance.canvas);
427
+ function initialize() {
428
+ if (initializing || phase !== "starting" || !target) return;
429
+ initializing = true;
430
+ width = target.width;
431
+ height = target.height;
432
+ const frameBytes = width * height * 4;
433
+ const estimatedBytes = Math.ceil(
434
+ frameBytes * Math.max(1, Math.ceil(options.duration * frameRate / 1e3)) * headroom
435
+ );
436
+ if (!frameBytes || !Number.isSafeInteger(estimatedBytes) || estimatedBytes > 4278190080) {
437
+ fail(
438
+ new RangeError(
439
+ "Estimated recording exceeds WASM32 addressable storage."
440
+ )
441
+ );
442
+ } else void client.initialize(frameBytes, estimatedBytes).catch(fail);
443
+ }
444
+ return session;
445
+ }
446
+ async function exportGif(recording, options = {}) {
447
+ const client = owners.get(recording);
448
+ if (!client)
449
+ throw new TypeError(
450
+ "exportGif requires a recording returned by recordFrames."
451
+ );
452
+ const frameRate = options.frameRate ?? 25;
453
+ positive(frameRate, "frameRate");
454
+ if (frameRate > 100)
455
+ throw new RangeError("GIF frameRate must not exceed 100.");
456
+ const repeat = options.repeatCount ?? -1;
457
+ if (options.repeatCount !== void 0 && (!Number.isInteger(repeat) || repeat < 0 || repeat > 65535))
458
+ throw new RangeError("repeatCount must be an integer from zero to 65535.");
459
+ const source = recording.frames[0];
460
+ const integer = (value, name, maximum, minimum = 1) => {
461
+ if (!Number.isInteger(value) || value < minimum || value > maximum)
462
+ throw new RangeError(
463
+ `${name} must be an integer from ${minimum} to ${maximum}.`
464
+ );
465
+ return value;
466
+ };
467
+ const width = integer(
468
+ options.width ?? (options.height === void 0 ? source.width : Math.max(
469
+ 1,
470
+ Math.round(source.width * options.height / source.height)
471
+ )),
472
+ "width",
473
+ 65535
474
+ );
475
+ const height = integer(
476
+ options.height ?? (options.width === void 0 ? source.height : Math.max(
477
+ 1,
478
+ Math.round(source.height * options.width / source.width)
479
+ )),
480
+ "height",
481
+ 65535
482
+ );
483
+ if (width * height * 4 > 4278190080)
484
+ throw new RangeError("GIF bitmap exceeds WASM32 memory capacity.");
485
+ const maxColors = integer(options.maxColors ?? 256, "maxColors", 256, 2);
486
+ const quantizationSampleFactor = integer(
487
+ options.quantizationSampleFactor ?? 10,
488
+ "quantizationSampleFactor",
489
+ 30
490
+ );
491
+ const paletteSampleCount = integer(
492
+ options.paletteSampleCount ?? 262144,
493
+ "paletteSampleCount",
494
+ 16777216
495
+ );
496
+ if (options.dithering !== void 0 && typeof options.dithering !== "boolean")
497
+ throw new TypeError("dithering must be a boolean.");
498
+ const opaqueColor = (color, name) => {
499
+ if (typeof color !== "string")
500
+ throw new TypeError(`${name} must be a valid opaque CSS color.`);
501
+ const context = new OffscreenCanvas(1, 1).getContext("2d");
502
+ context.fillStyle = "#010203";
503
+ context.fillStyle = color;
504
+ const first = context.fillStyle;
505
+ context.fillStyle = "#040506";
506
+ context.fillStyle = color;
507
+ if (context.fillStyle !== first)
508
+ throw new TypeError(`${name} must be a valid opaque CSS color.`);
509
+ context.fillRect(0, 0, 1, 1);
510
+ const pixel = context.getImageData(0, 0, 1, 1).data;
511
+ if (pixel[3] !== 255) throw new TypeError(`${name} must be opaque.`);
512
+ return [pixel[0], pixel[1], pixel[2]];
513
+ };
514
+ let background = -1;
515
+ if (options.background !== void 0) {
516
+ const [r, g, b] = opaqueColor(options.background, "background");
517
+ background = r << 16 | g << 8 | b;
518
+ }
519
+ let palette = [];
520
+ if (options.palette !== void 0) {
521
+ if (!Array.isArray(options.palette) || !options.palette.length || options.palette.length > maxColors - (background < 0 ? 1 : 0))
522
+ throw new RangeError(
523
+ "palette must contain opaque colors fitting maxColors (including transparency)."
524
+ );
525
+ palette = options.palette.flatMap(
526
+ (color) => opaqueColor(color, "palette color")
527
+ );
528
+ }
529
+ const buffer = await client.request(
530
+ {
531
+ type: "gif",
532
+ duration: recording.duration,
533
+ width,
534
+ height,
535
+ sourceWidth: source.width,
536
+ sourceHeight: source.height,
537
+ maxColors,
538
+ palette,
539
+ dithering: options.dithering ?? false,
540
+ quantizationSampleFactor,
541
+ paletteSampleCount,
542
+ frameRate,
543
+ repeatCount: repeat,
544
+ background
545
+ },
546
+ options
547
+ );
548
+ return new Blob([buffer], { type: "image/gif" });
549
+ }
550
+ export {
551
+ exportGif,
552
+ recordFrames,
553
+ recordingResources
554
+ };
555
+ //# sourceMappingURL=recording.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/recording/recording.ts"],
4
+ "sourcesContent": ["import { GLOBAL_STATE } from \"../global-state.js\";\nimport { update } from \"../update.js\";\nimport type { Canvas, PibblInstance } from \"../types.js\";\nimport { workerSource } from \"./worker-source.js\";\nimport { bytes } from \"./wasm-bytes.js\";\nimport type {\n PibblFrameRecording,\n PibblFrameRecordingOptions,\n PibblFrameRecordingSession,\n PibblRecordedFrameInfo,\n PibblGifExportOptions,\n PibblRenderCompletion,\n} from \"./types.js\";\n\n/** Private deterministic ownership evidence; not a public diagnostics API. */\nexport const recordingResources = {\n workers: 0,\n urls: 0,\n observers: 0,\n timers: 0,\n abortListeners: 0,\n requests: 0,\n exports: 0,\n};\nconst owners = /* @__PURE__ */ new WeakMap<\n PibblFrameRecording,\n RecordingClient\n>();\nfunction aborted(message = \"Recording cancelled.\"): DOMException {\n return new DOMException(message, \"AbortError\");\n}\nfunction positive(value: number, name: string): void {\n if (!Number.isFinite(value) || value <= 0)\n throw new RangeError(`${name} must be finite and greater than zero.`);\n}\nfunction listen(\n signal: AbortSignal | undefined,\n callback: () => void,\n): () => void {\n if (!signal) return () => {};\n let attached = true;\n signal.addEventListener(\"abort\", callback, { once: true });\n recordingResources.abortListeners++;\n return () => {\n if (!attached) return;\n attached = false;\n signal.removeEventListener(\"abort\", callback);\n recordingResources.abortListeners--;\n };\n}\ninterface Request {\n gif: boolean;\n resolve: (bytes: ArrayBuffer) => void;\n reject: (error: unknown) => void;\n cleanup: () => void;\n progress?: (value: number) => void;\n result?: ArrayBuffer;\n error?: unknown;\n}\nclass RecordingClient {\n worker?: Worker;\n closed = false;\n private url?: string;\n private nextId = 0;\n private pending = new Map<number, Request>();\n private exporting = false;\n onmessage: (data: any) => void = () => {};\n onerror: (error: unknown) => void = () => {};\n\n async initialize(frameBytes: number, estimatedBytes: number): Promise<void> {\n await Promise.resolve();\n if (this.closed) return;\n const source = workerSource;\n this.url = URL.createObjectURL(\n new Blob([source], { type: \"text/javascript\" }),\n );\n recordingResources.urls++;\n try {\n this.worker = new Worker(this.url, { name: \"Pibbl frame recording\" });\n recordingResources.workers++;\n this.worker.onmessage = ({ data }) => {\n if (this.closed) return;\n if (data.type === \"ready\") this.revoke();\n if (data.type === \"fatal\") {\n this.onerror(new Error(data.message));\n return;\n }\n const request = this.pending.get(data.id);\n if (request) {\n if (data.type === \"progress\" && !request.error) {\n try {\n request.progress?.(data.progress);\n } catch (error) {\n this.cancelExport(data.id, error);\n }\n } else if (data.type === \"result\") {\n if (request.gif) request.result = data.buffer;\n else this.settle(data.id, data.buffer);\n } else if (data.type === \"error\") {\n this.settle(data.id, undefined, new Error(data.message));\n } else if (data.type === \"exportReleased\") {\n this.settle(data.id, request.result, request.error);\n }\n }\n this.onmessage(data);\n };\n this.worker.onerror = (event) =>\n this.onerror(new Error(event.message || \"Recording worker failed.\"));\n this.worker.onmessageerror = () =>\n this.onerror(\n new Error(\"Recording worker message could not be decoded.\"),\n );\n const buffer = Uint8Array.from(atob(bytes), (char) =>\n char.charCodeAt(0),\n ).buffer;\n this.send({ type: \"start\", bytes: buffer, frameBytes, estimatedBytes }, [\n buffer,\n ]);\n } catch (error) {\n this.revoke();\n throw error;\n }\n }\n send(data: unknown, transfer: Transferable[] = []): void {\n if (this.closed || !this.worker)\n throw aborted(\"Recording has been disposed.\");\n this.worker.postMessage(data, transfer);\n }\n request(data: any, options?: PibblGifExportOptions): Promise<ArrayBuffer> {\n if (this.closed)\n return Promise.reject(aborted(\"Recording has been disposed.\"));\n if (options?.signal?.aborted)\n return Promise.reject(aborted(\"GIF export cancelled.\"));\n const gif = data.type === \"gif\";\n if (gif && this.exporting)\n return Promise.reject(\n new Error(\"A GIF export is already running for this recording.\"),\n );\n const id = ++this.nextId;\n if (gif) {\n this.exporting = true;\n recordingResources.exports++;\n }\n return new Promise((resolve, reject) => {\n const request: Request = {\n gif,\n resolve,\n reject,\n cleanup: () => {},\n progress: options?.onProgress,\n };\n this.pending.set(id, request);\n recordingResources.requests++;\n request.cleanup = listen(options?.signal, () =>\n this.cancelExport(id, aborted(\"GIF export cancelled.\")),\n );\n try {\n this.send({ ...data, id });\n } catch (error) {\n this.settle(id, undefined, error);\n }\n });\n }\n private cancelExport(id: number, error: unknown): void {\n const request = this.pending.get(id);\n if (!request || request.error) return;\n request.error = error;\n request.cleanup();\n try {\n this.send({ type: \"cancelExport\", id });\n } catch {\n this.settle(id, undefined, error);\n }\n }\n private settle(id: number, result?: ArrayBuffer, error?: unknown): void {\n const request = this.pending.get(id);\n if (!request) return;\n this.pending.delete(id);\n request.cleanup();\n recordingResources.requests--;\n if (request.gif) {\n this.exporting = false;\n recordingResources.exports--;\n }\n if (error !== undefined) request.reject(error);\n else if (result) request.resolve(result);\n else request.reject(new Error(\"Recording worker returned no result.\"));\n }\n private revoke(): void {\n if (!this.url) return;\n URL.revokeObjectURL(this.url);\n this.url = undefined;\n recordingResources.urls--;\n }\n dispose(error: unknown = aborted(\"Recording has been disposed.\")): void {\n if (this.closed) return;\n this.closed = true;\n if (this.worker) {\n this.worker.onmessage =\n this.worker.onerror =\n this.worker.onmessageerror =\n null;\n this.worker.terminate();\n this.worker = undefined;\n recordingResources.workers--;\n }\n this.revoke();\n for (const id of this.pending.keys()) this.settle(id, undefined, error);\n this.onmessage = this.onerror = () => {};\n }\n}\n\n// Completed recording methods capture only their worker and metadata, never\n// the capture session's mount, signal, controls, or lifecycle callbacks.\nfunction retainRecording(\n client: RecordingClient,\n frames: readonly PibblRecordedFrameInfo[],\n duration: number,\n): PibblFrameRecording {\n const result: PibblFrameRecording = Object.freeze({\n duration,\n frames,\n async readFrame(index: number) {\n if (!Number.isInteger(index) || index < 0 || index >= frames.length)\n throw new RangeError(\"Frame index is out of range.\");\n const buffer = await client.request({ type: \"read\", index });\n return { ...frames[index], data: new Uint8ClampedArray(buffer) };\n },\n dispose() {\n client.dispose();\n },\n });\n owners.set(result, client);\n client.onmessage = () => {};\n client.onerror = (error) => client.dispose(error);\n return result;\n}\n\n/**\n * Record committed bitmap frames from any live Pibbl root canvas.\n *\n * Capture uses the existing render lifecycle; it never starts a render loop.\n * Stop retains frames; cancel discards them. Dispose the completed recording\n * after reading or exporting it. Resizing, failed renders, unreadable pixels,\n * allocation failure, and capture queue overflow reject and release the session.\n *\n * @param canvas The canvas belonging to a live Pibbl root mount.\n * @param options Capture duration, maximum frame rate, allocation headroom, and cancellation.\n * @returns Stable controls and promises for one recording session.\n * @see {@link PibblFrameRecordingOptions}\n * @see {@link PibblFrameRecordingSession}\n */\nexport function recordFrames(\n canvas: Canvas,\n options: PibblFrameRecordingOptions,\n): PibblFrameRecordingSession {\n positive(options.duration, \"duration\");\n const frameRate = options.frameRate ?? 60;\n const headroom = options.memoryHeadroom ?? 1.15;\n positive(frameRate, \"frameRate\");\n positive(headroom, \"memoryHeadroom\");\n if (headroom < 1)\n throw new RangeError(\"memoryHeadroom must be at least one.\");\n if (options.duration > 2_147_483_647)\n throw new RangeError(\"duration exceeds the supported timer range.\");\n let instance: PibblInstance | undefined =\n GLOBAL_STATE.pibblInstances.get(canvas);\n if (!instance || instance.parent || instance.mainTeardowns.closed)\n throw new Error(\"recordFrames requires a live Pibbl root canvas.\");\n let target: Canvas | undefined = canvas;\n const client = new RecordingClient();\n const metadata: PibblRecordedFrameInfo[] = [];\n let phase: \"starting\" | \"capturing\" | \"finishing\" | \"finished\" | \"cancelled\" =\n \"starting\";\n let initializing = false;\n let workerReady = false,\n stopRequested = false;\n let started = 0,\n last = -Infinity,\n duration = 0,\n pendingFrames = 0;\n let width = 0,\n height = 0;\n let pendingRenderGeneration = 0;\n let lastNotifiedGeneration = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let sampleTimer: ReturnType<typeof setTimeout> | undefined;\n let removeAbort = () => {};\n let resolveReady!: () => void, rejectReady!: (error: unknown) => void;\n let resolveFinished!: (recording: PibblFrameRecording) => void,\n rejectFinished!: (error: unknown) => void;\n const ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n const finished = new Promise<PibblFrameRecording>((resolve, reject) => {\n resolveFinished = resolve;\n rejectFinished = reject;\n });\n // Cancellation is legitimate even when applications only await one of these promises.\n void ready.catch(() => {});\n void finished.catch(() => {});\n function clearSampleTimer(): void {\n if (sampleTimer === undefined) return;\n clearTimeout(sampleTimer);\n sampleTimer = undefined;\n recordingResources.timers--;\n }\n function detach(): void {\n clearSampleTimer();\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n recordingResources.timers--;\n }\n removeAbort();\n removeAbort = () => {};\n if (instance) {\n instance.mainTeardowns.remove(rootDisposed);\n if (instance.rootFrameObservers?.delete(observe))\n recordingResources.observers--;\n if (!instance.rootFrameObservers?.size)\n instance.rootFrameObservers = undefined;\n }\n instance = undefined;\n target = undefined;\n }\n function fail(error: unknown): void {\n if (phase === \"finished\" || phase === \"cancelled\") return;\n phase = \"cancelled\";\n detach();\n client.dispose(error);\n metadata.length = 0;\n rejectReady(error);\n rejectFinished(error);\n }\n function rootDisposed(): void {\n fail(aborted(\"Pibbl mount disposed during recording.\"));\n }\n function stop(): void {\n if (phase === \"starting\") {\n stopRequested = true;\n return;\n }\n if (phase !== \"capturing\") return;\n duration = Math.min(options.duration, performance.now() - started);\n phase = \"finishing\";\n detach();\n try {\n client.send({ type: \"finish\" });\n } catch (error) {\n fail(error);\n }\n }\n function capture(renderGeneration: number): void {\n if (!target) return;\n if (!Number.isSafeInteger(renderGeneration) || renderGeneration <= 0)\n throw new Error(\"Recording requires a committed render generation.\");\n if (target.width !== width || target.height !== height)\n throw new Error(\"Canvas backing size changed during recording.\");\n const now = performance.now();\n const initial = phase === \"starting\";\n const timestamp = initial ? 0 : now - started;\n if (!initial && timestamp >= options.duration) {\n stop();\n return;\n }\n if (!initial && timestamp - last < 1000 / frameRate) {\n // One pending successful render may be sampled later; no rendering is scheduled.\n // This preserves its final static bitmap when no further renders occur.\n if (sampleTimer === undefined) {\n sampleTimer = setTimeout(\n () => {\n sampleTimer = undefined;\n recordingResources.timers--;\n if (phase !== \"capturing\") return;\n try {\n capture(pendingRenderGeneration);\n } catch (error) {\n fail(error);\n }\n },\n Math.ceil(1000 / frameRate - (timestamp - last)),\n );\n recordingResources.timers++;\n }\n return;\n }\n clearSampleTimer();\n if (pendingFrames >= 3)\n throw new Error(\n \"Recording capture queue overflow; no frames were silently dropped.\",\n );\n const context = target.getContext(\"2d\") as\n CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\n if (!context)\n throw new Error(\"Recording requires a readable Canvas 2D surface.\");\n const pixels = context.getImageData(0, 0, width, height);\n client.send({ type: \"frame\", timestamp, buffer: pixels.data.buffer }, [\n pixels.data.buffer,\n ]);\n pendingFrames++;\n const info = Object.freeze({ timestamp, width, height, renderGeneration });\n metadata.push(info);\n options.onFrameCaptured?.(info);\n // Callbacks may release the session while its first capture is initializing.\n if (phase !== \"starting\" && phase !== \"capturing\") return;\n last = timestamp;\n if (initial) {\n started = now;\n phase = \"capturing\";\n timer = setTimeout(stop, options.duration);\n recordingResources.timers++;\n resolveReady();\n if (stopRequested) stop();\n }\n }\n function observe(success: boolean, renderGeneration: number): void {\n if (phase === \"finished\" || phase === \"cancelled\") return;\n if (renderGeneration > lastNotifiedGeneration) {\n lastNotifiedGeneration = renderGeneration;\n const completion: PibblRenderCompletion = success\n ? { status: \"committed\", generation: renderGeneration }\n : { status: \"failed\", generation: renderGeneration };\n try {\n options.onRenderComplete?.(Object.freeze(completion));\n } catch (error) {\n fail(error);\n return;\n }\n }\n if (!success) {\n fail(new Error(\"Pibbl render failed during recording.\"));\n return;\n }\n if (phase !== \"starting\" && phase !== \"capturing\") return;\n pendingRenderGeneration = renderGeneration;\n if (!workerReady) {\n initialize();\n return;\n }\n try {\n capture(renderGeneration);\n } catch (error) {\n fail(error);\n }\n }\n client.onerror = (error) => {\n fail(error);\n client.dispose(error);\n };\n client.onmessage = (data) => {\n if (data.type === \"ready\") {\n workerReady = true;\n if (!instance || phase !== \"starting\") return;\n if (\n instance.committedRenderGeneration &&\n instance.committedRenderGeneration === instance.renderGeneration\n )\n observe(true, instance.committedRenderGeneration);\n else update(instance.canvas);\n } else if (data.type === \"ack\") pendingFrames--;\n else if (data.type === \"finished\" && phase === \"finishing\") {\n phase = \"finished\";\n const frames = Object.freeze(metadata.splice(0));\n const result = retainRecording(client, frames, duration);\n resolveFinished(result);\n }\n };\n const session = Object.freeze({\n ready,\n finished,\n stop,\n cancel: () => fail(aborted()),\n });\n if (options.signal?.aborted) {\n fail(aborted());\n return session;\n }\n instance.rootFrameObservers ??= new Set();\n instance.rootFrameObservers.add(observe);\n recordingResources.observers++;\n instance.mainTeardowns.add(rootDisposed);\n removeAbort = listen(options.signal, () => fail(aborted()));\n if (\n instance.surface.kind === \"root\" &&\n (instance.surface.display.width <= 0 ||\n instance.surface.display.height <= 0)\n ) {\n fail(new Error(\"Recording requires a nonzero display surface.\"));\n } else if (\n instance.committedRenderGeneration &&\n instance.committedRenderGeneration === instance.renderGeneration\n )\n initialize();\n else update(instance.canvas);\n function initialize(): void {\n if (initializing || phase !== \"starting\" || !target) return;\n initializing = true;\n width = target!.width;\n height = target!.height;\n const frameBytes = width * height * 4;\n const estimatedBytes = Math.ceil(\n frameBytes *\n Math.max(1, Math.ceil((options.duration * frameRate) / 1000)) *\n headroom,\n );\n if (\n !frameBytes ||\n !Number.isSafeInteger(estimatedBytes) ||\n estimatedBytes > 0xff000000\n ) {\n fail(\n new RangeError(\n \"Estimated recording exceeds WASM32 addressable storage.\",\n ),\n );\n } else void client.initialize(frameBytes, estimatedBytes).catch(fail);\n }\n return session;\n}\n\n/**\n * Encode a retained recording to an image/gif Blob in its worker's WASM encoder.\n *\n * Pixels remain worker-owned. Cancellation stops encoding and preserves the\n * recording; disposing the recording cancels all pending reads and exports.\n * GIF timing is rounded cumulatively to 10ms units. Without an opaque background,\n * alpha below 128 is transparent and other pixels are opaque. Only one export\n * per recording may run at a time. Requires workers, WebAssembly, and blob-worker CSP permission.\n *\n * @param recording Retained frames returned by recordFrames.\n * @param options Output dimensions, palette, dithering, sampling, looping, background, progress, and cancellation.\n * @returns Encoded GIF bytes as a caller-owned Blob.\n * @see {@link PibblGifExportOptions}\n * @see {@link PibblFrameRecording}\n */\nexport async function exportGif(\n recording: PibblFrameRecording,\n options: PibblGifExportOptions = {},\n): Promise<Blob> {\n const client = owners.get(recording);\n if (!client)\n throw new TypeError(\n \"exportGif requires a recording returned by recordFrames.\",\n );\n const frameRate = options.frameRate ?? 25;\n positive(frameRate, \"frameRate\");\n if (frameRate > 100)\n throw new RangeError(\"GIF frameRate must not exceed 100.\");\n const repeat = options.repeatCount ?? -1;\n if (\n options.repeatCount !== undefined &&\n (!Number.isInteger(repeat) || repeat < 0 || repeat > 65535)\n )\n throw new RangeError(\"repeatCount must be an integer from zero to 65535.\");\n const source = recording.frames[0];\n const integer = (\n value: number,\n name: string,\n maximum: number,\n minimum = 1,\n ) => {\n if (!Number.isInteger(value) || value < minimum || value > maximum)\n throw new RangeError(\n `${name} must be an integer from ${minimum} to ${maximum}.`,\n );\n return value;\n };\n const width = integer(\n options.width ??\n (options.height === undefined\n ? source.width\n : Math.max(\n 1,\n Math.round((source.width * options.height) / source.height),\n )),\n \"width\",\n 65535,\n );\n const height = integer(\n options.height ??\n (options.width === undefined\n ? source.height\n : Math.max(\n 1,\n Math.round((source.height * options.width) / source.width),\n )),\n \"height\",\n 65535,\n );\n if (width * height * 4 > 0xff000000)\n throw new RangeError(\"GIF bitmap exceeds WASM32 memory capacity.\");\n const maxColors = integer(options.maxColors ?? 256, \"maxColors\", 256, 2);\n const quantizationSampleFactor = integer(\n options.quantizationSampleFactor ?? 10,\n \"quantizationSampleFactor\",\n 30,\n );\n const paletteSampleCount = integer(\n options.paletteSampleCount ?? 262144,\n \"paletteSampleCount\",\n 16777216,\n );\n if (options.dithering !== undefined && typeof options.dithering !== \"boolean\")\n throw new TypeError(\"dithering must be a boolean.\");\n const opaqueColor = (color: string, name: string) => {\n if (typeof color !== \"string\")\n throw new TypeError(`${name} must be a valid opaque CSS color.`);\n const context = new OffscreenCanvas(1, 1).getContext(\"2d\")!;\n context.fillStyle = \"#010203\";\n context.fillStyle = color;\n const first = context.fillStyle;\n context.fillStyle = \"#040506\";\n context.fillStyle = color;\n if (context.fillStyle !== first)\n throw new TypeError(`${name} must be a valid opaque CSS color.`);\n context.fillRect(0, 0, 1, 1);\n const pixel = context.getImageData(0, 0, 1, 1).data;\n if (pixel[3] !== 255) throw new TypeError(`${name} must be opaque.`);\n return [pixel[0], pixel[1], pixel[2]];\n };\n let background = -1;\n if (options.background !== undefined) {\n const [r, g, b] = opaqueColor(options.background, \"background\");\n background = (r << 16) | (g << 8) | b;\n }\n let palette: number[] = [];\n if (options.palette !== undefined) {\n if (\n !Array.isArray(options.palette) ||\n !options.palette.length ||\n options.palette.length > maxColors - (background < 0 ? 1 : 0)\n )\n throw new RangeError(\n \"palette must contain opaque colors fitting maxColors (including transparency).\",\n );\n palette = options.palette.flatMap((color) =>\n opaqueColor(color, \"palette color\"),\n );\n }\n const buffer = await client.request(\n {\n type: \"gif\",\n duration: recording.duration,\n width,\n height,\n sourceWidth: source.width,\n sourceHeight: source.height,\n maxColors,\n palette,\n dithering: options.dithering ?? false,\n quantizationSampleFactor,\n paletteSampleCount,\n frameRate,\n repeatCount: repeat,\n background,\n },\n options,\n );\n return new Blob([buffer], { type: \"image/gif\" });\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }