blockyard 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +929 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +4 -0
  4. package/README.md +191 -4
  5. package/SECURITY.md +38 -0
  6. package/bin/blockyard.js +41 -0
  7. package/config/pool-map.json +2620 -0
  8. package/docs/API.md +1577 -0
  9. package/docs/ARCHITECTURE.md +1394 -0
  10. package/docs/AUTO-UPDATE.md +269 -0
  11. package/docs/CONFIGURATION.md +847 -0
  12. package/docs/DEFECTS.md +813 -0
  13. package/docs/EFFECTS-AGENTS.md +448 -0
  14. package/docs/GETTING-STARTED.md +205 -0
  15. package/docs/INSTALL.md +547 -0
  16. package/docs/MEASUREMENTS.md +1401 -0
  17. package/docs/RULES.md +681 -0
  18. package/docs/SECURITY-AUDIT-2026-09-14.md +177 -0
  19. package/docs/SECURITY-AUDIT.md +258 -0
  20. package/docs/SECURITY.md +212 -0
  21. package/docs/TROUBLESHOOTING.md +332 -0
  22. package/docs/USER-GUIDE.md +1262 -0
  23. package/package.json +53 -5
  24. package/public/404.html +9 -0
  25. package/public/css/app.css +2009 -0
  26. package/public/donate-qr.png +0 -0
  27. package/public/index.html +1085 -0
  28. package/public/js/about.js +112 -0
  29. package/public/js/agents.js +1141 -0
  30. package/public/js/app.js +1386 -0
  31. package/public/js/arkanoid.js +806 -0
  32. package/public/js/blockanoid.js +347 -0
  33. package/public/js/blockout.js +347 -0
  34. package/public/js/blockpack.js +428 -0
  35. package/public/js/blockscene3d.js +2830 -0
  36. package/public/js/breakout.js +224 -0
  37. package/public/js/charts.js +635 -0
  38. package/public/js/depthchart.js +315 -0
  39. package/public/js/details3d.js +4342 -0
  40. package/public/js/doom.js +31 -0
  41. package/public/js/dosaudio.js +48 -0
  42. package/public/js/dosgame.js +389 -0
  43. package/public/js/dosio.js +186 -0
  44. package/public/js/dospc.js +1353 -0
  45. package/public/js/dosworker.js +196 -0
  46. package/public/js/explorer.js +405 -0
  47. package/public/js/feepalette.js +149 -0
  48. package/public/js/fmt.js +162 -0
  49. package/public/js/goggles.js +886 -0
  50. package/public/js/kiosk.js +41 -0
  51. package/public/js/login.js +88 -0
  52. package/public/js/markets.js +395 -0
  53. package/public/js/mining.js +1416 -0
  54. package/public/js/panels.js +970 -0
  55. package/public/js/pricechart.js +189 -0
  56. package/public/js/quake.js +20 -0
  57. package/public/js/settings.js +1096 -0
  58. package/public/js/soundcard.js +459 -0
  59. package/public/js/tetris.js +226 -0
  60. package/public/js/tetrust.js +356 -0
  61. package/public/js/tetsound.js +175 -0
  62. package/public/js/theme.js +235 -0
  63. package/public/js/wolf3d.js +22 -0
  64. package/public/js/x86.js +1978 -0
  65. package/public/login.html +33 -0
  66. package/scripts/blockfile-measure.js +156 -0
  67. package/scripts/browser-check.mjs +286 -0
  68. package/scripts/check.js +173 -0
  69. package/scripts/decode-check.js +81 -0
  70. package/scripts/doc-counts.js +109 -0
  71. package/scripts/donate-qr.py +23 -0
  72. package/scripts/dos-bench.js +56 -0
  73. package/scripts/fake-node.js +534 -0
  74. package/scripts/index-bench.js +216 -0
  75. package/scripts/index-benchmark.js +117 -0
  76. package/scripts/index-build.js +40 -0
  77. package/scripts/live-render-check.mjs +89 -0
  78. package/scripts/manage-users.js +132 -0
  79. package/scripts/motion-check.mjs +138 -0
  80. package/scripts/pool-map.js +157 -0
  81. package/scripts/setup.js +432 -0
  82. package/scripts/shots.mjs +278 -0
  83. package/scripts/smoke.sh +327 -0
  84. package/scripts/tls.js +31 -0
  85. package/scripts/ui.js +174 -0
  86. package/server/auth/sessions.js +221 -0
  87. package/server/auth/users.js +243 -0
  88. package/server/chain/blockfile.js +234 -0
  89. package/server/chain/index/build.js +210 -0
  90. package/server/chain/index/heights.js +36 -0
  91. package/server/chain/index/live.js +276 -0
  92. package/server/chain/index/rows.js +145 -0
  93. package/server/chain/index/store.js +154 -0
  94. package/server/chain/index/worker.js +109 -0
  95. package/server/chain/tx.js +310 -0
  96. package/server/collect/gbt.js +229 -0
  97. package/server/collect/logparse.js +765 -0
  98. package/server/collect/logtail.js +189 -0
  99. package/server/collect/markets.js +333 -0
  100. package/server/collect/mining.js +333 -0
  101. package/server/collect/monitor.js +2545 -0
  102. package/server/collect/network.js +295 -0
  103. package/server/collect/nextblock.js +275 -0
  104. package/server/collect/sync.js +386 -0
  105. package/server/config.js +644 -0
  106. package/server/http/api.js +1319 -0
  107. package/server/http/explorer.js +418 -0
  108. package/server/http/games.js +77 -0
  109. package/server/http/server.js +420 -0
  110. package/server/http/sse.js +176 -0
  111. package/server/http/static.js +212 -0
  112. package/server/main.js +673 -0
  113. package/server/netinfo.js +253 -0
  114. package/server/rpc/allowlist.js +130 -0
  115. package/server/rpc/client.js +414 -0
  116. package/server/store/audit.js +148 -0
  117. package/server/store/history.js +220 -0
  118. package/server/store/ledger.js +290 -0
  119. package/server/store/ring.js +173 -0
  120. package/server/tls/selfsigned.js +160 -0
  121. package/server/util/fmt.js +29 -0
  122. package/systemd/blockyard.service +102 -0
@@ -0,0 +1,189 @@
1
+ // THE PRICE CHART (operator, 2026-09-11, on the first Markets tab -- rows of towers on the 3D
2
+ // board with no axis at all: "What the fuck is this? Where is the price chart info?!??").
3
+ // A price chart has to be READ: a price axis, a time axis, candles, volume, the last price, and a
4
+ // crosshair that says exactly what an hour did. This is that chart. The 3D board under it is a
5
+ // view of the same hours, not a substitute for it.
6
+ import { niceTicks } from './charts.js';
7
+ import { INK } from './theme.js'; // the axis, grid and tooltip colours of the chosen theme
8
+
9
+ export const EX_COLORS = { coinbase: '#4c8dff', kraken: '#a78bfa', bitstamp: '#2ecc8f', bitfinex: '#4dd0e1', okx: '#f0b429' };
10
+ const UP = '#26c281', DOWN = '#ef5350';
11
+ const UP_V = 'rgba(38,194,129,0.42)', DOWN_V = 'rgba(239,83,80,0.42)';
12
+ const PAD = { top: 28, right: 78, bottom: 22, left: 10 };
13
+ const MON = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
14
+ const H1 = 3600e3;
15
+
16
+ const money = (v, dp = 2) => (v == null || !Number.isFinite(v) ? '–' : v.toLocaleString('en-US', { minimumFractionDigits: dp, maximumFractionDigits: dp }));
17
+ const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
18
+ const stamp = (t) => { const d = new Date(t); return `${MON[d.getUTCMonth()]} ${d.getUTCDate()} ${String(d.getUTCHours()).padStart(2, '0')}:${String(d.getUTCMinutes()).padStart(2, '0')}`; };
19
+
20
+ // Pure: where everything goes. candles oldest first; overlays [{ candles }] only widen the scale.
21
+ export function layoutChart(candles, overlays, w, h) {
22
+ const n = candles.length;
23
+ const plotW = Math.max(10, w - PAD.left - PAD.right);
24
+ const plotH = Math.max(40, h - PAD.top - PAD.bottom);
25
+ const volH = Math.round(plotH * 0.2);
26
+ const priceH = plotH - volH - 8;
27
+ const t0 = candles[0]?.t ?? 0, t1 = candles.at(-1)?.t ?? 0;
28
+ let lo = Infinity, hi = -Infinity;
29
+ for (const k of candles) { lo = Math.min(lo, k.l ?? k.c); hi = Math.max(hi, k.h ?? k.c); }
30
+ for (const o of overlays ?? []) for (const k of o.candles) if (k.t >= t0 && k.t <= t1) { lo = Math.min(lo, k.c); hi = Math.max(hi, k.c); }
31
+ const padV = (hi - lo) * 0.06 || Math.abs(hi) * 0.001 || 1;
32
+ lo -= padV; hi += padV;
33
+ const vmax = Math.max(1e-9, ...candles.map((k) => k.v ?? 0));
34
+ const slot = plotW / Math.max(1, n);
35
+ const step = n > 1 ? (t1 - t0) / (n - 1) : H1;
36
+ const X = (i) => PAD.left + slot * (i + 0.5);
37
+ const XT = (t) => X((t - t0) / step);
38
+ const Y = (v) => PAD.top + priceH - ((v - lo) / (hi - lo)) * priceH;
39
+ const V = (y) => lo + (1 - (y - PAD.top) / priceH) * (hi - lo);
40
+ const VY0 = PAD.top + priceH + 8 + volH;
41
+ const VH = (v) => ((v ?? 0) / vmax) * volH;
42
+ const index = (x) => clamp(Math.round((x - PAD.left) / slot - 0.5), 0, Math.max(0, n - 1));
43
+ return { n, plotW, plotH, priceH, volH, lo, hi, slot, t0, t1, step, X, XT, Y, V, VY0, VH, index, w, h };
44
+ }
45
+
46
+ // Whole UTC hours, as far apart as the width can label (~80 px); midnight carries the date.
47
+ export function timeTicks(t0, t1, plotW) {
48
+ const span = Math.max(H1, t1 - t0);
49
+ const step = [1, 2, 3, 6, 12, 24, 48, 96].map((x) => x * H1).find((s) => plotW / (span / s) >= 80) ?? 96 * H1;
50
+ const out = [];
51
+ for (let t = Math.ceil(t0 / step) * step; t <= t1; t += step) {
52
+ const d = new Date(t);
53
+ out.push({ t, label: d.getUTCHours() === 0 ? `${MON[d.getUTCMonth()]} ${d.getUTCDate()}` : `${String(d.getUTCHours()).padStart(2, '0')}:00` });
54
+ }
55
+ return out;
56
+ }
57
+
58
+ export function readout(k, name) {
59
+ const ch = k.o ? (k.c - k.o) / k.o : null;
60
+ return `${name} · ${stamp(k.t)} UTC O ${money(k.o)} H ${money(k.h)} L ${money(k.l)} C ${money(k.c)} ${ch == null ? '' : `${ch >= 0 ? '+' : ''}${(ch * 100).toFixed(2)}%`} vol ${k.v == null ? '–' : money(k.v, 0)} BTC`;
61
+ }
62
+
63
+ export function prep(canvas) {
64
+ const dpr = Math.min(globalThis.devicePixelRatio || 1, 2);
65
+ const w = canvas.clientWidth || 800;
66
+ const h = canvas.clientHeight || 420;
67
+ if (canvas.width !== Math.round(w * dpr) || canvas.height !== Math.round(h * dpr)) {
68
+ canvas.width = Math.round(w * dpr);
69
+ canvas.height = Math.round(h * dpr);
70
+ }
71
+ const ctx = canvas.getContext('2d');
72
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
73
+ ctx.clearRect(0, 0, w, h);
74
+ ctx.font = '11px ui-monospace, SFMono-Regular, Menlo, monospace';
75
+ ctx.textBaseline = 'middle';
76
+ return { ctx, w, h };
77
+ }
78
+
79
+ export function drawPriceChart(canvas, { candles = [], overlays = [], name = '', hover = null } = {}) {
80
+ if (!canvas?.getContext) return null;
81
+ const { ctx, w, h } = prep(canvas);
82
+ if (!candles.length) {
83
+ ctx.fillStyle = INK.text; ctx.textAlign = 'center';
84
+ ctx.fillText('no candles yet', w / 2, h / 2);
85
+ return null;
86
+ }
87
+ const L = layoutChart(candles, overlays, w, h);
88
+ const right = w - PAD.right;
89
+
90
+ // price grid and axis (right, as on a trading screen)
91
+ ctx.lineWidth = 1;
92
+ ctx.textAlign = 'left';
93
+ for (const v of niceTicks(L.lo, L.hi, Math.max(3, Math.floor(L.priceH / 46)))) {
94
+ const y = Math.round(L.Y(v)) + 0.5;
95
+ if (y < PAD.top || y > PAD.top + L.priceH) continue;
96
+ ctx.strokeStyle = INK.grid;
97
+ ctx.beginPath(); ctx.moveTo(PAD.left, y); ctx.lineTo(right, y); ctx.stroke();
98
+ ctx.fillStyle = INK.axisText;
99
+ ctx.fillText(money(v, 0), right + 7, y);
100
+ }
101
+ // time grid and axis
102
+ ctx.textAlign = 'center';
103
+ for (const tk of timeTicks(L.t0, L.t1, L.plotW)) {
104
+ const x = Math.round(L.XT(tk.t)) + 0.5;
105
+ ctx.strokeStyle = tk.label.includes(' ') ? INK.axis : INK.grid;
106
+ ctx.beginPath(); ctx.moveTo(x, PAD.top); ctx.lineTo(x, L.VY0); ctx.stroke();
107
+ ctx.fillStyle = tk.label.includes(' ') ? INK.label : INK.axisText;
108
+ ctx.fillText(tk.label, x, h - PAD.bottom / 2);
109
+ }
110
+ // the pane edges
111
+ ctx.strokeStyle = INK.axis;
112
+ ctx.beginPath(); ctx.moveTo(right + 0.5, PAD.top); ctx.lineTo(right + 0.5, L.VY0); ctx.stroke();
113
+ ctx.beginPath(); ctx.moveTo(PAD.left, L.VY0 + 0.5); ctx.lineTo(right, L.VY0 + 0.5); ctx.stroke();
114
+
115
+ const bodyW = Math.max(1, Math.min(16, L.slot * 0.66));
116
+ // volume
117
+ candles.forEach((k, i) => {
118
+ const vh = L.VH(k.v);
119
+ if (vh < 0.5) return;
120
+ ctx.fillStyle = k.c >= k.o ? UP_V : DOWN_V;
121
+ ctx.fillRect(L.X(i) - bodyW / 2, L.VY0 - vh, bodyW, vh);
122
+ });
123
+ ctx.fillStyle = INK.textDim; ctx.textAlign = 'left';
124
+ ctx.fillText('volume', PAD.left + 4, L.VY0 - L.volH + 6);
125
+
126
+ // the other exchanges, as thin close lines
127
+ for (const o of overlays) {
128
+ const pts = o.candles.filter((k) => k.t >= L.t0 && k.t <= L.t1);
129
+ if (pts.length < 2) continue;
130
+ ctx.strokeStyle = o.color; ctx.lineWidth = 1.1;
131
+ ctx.beginPath();
132
+ pts.forEach((k, j) => { const x = L.XT(k.t), y = L.Y(k.c); if (j) ctx.lineTo(x, y); else ctx.moveTo(x, y); });
133
+ ctx.stroke();
134
+ }
135
+ ctx.lineWidth = 1;
136
+
137
+ // candles: the wick is the hour's range, the body open to close
138
+ candles.forEach((k, i) => {
139
+ const x = Math.round(L.X(i)) + 0.5;
140
+ const col = k.c >= k.o ? UP : DOWN;
141
+ ctx.strokeStyle = col;
142
+ ctx.beginPath(); ctx.moveTo(x, L.Y(k.h ?? Math.max(k.o, k.c))); ctx.lineTo(x, L.Y(k.l ?? Math.min(k.o, k.c))); ctx.stroke();
143
+ const y1 = L.Y(Math.max(k.o, k.c)), y2 = L.Y(Math.min(k.o, k.c));
144
+ ctx.fillStyle = col;
145
+ ctx.fillRect(x - bodyW / 2, y1, bodyW, Math.max(1, y2 - y1));
146
+ });
147
+
148
+ // the last price: a dashed line and its label on the axis
149
+ const lastK = candles.at(-1);
150
+ const ly = Math.round(L.Y(lastK.c)) + 0.5;
151
+ const lcol = lastK.c >= lastK.o ? UP : DOWN;
152
+ ctx.strokeStyle = lcol; ctx.setLineDash([4, 3]);
153
+ ctx.beginPath(); ctx.moveTo(PAD.left, ly); ctx.lineTo(right, ly); ctx.stroke();
154
+ ctx.setLineDash([]);
155
+ ctx.fillStyle = lcol; ctx.fillRect(right + 1, ly - 9, PAD.right - 2, 18);
156
+ ctx.fillStyle = INK.bright; ctx.textAlign = 'left';
157
+ ctx.fillText(money(lastK.c), right + 6, ly);
158
+
159
+ // the crosshair
160
+ let shown = lastK;
161
+ if (hover && hover.x >= PAD.left && hover.x <= right) {
162
+ const i = L.index(hover.x);
163
+ shown = candles[i];
164
+ const x = Math.round(L.X(i)) + 0.5;
165
+ ctx.strokeStyle = INK.dash; ctx.setLineDash([3, 3]);
166
+ ctx.beginPath(); ctx.moveTo(x, PAD.top); ctx.lineTo(x, L.VY0); ctx.stroke();
167
+ if (hover.y >= PAD.top && hover.y <= PAD.top + L.priceH) {
168
+ const y = Math.round(hover.y) + 0.5;
169
+ ctx.beginPath(); ctx.moveTo(PAD.left, y); ctx.lineTo(right, y); ctx.stroke();
170
+ ctx.setLineDash([]);
171
+ ctx.fillStyle = INK.cursorFill; ctx.fillRect(right + 1, y - 9, PAD.right - 2, 18);
172
+ ctx.fillStyle = INK.cursorText; ctx.fillText(money(L.V(hover.y)), right + 6, y);
173
+ }
174
+ ctx.setLineDash([]);
175
+ }
176
+ // readout (top-left) and overlay legend (top-right)
177
+ ctx.textAlign = 'left';
178
+ ctx.fillStyle = INK.bright;
179
+ ctx.fillText(readout(shown, name), PAD.left + 2, 12);
180
+ ctx.textAlign = 'right';
181
+ let lx = right;
182
+ for (const o of [...overlays].reverse()) {
183
+ const wT = ctx.measureText(o.name).width;
184
+ ctx.fillStyle = INK.label; ctx.fillText(o.name, lx, 12);
185
+ ctx.fillStyle = o.color; ctx.fillRect(lx - wT - 16, 11, 11, 2);
186
+ lx -= wT + 26;
187
+ }
188
+ return L;
189
+ }
@@ -0,0 +1,20 @@
1
+ // QUAKE, the tab (operator, 2026-09-15: "yes, get Quake working as a diversion").
2
+ //
3
+ // The shareware QUAKE.EXE v1.06 and its PAK0.PAK from games/quake_dos/, unmodified, on the emulated
4
+ // PC (dosgame.js has the tab, dosworker.js the machine). Quake is a DJGPP program where DOOM was a
5
+ // DOS/4GW one, so the same machine plays the go32 stub and CWSDPMI for it (dospc.js bootCoff), and it
6
+ // asks far more of the FPU. Its keys are its own: W A S D and mouse look on the first run
7
+ // (dosio.js quakeAutoexec), and after that whatever the player binds in Quake's own menu.
8
+ import { createDosGame } from './dosgame.js';
9
+
10
+ export const renderQuake = createDosGame({
11
+ game: 'quake',
12
+ page: 'quake',
13
+ prefix: 'quake',
14
+ title: 'Quake',
15
+ idleText: 'The shareware episode, Dimension of the Doomed: the real QUAKE.EXE v1.06 running on a PC this monitor emulates. Click the screen to use the mouse.',
16
+ loadingText: 'loading the shareware episode (18 MB)…',
17
+ saveName: /\.SAV$/i,
18
+ keysText: () => 'W S walk · A D strafe · mouse to look · left click fire · Space or right click jump · Shift run · 1–8 weapons · − = smaller or bigger view (smaller runs faster) · Esc menu · ~ console · F6 quicksave · F9 quickload',
19
+ switches: [],
20
+ });