visualproof 0.2.0 → 0.4.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 (96) hide show
  1. package/README.md +88 -33
  2. package/dist/assets/tips/phone-fingers.light.mp4 +0 -0
  3. package/dist/assets/tips/phone-fingers.light.webp +0 -0
  4. package/dist/assets/tips/tour-agent.webp +0 -0
  5. package/dist/assets/tips/tour-arrange.webp +0 -0
  6. package/dist/assets/tips/tour-artwork.webp +0 -0
  7. package/dist/assets/tips/tour-checks.webp +0 -0
  8. package/dist/assets/tips/tour-export.webp +0 -0
  9. package/dist/assets/tips/tour-keys.webp +0 -0
  10. package/dist/assets/tips/tour-library.webp +0 -0
  11. package/dist/assets/tips/tour-project.webp +0 -0
  12. package/dist/assets/tips/tour-review.webp +0 -0
  13. package/dist/assets/tips/tour-share.webp +0 -0
  14. package/dist/assets/tips/tour-source.webp +0 -0
  15. package/dist/assets/tips/tour-target.webp +0 -0
  16. package/dist/assets/tips/tour-view.webp +0 -0
  17. package/dist/assets/tips/tour.json +289 -0
  18. package/dist/assets/tips/tour.webp +0 -0
  19. package/dist/assets/webfonts/LICENSE-Noto.txt +95 -0
  20. package/dist/assets/webfonts/metrics.json +1 -0
  21. package/dist/assets/webfonts/ttf/jost-400-normal.ttf +0 -0
  22. package/dist/assets/webfonts/ttf/jost-500-normal.ttf +0 -0
  23. package/dist/assets/webfonts/ttf/noto-sans-math.ttf +0 -0
  24. package/dist/assets/webfonts/ttf/noto-sans.ttf +0 -0
  25. package/dist/assets/webfonts/ttf/source-sans-3-400-italic.ttf +0 -0
  26. package/dist/assets/webfonts/ttf/source-sans-3-400-normal.ttf +0 -0
  27. package/dist/assets/webfonts/ttf/source-sans-3-500-normal.ttf +0 -0
  28. package/dist/assets/webfonts/ttf/source-sans-3-600-normal.ttf +0 -0
  29. package/dist/assets/webfonts/ttf/source-sans-3-700-normal.ttf +0 -0
  30. package/dist/assets/webfonts/ttf/source-serif-4-400-italic.ttf +0 -0
  31. package/dist/assets/webfonts/ttf/source-serif-4-600-italic.ttf +0 -0
  32. package/dist/mcp/visualproof-mcp.mjs +3 -1
  33. package/dist/server/agent.js +94 -91
  34. package/dist/server/agentdocs.js +1 -1
  35. package/dist/server/artcmd.js +335 -0
  36. package/dist/server/children.js +85 -0
  37. package/dist/server/doctor.js +105 -42
  38. package/dist/server/events.js +10 -0
  39. package/dist/server/export.js +11 -4
  40. package/dist/server/extract.js +3 -2
  41. package/dist/server/figures.js +3 -2
  42. package/dist/server/film.js +380 -0
  43. package/dist/server/history.js +11 -1
  44. package/dist/server/hover.js +8 -5
  45. package/dist/server/live.js +72 -9
  46. package/dist/server/main.js +352 -23
  47. package/dist/server/mcptools.js +4 -1
  48. package/dist/server/media.js +114 -0
  49. package/dist/server/pipeline.js +21 -10
  50. package/dist/server/poppler.js +3 -2
  51. package/dist/server/readonlygate.js +4 -4
  52. package/dist/server/review.js +4 -1
  53. package/dist/server/reviewapi.js +35 -1
  54. package/dist/server/snapshot.js +10 -1
  55. package/dist/server/sourcestore.js +3 -2
  56. package/dist/server/status.js +3 -2
  57. package/dist/server/supervise.js +219 -0
  58. package/dist/server/updates.js +951 -0
  59. package/dist/server/usage.js +3 -1
  60. package/dist/server/version.js +183 -0
  61. package/dist/server/view.js +0 -7
  62. package/dist/server/views.js +24 -0
  63. package/dist/shared/artfonts.js +81 -0
  64. package/dist/shared/artrecipe.js +316 -0
  65. package/dist/shared/collab.js +7 -2
  66. package/dist/shared/declfind.js +95 -0
  67. package/dist/shared/lostfound.js +1 -0
  68. package/dist/shared/pastgraph.js +6 -6
  69. package/dist/shared/review.js +62 -5
  70. package/dist/shared/timeline.js +5 -0
  71. package/dist/web/bundle/app.js +3006 -413
  72. package/dist/web/bundle/edges.js +1 -1
  73. package/dist/web/index.html +13 -1
  74. package/dist/web/src/agentmark.js +14 -0
  75. package/dist/web/src/artwork.js +1000 -0
  76. package/dist/web/src/bundles.js +151 -0
  77. package/dist/web/src/canvas.js +3716 -0
  78. package/dist/web/src/drag.js +61 -0
  79. package/dist/web/src/edgequeue.js +204 -0
  80. package/dist/web/src/gl/gl.js +123 -0
  81. package/dist/web/src/gl/renderer.js +451 -0
  82. package/dist/web/src/halo.js +95 -0
  83. package/dist/web/src/highlight.js +108 -0
  84. package/dist/web/src/overview.js +393 -0
  85. package/dist/web/src/reviewqueue.js +250 -0
  86. package/dist/web/src/selection.js +272 -0
  87. package/dist/web/src/status.js +80 -0
  88. package/dist/web/src/visitors.js +318 -0
  89. package/dist/web/src/visits.js +174 -0
  90. package/dist/web/style.css +196 -1
  91. package/docs/agent-api/README.md +1 -1
  92. package/docs/agent-api/export.md +41 -2
  93. package/docs/agent-api/history.md +5 -3
  94. package/docs/agent-api/mcp.md +1 -1
  95. package/docs/agent-api/reading.md +2 -1
  96. package/package.json +5 -1
@@ -0,0 +1,151 @@
1
+ // Hierarchical edge bundling (CanvasSpec.md, "Edges"; Holten 2006).
2
+ //
3
+ // An edge's control points are the cluster origins on its tree path: up from one end to the
4
+ // lowest common ancestor, and down to the other. Dependencies that travel the same way through
5
+ // the hierarchy share control points and run together as a bundle.
6
+ //
7
+ // Ends are "units": what an edge end stands for on screen right now. A declaration is its own
8
+ // unit, unless it sits in a cluster that is folded, or too small on screen to tell apart from its
9
+ // siblings — then that cluster is the unit, and every edge into it is aggregated. Zoomed out the
10
+ // overview shows which parts of the project depend on which; zoomed in, which declarations do.
11
+ //
12
+ // Position ids, shared with the positions texture: cluster c → c, node i → nc + i.
13
+ const MAX_POINTS = 8;
14
+ /** Each node's unit (a position id): itself, or the outermost cluster above it that is shut or
15
+ * smaller than `minPx` on screen. */
16
+ export function units(S, k, minPx) {
17
+ const cu = new Int32Array(S.nc).fill(-1);
18
+ for (let c = 0; c < S.nc; c++) {
19
+ const p = S.parent[c];
20
+ if (p >= 0 && cu[p] >= 0)
21
+ cu[c] = cu[p];
22
+ else if (S.rep[c] === c || S.curR[c] * k < minPx)
23
+ cu[c] = c;
24
+ }
25
+ const out = new Int32Array(S.n);
26
+ for (let i = 0; i < S.n; i++) {
27
+ const c = S.nodeCluster[i];
28
+ out[i] = c >= 0 && cu[c] >= 0 ? cu[c] : S.nc + i;
29
+ }
30
+ return out;
31
+ }
32
+ /** Edges between units, counted. `keep` filters nodes (hidden externals, say). */
33
+ export function aggregate(g, unit, sites, keep) {
34
+ const counts = new Map();
35
+ const W = 1 << 22;
36
+ for (let u = 0; u < g.n; u++) {
37
+ if (!keep(u))
38
+ continue;
39
+ const a = unit[u];
40
+ for (let e = g.outStart[u]; e < g.outStart[u + 1]; e++) {
41
+ if (!(g.outSite[e] & sites))
42
+ continue;
43
+ const v = g.outDst[e];
44
+ if (!keep(v))
45
+ continue;
46
+ const b = unit[v];
47
+ if (a === b)
48
+ continue;
49
+ const key = a * W + b;
50
+ counts.set(key, (counts.get(key) ?? 0) + 1);
51
+ }
52
+ }
53
+ const n = counts.size;
54
+ const out = { n, a: new Int32Array(n), b: new Int32Array(n), w: new Int32Array(n) };
55
+ let k = 0;
56
+ for (const [key, w] of counts) {
57
+ const a = Math.floor(key / W);
58
+ out.a[k] = a;
59
+ out.b[k] = key - a * W;
60
+ out.w[k] = w;
61
+ k++;
62
+ }
63
+ return out;
64
+ }
65
+ /** Indices of the `cap` highest scores among `idx` (all of them if there are fewer), in no
66
+ * particular order. Linear time: a selection, not a sort. */
67
+ export function topK(idx, score, cap) {
68
+ const n = idx.length;
69
+ if (n <= cap)
70
+ return idx;
71
+ const s = new Float64Array(n);
72
+ for (let k = 0; k < n; k++)
73
+ s[k] = score[idx[k]];
74
+ // the (n - cap)-th smallest score is the threshold (Hoare's quickselect)
75
+ const want = n - cap;
76
+ let lo = 0, hi = n - 1;
77
+ while (lo < hi) {
78
+ const pivot = s[(lo + hi) >> 1];
79
+ let i = lo, j = hi;
80
+ while (i <= j) {
81
+ while (s[i] < pivot)
82
+ i++;
83
+ while (s[j] > pivot)
84
+ j--;
85
+ if (i <= j) {
86
+ const t = s[i];
87
+ s[i] = s[j];
88
+ s[j] = t;
89
+ i++;
90
+ j--;
91
+ }
92
+ }
93
+ if (want <= j)
94
+ hi = j;
95
+ else if (want >= i)
96
+ lo = i;
97
+ else
98
+ break;
99
+ }
100
+ const threshold = s[want];
101
+ const out = new Int32Array(cap);
102
+ let m = 0;
103
+ for (let k = 0; k < n && m < cap; k++)
104
+ if (score[idx[k]] > threshold)
105
+ out[m++] = idx[k];
106
+ for (let k = 0; k < n && m < cap; k++)
107
+ if (score[idx[k]] === threshold)
108
+ out[m++] = idx[k];
109
+ return out;
110
+ }
111
+ /** The control points from one end to the other through the tree, at most MAX_POINTS. */
112
+ export function pathOf(S, a, b) {
113
+ const chain = (id) => {
114
+ const out = [id];
115
+ let c = id < S.nc ? S.parent[id] : S.nodeCluster[id - S.nc];
116
+ while (c >= 0) {
117
+ out.push(c);
118
+ c = S.parent[c];
119
+ }
120
+ return out;
121
+ };
122
+ return joinChains(chain(a), chain(b));
123
+ }
124
+ /** The control points between two ends, each given with its chain of ancestors up to the top level
125
+ * (`ca[0]` and `cb[0]` the ends): up to the common ancestor, through it, down to the other end, at
126
+ * most MAX_POINTS. A visitor's chain runs through its temporary clusters (ViewSpec decision 27). */
127
+ export function joinChains(ca, cb) {
128
+ const inB = new Map();
129
+ cb.forEach((x, k) => inB.set(x, k));
130
+ let path;
131
+ const ka = ca.findIndex((x) => inB.has(x));
132
+ if (ka >= 0) {
133
+ const kb = inB.get(ca[ka]);
134
+ // up to the common ancestor, through it, down to the other end
135
+ path = [...ca.slice(0, ka + 1), ...cb.slice(0, kb).reverse()];
136
+ // an end that is the ancestor itself (an edge into its own cluster) is just a short hop
137
+ if (path.length < 2)
138
+ path = [ca[0], cb[0]];
139
+ }
140
+ else {
141
+ path = [...ca, ...[...cb].reverse()];
142
+ }
143
+ if (path.length > MAX_POINTS) {
144
+ const keep = [path[0]];
145
+ for (let k = 1; k < MAX_POINTS - 1; k++)
146
+ keep.push(path[Math.round((k * (path.length - 1)) / (MAX_POINTS - 1))]);
147
+ keep.push(path[path.length - 1]);
148
+ path = keep;
149
+ }
150
+ return path;
151
+ }