visualproof 0.1.0 → 0.3.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.
- package/README.md +40 -26
- package/dist/assets/webfonts/LICENSE-Jost.txt +93 -0
- package/dist/assets/webfonts/LICENSE-Noto.txt +95 -0
- package/dist/assets/webfonts/LICENSE-SourceSans3.txt +93 -0
- package/dist/assets/webfonts/LICENSE-SourceSerif4.txt +93 -0
- package/dist/assets/webfonts/jost-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/jost-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/metrics.json +1 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-sans-3-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-greek-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-ext-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-italic.woff2 +0 -0
- package/dist/assets/webfonts/source-serif-4-latin-wght-normal.woff2 +0 -0
- package/dist/assets/webfonts/ttf/jost-400-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/jost-500-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/noto-sans-math.ttf +0 -0
- package/dist/assets/webfonts/ttf/noto-sans.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-400-italic.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-400-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-500-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-600-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-sans-3-700-normal.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-serif-4-400-italic.ttf +0 -0
- package/dist/assets/webfonts/ttf/source-serif-4-600-italic.ttf +0 -0
- package/dist/server/agent.js +125 -92
- package/dist/server/agentdocs.js +1 -1
- package/dist/server/artcmd.js +335 -0
- package/dist/server/history.js +39 -0
- package/dist/server/historyapi.js +2 -2
- package/dist/server/hover.js +3 -3
- package/dist/server/layoutthread.js +1 -1
- package/dist/server/live.js +6 -0
- package/dist/server/main.js +151 -11
- package/dist/server/mcptools.js +6 -4
- package/dist/server/pastdoc.js +1 -1
- package/dist/server/pipeline.js +18 -9
- package/dist/server/readonlygate.js +2 -2
- package/dist/server/review.js +4 -1
- package/dist/server/reviewapi.js +35 -1
- package/dist/server/snapshot.js +13 -3
- package/dist/server/usage.js +2 -2
- package/dist/server/views.js +25 -1
- package/dist/shared/artfonts.js +81 -0
- package/dist/shared/artrecipe.js +316 -0
- package/dist/shared/collab.js +99 -1
- package/dist/shared/declfind.js +95 -0
- package/dist/shared/doc/order.js +17 -0
- package/dist/shared/doc/outline.js +45 -0
- package/dist/shared/keys.js +1 -1
- package/dist/shared/lostfound.js +1 -0
- package/dist/shared/moves.js +2 -1
- package/dist/shared/pastgraph.js +9 -1
- package/dist/shared/query.js +21 -13
- package/dist/shared/review.js +62 -5
- package/dist/shared/sharesnap.js +2 -1
- package/dist/shared/titles.js +2 -0
- package/dist/shared/viewgraph.js +18 -0
- package/dist/web/bundle/app.js +7709 -3222
- package/dist/web/bundle/edges.js +4 -6
- package/dist/web/index.html +24 -6
- package/dist/web/src/agentmark.js +14 -0
- package/dist/web/src/artwork.js +1000 -0
- package/dist/web/src/bundles.js +151 -0
- package/dist/web/src/canvas.js +3694 -0
- package/dist/web/src/drag.js +61 -0
- package/dist/web/src/edgequeue.js +204 -0
- package/dist/web/src/gl/gl.js +123 -0
- package/dist/web/src/gl/renderer.js +451 -0
- package/dist/web/src/halo.js +95 -0
- package/dist/web/src/highlight.js +108 -0
- package/dist/web/src/overview.js +393 -0
- package/dist/web/src/reviewqueue.js +250 -0
- package/dist/web/src/scene.js +17 -0
- package/dist/web/src/selection.js +272 -0
- package/dist/web/src/status.js +80 -0
- package/dist/web/src/visitors.js +318 -0
- package/dist/web/src/visits.js +174 -0
- package/dist/web/style.css +255 -12
- package/docs/agent-api/README.md +1 -1
- package/docs/agent-api/export.md +41 -2
- package/docs/agent-api/following.md +2 -2
- package/docs/agent-api/history.md +2 -1
- package/docs/agent-api/mcp.md +1 -1
- package/docs/agent-api/reading.md +2 -1
- package/docs/agent-api/views.md +3 -2
- package/package.json +3 -1
- package/test/toolchains.json +2 -2
|
@@ -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
|
+
}
|