blockyard 0.0.9 → 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 (58) hide show
  1. package/CHANGELOG.md +251 -1
  2. package/README.md +42 -23
  3. package/bin/blockyard.js +2 -1
  4. package/docs/API.md +16 -14
  5. package/docs/ARCHITECTURE.md +92 -5
  6. package/docs/CONFIGURATION.md +33 -26
  7. package/docs/GETTING-STARTED.md +5 -2
  8. package/docs/INSTALL.md +90 -33
  9. package/docs/MEASUREMENTS.md +147 -0
  10. package/docs/SECURITY.md +32 -15
  11. package/docs/TROUBLESHOOTING.md +35 -1
  12. package/docs/USER-GUIDE.md +266 -26
  13. package/package.json +1 -1
  14. package/public/404.html +1 -1
  15. package/public/css/app.css +306 -82
  16. package/public/donate-qr.png +0 -0
  17. package/public/index.html +295 -103
  18. package/public/js/agents.js +228 -51
  19. package/public/js/app.js +82 -8
  20. package/public/js/blockscene3d.js +179 -27
  21. package/public/js/charts.js +21 -21
  22. package/public/js/depthchart.js +31 -27
  23. package/public/js/details3d.js +1456 -71
  24. package/public/js/doom.js +31 -0
  25. package/public/js/dosaudio.js +48 -0
  26. package/public/js/dosgame.js +389 -0
  27. package/public/js/dosio.js +186 -0
  28. package/public/js/dospc.js +1353 -0
  29. package/public/js/dosworker.js +196 -0
  30. package/public/js/login.js +5 -0
  31. package/public/js/markets.js +46 -8
  32. package/public/js/mining.js +310 -32
  33. package/public/js/panels.js +14 -10
  34. package/public/js/pricechart.js +14 -13
  35. package/public/js/quake.js +20 -0
  36. package/public/js/settings.js +103 -21
  37. package/public/js/soundcard.js +459 -0
  38. package/public/js/theme.js +235 -0
  39. package/public/js/wolf3d.js +22 -0
  40. package/public/js/x86.js +1978 -0
  41. package/scripts/donate-qr.py +12 -9
  42. package/scripts/dos-bench.js +56 -0
  43. package/scripts/setup.js +34 -12
  44. package/scripts/shots.mjs +6 -0
  45. package/scripts/smoke.sh +1 -1
  46. package/scripts/tls.js +31 -0
  47. package/server/chain/index/build.js +21 -4
  48. package/server/collect/monitor.js +30 -1
  49. package/server/collect/network.js +295 -0
  50. package/server/config.js +46 -22
  51. package/server/http/api.js +49 -5
  52. package/server/http/games.js +77 -0
  53. package/server/http/server.js +8 -0
  54. package/server/main.js +53 -8
  55. package/server/tls/selfsigned.js +160 -0
  56. package/systemd/blockyard.service +7 -5
  57. package/docs/PRIVATE-LEADERBOARD.md +0 -230
  58. package/docs/STATE-2026-09-09.md +0 -200
package/CHANGELOG.md CHANGED
@@ -6,7 +6,256 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- Nothing yet.
9
+ ## [0.1.0] — 2026-09-16
10
+
11
+ The first minor release, two days after the initial 0.0.9, and everything since it in one place:
12
+ the 0.0.10 that was prepared on 2026-09-15 was never published, and its changes ship here. Four
13
+ things shaped it. The **first outside review** of 0.0.9 on bitcointalk, which called out a monitor
14
+ that bound every interface with no sign-in: 0.1.0 ships hardened — this machine only, sign-in on,
15
+ HTTPS with a certificate it makes itself, and no outbound connection at all until the exchange
16
+ feed is switched on. A day of **use on a laptop screen**, which found every tab a scroll: every
17
+ page now packs to one screen at 1093×945, and the Mining tab follows mempool.space's dashboard
18
+ with its **View more** panels. **Appearance**: the layout's colours are a setting — light or
19
+ dark, five themes, or nine colours of your own. And the **DOS Diversions**: Wolfenstein 3D, DOOM
20
+ and Quake, unmodified shareware on a PC emulated in the browser, written here with no
21
+ dependencies, because "can it run DOOM?" deserved a straight answer. 945 tests, from 862.
22
+
23
+ Upgrading from 0.0.9: [docs/INSTALL.md §11](docs/INSTALL.md#11-updating) — the first start after
24
+ the update serves HTTPS, creates the `admin` account and prints its password once.
25
+
26
+ ### Security
27
+
28
+ - **Hardened defaults** (after the first outside review of 0.0.9): the monitor binds `127.0.0.1`
29
+ and requires sign-in out of the box — the first start creates the `admin` account and prints its
30
+ password once (or takes `BLOCKYARD_ADMIN_PASSWORD`). Reach it from elsewhere over an SSH tunnel,
31
+ or bind a LAN address with `BLOCKYARD_BIND` / `server.hosts`; open read-only access is a choice
32
+ (`BLOCKYARD_AUTH=0`), announced at boot. The boot banner says how to reach a loopback-only
33
+ monitor. Existing installs keep whatever `config/local.json` says.
34
+ - **HTTPS by default.** Every listener serves HTTPS; with no certificate named, the first start
35
+ makes the monitor its own self-signed one under `<data>/tls/` — written without dependencies
36
+ (`server/tls/selfsigned.js`: a v3 X.509 certificate assembled in DER and signed with ECDSA P-256
37
+ over SHA-256), naming the bound hosts, this machine's addresses and hostname — and remakes it
38
+ near expiry or when a bound address is missing from it. `blockyard tls` remakes it by hand
39
+ (`--san` to add names, `--print` to export it). Your own certificate still replaces it;
40
+ `BLOCKYARD_TLS=0` serves plain HTTP behind a proxy. The installer's summary and port probe know
41
+ both schemes.
42
+ - **The installer asks twice before a non-loopback bind.** A LAN or wildcard address is written
43
+ only when the operator types it and confirms it; the default it offers is `127.0.0.1`.
44
+ - **Market polling is off by default** — a new checkbox, **Display settings → Markets & Price →
45
+ Enable market polling**, shared by every screen. A fresh install makes no outbound connection
46
+ but to the node: the Markets and Kiosk tabs say that polling is off and where the switch is,
47
+ Overview's price line stays hidden and the explorer shows no dollar figures. Ticking it takes
48
+ effect at once; unticking parks the feed at once. `BLOCKYARD_MARKETS=0` still removes the feed
49
+ so that the checkbox cannot turn it on. Existing installs tick the box once.
50
+
51
+ ### Appearance
52
+
53
+ - **A first tab in Display settings for the colours of the layout.** A theme mode — Light, Dark,
54
+ or System, which follows the operating system and changes with it — and theme cards with swatch
55
+ strips of the face the mode picks: **BlockYard** (the shipped look, the default; its dark face
56
+ is value for value what the monitor drew before), **Mono** (clean grayscale), **Nous** (GitHub's
57
+ chrome with a Nous blue accent), **GitHub** (Light Default and Dark Default) and **Catppuccin**
58
+ (Latte and Mocha). **Custom** is nine colour pickers — page, panels, text, muted text, accent,
59
+ lines, good, warning, bad — with the rest of a face derived from them (a raised panel, the
60
+ softer rules, the fainter text, the darker accent of a pressed button), and whether Custom is
61
+ light or dark read off its page colour; **customise <theme>** copies the theme on screen into
62
+ the pickers so a custom scheme starts from a look. Saved on the server with the other settings,
63
+ so every screen of the monitor draws the same; the sign-in page draws in the theme the browser
64
+ last saw.
65
+ - The theme is applied through the CSSOM (the page's custom properties rewritten on `<html>`),
66
+ which the content-security policy permits where a style attribute is refused. The charts' axis
67
+ text, grid lines and tooltips, the order-book depth chart's two sides and the market charts'
68
+ grounds follow the theme — they were literals of the dark look, and a light theme would have
69
+ drawn grey-on-grey. The 3D boards stay space, and the Explorer's block and transaction pages
70
+ keep their own dark cards.
71
+
72
+ ### Mining
73
+
74
+ - **The Mining tab has the network row**: reward stats over the last 144 blocks, the difficulty
75
+ period (blocks remaining, the estimated and the previous change, the next halving), a week of
76
+ pools with luck and counts, a year of hashrate with the difficulty's steps, and the last twelve
77
+ adjustments as a table — every figure from this node alone (`server/collect/network.js`:
78
+ `getblockstats` for the reward window, block headers for the periods and a daily sample, the
79
+ week's coinbases read in the background at the lowest RPC priority).
80
+ - **mempool.space's layout**: two columns in its order (reward stats, difficulty adjustment;
81
+ pools, hashrate; recent blocks, adjustments) under the block flow, our own panels beneath, and
82
+ **View more »** on four cards opening that card full screen — the whole week of pools as a
83
+ table, the year's chart large, the whole attributed window of blocks, a year of adjustments.
84
+ - **The pool chart is a labelled pie**: every pool named beside its slice and joined to it by a
85
+ leader in the slice's colour, the small ones stacked, slices under half a percent gathered as
86
+ "Other" — and the "Other" threshold rises until every label fits the card, so no name runs off
87
+ the bottom at any window height. The pie and the year chart size themselves to the window.
88
+ - **Dollar figures** on the reward stats while market polling is on, from a new `/api/price` that
89
+ answers the cached spot price and never starts the exchange polling itself.
90
+ - The Mempool space viewer left this page — it is on Overview, Block space and Mempool — and with
91
+ it the full-pool poll the page used to ask for. The reward window is exactly 144 blocks.
92
+ - At a narrow window the block flow spans the width and is thinner, and the packages table scrolls
93
+ inside its card instead of bleeding into the neighbour; the three stacks become two below 1400px.
94
+ - **A streak of stale drops of the full-pool poll is one story**: one warning event when it
95
+ starts, a counter on Node & RPC while it lasts, one event when the poll answers again with the
96
+ count and the span. On a day the node answered slowly for thirteen hours, each drop had been its
97
+ own event, 188 of the feed's 200 rows.
98
+
99
+ ### Every tab on one screen
100
+
101
+ Measured at 1093×945 and 1600×1000 with a dead-height probe, page by page:
102
+
103
+ - **Globally**: tighter card padding and heading spacing, and a short card beside a tall one keeps
104
+ its own height instead of being stretched to match (Chain & Sync's drill-down card had a
105
+ thousand pixels of nothing under its input; Node & RPC's poll cadence and connection cards
106
+ hundreds).
107
+ - **Overview**: the block flow card a quarter shorter, and the Block space board capped to the
108
+ viewport (it set the whole right column's height), so the events are on the first screen.
109
+ - **Block space**: the card tighter and the board sized so the whole page, note included, fits the
110
+ viewport without a scroll.
111
+ - **Markets**: the board takes what the window leaves, and the exchange table and the order-book
112
+ depth sit side by side beneath it (under 1400px the table drops the pair, 24 h range and volume
113
+ columns; all still in the summary line and on the Kiosk) instead of the depth chart starting a
114
+ thousand pixels down.
115
+ - **Kiosk**: tighter heads and gaps, the price panel's padding trimmed, the Block flow strip a
116
+ quarter shorter, and the full-screen button in that strip's head instead of floating over its
117
+ cards.
118
+ - **Mempool**: keeps its two columns down to 900px (it stacked from 1100), and the room over goes
119
+ to its time-series charts, a fifth taller.
120
+ - **Explorer**: a smaller title, the block strip's padding and scrollbar band trimmed, tighter
121
+ table rows and the table reaching the window's bottom edge — three more blocks on the first
122
+ screen.
123
+ - **Peers**: a long onion or i2p address no longer makes the whole page scroll sideways (it clips
124
+ with an ellipsis and carries the full text as its title; a wide table scrolls inside its card),
125
+ rows and service badges tighter, the top strip's cards at their own heights.
126
+ - **Network**: Throughput beside a stack of Upload and Traffic accounting, the throughput chart
127
+ taller, and the sources table taking the rest of the window.
128
+ - **Events**: the feed reaches the window's bottom edge (it stopped a hundred pixels short).
129
+ - **Chain & Sync**: one-line notes under the block-size and tip charts (the longer sentences are
130
+ their tooltips), the transaction-rate figures as one wrapping line, values that keep to their
131
+ line, and a shorter uptime label — the first three rows sit level and the drill-down and indexes
132
+ reach the first screen.
133
+ - **Node & RPC**: two stacks (RPC etiquette with its figures in two columns, Data quality and Node
134
+ connection; Poll cadence, self-telemetry beside the log tail, Panel sources and the RPC
135
+ console) instead of grid rows that left holes beside the short cards.
136
+ - **Admin**: two stacks (Users over the audit log; Node actions over Change own password, whose
137
+ two fields share a row). **Sign-in** and **404**: the same tighter card.
138
+ - **Display settings**: the tabs in three labelled rows — Boards (Appearance, Block space, Sky,
139
+ Markets & Price), Effects, and the Diversions last; rows, note and groups tighter, the sheet a little wider so hints wrap
140
+ less, and on the two effects tabs the switches run two across with each hint as the row's
141
+ tooltip — the Space effects tab is under half the scrolling it was. The price line on Overview
142
+ switch sits directly under the polling switch it depends on.
143
+ - **About**: the sky runs to the bottom edge with the credit line at its foot, and the GitHub
144
+ link and the tip pill share a row.
145
+ - **The Diversions pages take the window**: the wells of Tetrust, Blockout and Blockanoid grow to
146
+ the window's height (they stopped at 600px), and the DOS screen is always 4:3 and as large as
147
+ the window allows — at a 1093px window the 320×200 picture had been drawn squashed into a
148
+ 761×720 box.
149
+
150
+ ### DOS Diversions
151
+
152
+ - **DOOM.** The shareware `DOOM.EXE` v1.9 and `DOOM1.WAD` from `games/doom_dos/`, unmodified,
153
+ running on a PC emulated in the browser with no dependencies: an i386 interpreter
154
+ (`public/js/x86.js`), the DOS/4GW machine around it — DOS, DPMI, BIOS, PIC, timer, keyboard and
155
+ a planar VGA (`dospc.js`) — and a Sound Blaster Pro 2 with an OPL3 for the effects and the music
156
+ (`soundcard.js`), in a worker. Demos, menus, savegames and ENDOOM all work; 35 frames a second.
157
+ Mouse capture, WASD keys by default (the switch rebinds the running game at once), smoothing,
158
+ full screen; pauses when you look away; savegames and DOOM's config stay in the browser.
159
+ - **Wolfenstein 3D.** The shareware `WOLF3D.EXE` v1.4 and its `.WL1` files from
160
+ `games/wolf3d_dos/`, unmodified, on the same emulated PC — which now also runs a 16-bit real-mode
161
+ DOS program: real mode in the CPU (segments times sixteen, a wrapping SP, 16-bit string
162
+ instructions and interrupt frames), a plain MZ loader with its relocations, DOS's memory
163
+ allocator, the interrupt vector table, and VGA write mode 1. Menus, demos, AdLib music,
164
+ digitised sound effects, savegames and high scores kept in the browser, at its full 70 frames a
165
+ second. It sits before DOOM and Quake in the Diversions menu.
166
+ - **Quake.** The shareware `QUAKE.EXE` v1.06 and `PAK0.PAK` from `games/quake_dos/`, unmodified,
167
+ on the same emulated PC — which now also plays the go32 stub and CWSDPMI for a DJGPP program:
168
+ segment bases and 16-bit code in the CPU, a COFF loader, a directory tree, DOS's system file
169
+ table, the BIOS tick count. Demos, menus, savegames, sound effects through the Sound Blaster,
170
+ and the order screen on quit. W A S D and mouse look on the first start, Quake's own bindings
171
+ after. Quake starts with a smaller view (`viewsize 80`); **−** and **=** change it and Quake
172
+ keeps the choice.
173
+ - **The emulated PC is fast.** Each instruction is decoded once and cached rather than decoded
174
+ every time it runs (writes into cached code clear what they overlap, because both games patch
175
+ their own drawing code), the arithmetic and the x87 forms Quake runs most have handlers of their
176
+ own, and memory addresses are formed inline: Quake from 77 to about 141 million instructions a
177
+ second, its `timedemo demo1` from 29.7 fps to over 50; in the browser Quake plays at 40–50
178
+ frames a second.
179
+ - **A way out of full screen**: an **exit full screen** button in the top corner while full
180
+ screen, and holding **Esc** for a second (a tap of Esc stays the game's menu, which is what the
181
+ keyboard lock is for); leaving unlocks the keyboard and releases the mouse.
182
+ - The game files are served at `/games/<game>/<path>` (`server/http/games.js`); the shareware
183
+ packages live under `games/` (DOOM's moved from `doom_dos/` at the repository root).
184
+
185
+ ### Markets and the effects
186
+
187
+ - **Black hole**, a Markets effect (modelled on NASA's visualisation, svs.gsfc.nasa.gov/14576): a
188
+ point of darkness opens and grows to a horizon over 26 s, the price line bends round it as
189
+ through a lens (the Einstein-radius push), the candles it reaches stretch and lean toward it and
190
+ shrink away into it, and an accretion disk seen nearly edge-on — a thin band white-yellow at its
191
+ inner edge through orange to a dark red rim, five hundred fibres spiralling inward sheared by
192
+ the Keplerian flow, its far side lensed into an arch over the shadow and a smaller one beneath,
193
+ a photon ring hugging the horizon, starlight bent into arcs. **It crosses the board**: it opens
194
+ a fifth of the way in on one side and runs a straight line through the chart to a fifth from the
195
+ other, from one height to another, so the line is seen bending round it as it passes; the
196
+ candles' orbits ride along at a quarter of the first cut's speed. It finishes its crossing before
197
+ it lets go, and lets go evenly, every candle gliding home and growing back smoothly. It hovered
198
+ over Block space for a day and its cubes never came home cleanly enough, so it is a Markets
199
+ effect only.
200
+ - **Supernova** (the solar flare, renamed and remade on NASA Goddard's animation,
201
+ svs.gsfc.nasa.gov/20413): the star is a glint — halo, hot core, diffraction spikes — growing and
202
+ blue-shifting as it goes; the opening explosion is a **white-hot flash**, held and washing far
203
+ out, that throws **a hundred and twenty-eight plumes of white gas** in every direction, each
204
+ flying and growing on its own out to nine star radii and drifting on until the effect is nearly
205
+ done (drawn on a half-resolution layer to keep the frame cheap); the debris is a volume of gas in
206
+ three layers — a blue cloud out in front, a white one behind it into which **violet grows patch
207
+ by patch from a tenth of the run**, and a deep violet heart — with a soft shock band throwing
208
+ and shaking the candles it crosses; and as the cloud dims a **pulsar** beats seven times a
209
+ second at the centre, two thin beams sweeping round, inside a nebula of the same gas that holds
210
+ its violet weight until four fifths of the run. 16 s (24 on Markets).
211
+ - **Fireworks are a display**, on both boards: every shell drawn — the rocket's arc, a white flash
212
+ and a shockwave ring at the burst, seven shell kinds by turn (peony, chrysanthemum, willow, ring,
213
+ crossette, strobe and more), sixty to ninety sparks each a curved trail, a lens flare at every
214
+ burst, glitter rain, and a nebula of smoke that drifts up and lingers; up to ten shells on
215
+ Markets over 14 s (five on Block space), each lighting the candles under it in its own colour.
216
+ **Off by default** on both boards, kept for special occasions.
217
+ - **X-ray**, on both boards: a front sweeps the board and everything behind it goes x-ray — bodies
218
+ dimmed to glass, every edge lit, a raster of thin lines across each face — then develops back.
219
+ - **Breathe** and **Light saber**, on the price line: three slow swells from the plain wire to
220
+ white heat and back; and the line igniting from its left end, blue, green, red or purple by the
221
+ run, humming with a breathing glow, spitting sparks, retracting to the hilt.
222
+ - **The energy pulse is heat, not blue, and its head is a crackling ball of plasma**; **the scan
223
+ line is a light curtain** standing on the board floor to the chart's top; **ball lightning is a
224
+ light source**, its arcs discharges built by midpoint displacement rather than zigzags, a quarter
225
+ of its size and a third of its speed on Markets; the scanner's cone is dimmer on both boards.
226
+ - **The Markets board keeps its price fit across refreshes**: the last fit is kept while the data
227
+ still sits inside it and fills at least two-thirds of it, so a refresh no longer re-scales the
228
+ whole chart unanimated. Whatever a head pulls is painted last, nearest the head on top; a held
229
+ pool refresh waits a moment and a half after an idle effect ends, with the board whole and still.
230
+ - **Layered soft fills add up correctly** (`softStops`): each nested disc carries only its
231
+ increment, so a stop's cumulative opacity is exactly the stop's; measured on the Kiosk, the
232
+ supernova's peak opacity fell from about 0.9 to about 0.45 and the chart shows through it.
233
+ - **The no-repeat window holds from the first pick** on both boards: every effect plays once
234
+ before any repeats (a negative slice index had let one come round at the tenth pick). The
235
+ searchlight and the tractor beam, which fly the same saucer, share the window.
236
+ - **A Kiosk test suite** (`test/kiosk.test.js`): every Markets and Block space effect plays through
237
+ the frame loop on a Kiosk-sized panel; the supernova, the black hole and the fireworks are
238
+ bounded by the board's width so no panel is covered.
239
+
240
+ ### Fixed
241
+
242
+ - **The donation QR shows on Safari.** It was an inline SVG of 800 module rects, and Safari on
243
+ the first Mac install painted its white ground and none of the rects. It is a PNG now, painted
244
+ the same everywhere.
245
+ - **A dead index worker fails the build instead of hanging it.** A worker killed outright (out of
246
+ memory, with four beside the node) left its job unanswered and the build sat at "scan 5,720 of
247
+ 5,721, about 1 s left" for an hour and a half on the first Mac install. The run now rejects the
248
+ moment a worker exits or throws, naming the job and the fix (fewer `addressIndexWorkers`); the
249
+ progress flag says *no progress for N min* when nothing has moved.
250
+ - The 0.0.9 release notes' test count corrected (862, not 864).
251
+
252
+ ### Documentation
253
+
254
+ - INSTALL, GETTING-STARTED, SECURITY, CONFIGURATION, API, TROUBLESHOOTING and the README describe
255
+ the hardened defaults, HTTPS and the polling switch; INSTALL §11 has the notes for updating a
256
+ 0.0.9 install; the USER-GUIDE has the Appearance section, the Mining row and the packed layouts;
257
+ TROUBLESHOOTING explains a streak of stale pool-poll drops. Screenshots re-shot at 0.1.0, with a
258
+ Mining shot added. The announcement for the bitcointalk thread is in `docs/announcement/0.1.0/`.
10
259
 
11
260
  ## [0.0.9] — 2026-09-14
12
261
 
@@ -676,4 +925,5 @@ are an original implementation (`public/js/blockpack.js`, `public/js/feepalette.
676
925
  Internal first version: multi-user monitor with charts, sync viewer, mempool view, peers and
677
926
  event feed.
678
927
 
928
+ [0.0.10]: https://github.com/BobClawblaw/blockyard/releases/tag/v0.0.10
679
929
  [0.0.9]: https://github.com/BobClawblaw/blockyard/releases/tag/v0.0.9
package/README.md CHANGED
@@ -5,8 +5,8 @@ A live, multi-user web monitor and block explorer for
5
5
 
6
6
  Point it at your node and open a browser: live charts, a 3D block-space viewer,
7
7
  a block / transaction / address explorer, exchange prices with order-book depth, and a
8
- kiosk view for a wall screen. No dependencies to install, no CDN, no telemetry, and
9
- read-only toward your node by default.
8
+ kiosk view for a wall screen. No dependencies to install, no CDN, no telemetry, no outbound
9
+ connection but to your node out of the box, and read-only toward your node by default.
10
10
 
11
11
  **This is 100% machine-generated code, directed by a human operator.** Every line of the
12
12
  server, the browser app, the 3D engine, the tests and these documents was written by an AI
@@ -21,18 +21,19 @@ bugs.**
21
21
 
22
22
  | | |
23
23
  |---|---|
24
- | **Block space, in 3D.** The next block's worth of the mempool as a board of glowing tiles: area is vbytes, colour is feerate. Refreshes are choreographed — blocks lift, travel in collision-free lanes and land under gravity — and the board comes alive at rest with **30 idle effects**, from ripples and light cycles to a lightning ball, ball lightning, a UFO's tractor beam, Missile Command, fireworks, code rain and a demoscene plasma. Two viewer modes: **Simple** (the richest few hundred transactions as cubes) and **Detailed** (every transaction in the block). | ![Block space, Detailed mode](docs/images/block-space-mode2.jpg) |
25
- | **A board you can tune.** Neon-tube blocks, a metallic sheen or a chrome finish that mirrors a horizon, a movable lamp, a touch of perspective, a spiral galaxy behind the board, and a switch for every one of the 30 effects — in a tabbed settings panel. Stored on the server (`config/blockyard.json`), so every screen sees the same board; they change how things are *drawn*, never what is measured. | ![Neon blocks and the metallic sheen](docs/images/block-space-neon.jpg) |
24
+ | **Block space, in 3D.** The next block's worth of the mempool as a board of glowing tiles: area is vbytes, colour is feerate. Refreshes are choreographed — blocks lift, travel in collision-free lanes and land under gravity — and the board comes alive at rest with **34 idle effects**, from ripples and light cycles to a lightning ball, ball lightning, a UFO's tractor beam, Missile Command, fireworks, code rain and a demoscene plasma. Two viewer modes: **Simple** (the richest few hundred transactions as cubes) and **Detailed** (every transaction in the block). | ![Block space, Detailed mode](docs/images/block-space-mode2.jpg) |
25
+ | **A board you can tune.** Neon-tube blocks, a metallic sheen or a chrome finish that mirrors a horizon, a movable lamp, a touch of perspective, a spiral galaxy behind the board, and a switch for every one of the 34 effects — in a tabbed settings panel. Stored on the server (`config/blockyard.json`), so every screen sees the same board; they change how things are *drawn*, never what is measured. | ![Neon blocks and the metallic sheen](docs/images/block-space-neon.jpg) |
26
26
  | **An explorer that looks the part.** Search a height, block hash, txid or address. Transaction pages with fee, fee rate and dollar value, feature badges, a flow diagram from inputs to outputs, and links to where every coin came from and went. **Address pages with full history and balance** — Bitcoin Core has no address index, so BlockYard builds its own from the node's block files (**a few hours** on first start, 124 GB) and keeps it current as blocks arrive. | ![Explorer transaction](docs/images/explorer-tx.jpg) |
27
- | **Markets.** Five exchanges' public prices: a 3D candle chart with a neon price line, a precise flat candlestick chart, an exchange table, and a bitcoinity-style order-book depth chart with change bars. Fetched by the server only while someone is looking. | ![Markets](docs/images/markets.jpg) |
27
+ | **Markets.** Five exchanges' public prices: a 3D candle chart with a neon price line, a precise flat candlestick chart, an exchange table, and a bitcoinity-style order-book depth chart with change bars. Off until you tick **Enable market polling** — it is the one thing that talks to anyone but your node — and, once on, fetched by the server only while someone is looking. | ![Markets](docs/images/markets.jpg) |
28
28
  | **Kiosk.** The 3D markets board, a price panel and the block-space board side by side, full screen with one click. | ![Kiosk](docs/images/kiosk.jpg) |
29
- | **Tetrust, Blockout and Blockanoid.** Three playable games built on the same 3D engine — trust, but verify. Tetrust is Tetris: the well is the block-space board and the music is synthesised in the browser. Blockout is Breakout, where the wall is made of block-space stones and the bat follows your mouse. Blockanoid is Arkanoid: a different wall every level, silver bricks that take more than one hit, gold that takes none, and capsules that fall out of what you break — laser, wide, catch, slow, three balls, a life. All three pause when you look away and keep high scores per browser. | ![Tetrust](docs/images/tetrust.jpg) |
29
+ | **Tetrust, Blockout and Blockanoid.** Three playable games built on the same 3D engine — trust, but verify. Tetrust is Tetris: the well is the block-space board and the music is synthesised in the browser. Blockout is Breakout, where the wall is made of block-space stones and the bat follows your mouse. Blockanoid is Arkanoid: a different wall every level, silver bricks that take more than one hit, gold that takes none, and capsules that fall out of what you break — laser, wide, catch, slow, three balls, a life. All three pause when you look away and keep high scores per browser. And **Wolfenstein 3D**, **DOOM** and **Quake**: the real shareware `WOLF3D.EXE` (1992), `DOOM.EXE` (1993) and `QUAKE.EXE` (1996), unmodified, on a PC emulated in the browser — processor in real and protected mode, FPU, DOS and both extenders, VGA and Sound Blaster written from scratch, still with no dependencies. So if anyone asks *"well, can it run DOOM?"*, the answer is an emphatic **"Naturally. What sort of AI slop generator do you take me for?"** | ![Tetrust](docs/images/tetrust.jpg) |
30
30
 
31
31
  Also on board: a sync viewer with an honest ETA, Block flow (projected blocks, the block
32
32
  being built, recent blocks), mempool and fee charts, a peer table, bandwidth, the node's
33
33
  event stream, a provenance table for every figure, a read-only RPC console behind a
34
34
  default-deny allowlist, and a tabbed **Display settings** panel (the gear) that tunes every
35
- board without a reload.
35
+ board without a reload and picks the layout's colours — light or dark, the shipped look, Mono,
36
+ Nous, GitHub, Catppuccin, or nine colours of your own.
36
37
 
37
38
  ## Quick start
38
39
 
@@ -46,9 +47,10 @@ top of the node's own ~875 GB of block files.
46
47
  ```bash
47
48
  git clone https://github.com/BobClawblaw/blockyard.git
48
49
  cd blockyard
49
- npm test # optional: 862 unit tests, all built in
50
+ npm test # optional: 945 unit tests, all built in
50
51
  npm run setup # reads the node's bitcoin.conf, checks the node, writes config/local.json
51
- npm start # builds the address index in the background (a few hours); open http://127.0.0.1:21000
52
+ npm start # builds the address index in the background (a few hours); open https://127.0.0.1:21000
53
+ # and sign in as admin with the password the first start prints once
52
54
  ```
53
55
 
54
56
  `npm run setup` asks for the node's data directory, reads its `bitcoin.conf` for the rest,
@@ -107,15 +109,23 @@ design rests on) and [docs/DEFECTS.md](docs/DEFECTS.md) (known limits).
107
109
 
108
110
  ## Security at a glance
109
111
 
110
- - **Open, read-only access by default** — like a block explorer, anyone who can reach the
111
- port can look. Accounts, roles, sessions, CSRF protection and a per-user audit trail turn
112
- on with `BLOCKYARD_AUTH=1`.
113
- - **Where it listens is your decision** bind to `127.0.0.1`, a LAN address, a VPN
114
- address, or several. Built-in HTTPS with `BLOCKYARD_TLS_CERT` / `BLOCKYARD_TLS_KEY`.
115
- - **Outbound connections are limited and on demand**: exchange APIs only while someone has
116
- the Markets, Kiosk or Overview tab open Overview's price line is on by default, so the landing
117
- page reaches out unless you switch it off plus a cached spot price for the explorer's dollar
118
- figures. `BLOCKYARD_MARKETS=0` turns all of it off.
112
+ - **Hardened out of the box** — it listens on `127.0.0.1` only and requires sign-in: the
113
+ first start creates an `admin` account and prints its password once. Accounts, roles,
114
+ sessions, CSRF protection and a per-user audit trail are on. Reach it from another machine
115
+ over an SSH tunnel, or bind a LAN address (`BLOCKYARD_BIND`) when you decide the LAN may
116
+ see it; open, read-only access with no account is a choice (`BLOCKYARD_AUTH=0`), announced
117
+ at boot.
118
+ - **HTTPS by default**the first start makes the monitor its own certificate (no
119
+ dependencies: the X.509 is written by hand), and every listener serves it; a certificate of
120
+ your own with `BLOCKYARD_TLS_CERT` / `BLOCKYARD_TLS_KEY`, or `BLOCKYARD_TLS=0` behind a
121
+ proxy that terminates TLS.
122
+ - **Where it listens is your decision** — `127.0.0.1`, a LAN address, a VPN address, or
123
+ several.
124
+ - **No outbound connections out of the box**: a fresh install talks to nothing but your node.
125
+ The one exception is opt-in — a checkbox, **Display settings → Markets & Price → Enable
126
+ market polling**, turns on the exchange feed for the Markets and Kiosk tabs, Overview's price
127
+ line and the explorer's dollar figures, and even then the server asks the exchanges only while
128
+ someone is looking. `BLOCKYARD_MARKETS=0` removes the feed so that no checkbox can turn it on.
119
129
 
120
130
  Details in [docs/SECURITY.md](docs/SECURITY.md). To report a vulnerability, see
121
131
  [SECURITY.md](SECURITY.md).
@@ -126,7 +136,7 @@ Details in [docs/SECURITY.md](docs/SECURITY.md). To report a vulnerability, see
126
136
  npm run dev # fake node doing a simulated sync, port 18088
127
137
  npm run setup # interactive install: read bitcoin.conf, check the node, write config/local.json
128
138
  npm run check # the same checks (every call timed) against every configured node; exits 1 on a FAIL
129
- npm test # 862 unit tests (node:test, no dependencies)
139
+ npm test # 945 unit tests (node:test, no dependencies)
130
140
  npm run smoke # boots the real server and checks the HTTP contract
131
141
  npm run counts:fix # keep the documented test count in step with the suite
132
142
  ```
@@ -136,13 +146,22 @@ RPC etiquette) and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for how it fits
136
146
 
137
147
  ## Status
138
148
 
139
- Version **0.0.9** — the initial release, and pre-release software: the word is meant literally. The test suite is
140
- comprehensive (862 tests, plus a live smoke run), the monitoring side is solid, and the
149
+ Version **0.1.0** — the first minor release, two days after the initial 0.0.9, and pre-release
150
+ software: the word is meant literally. Published 2026-09-16: on [npm](https://www.npmjs.com/package/blockyard)
151
+ as `blockyard`, as a [GitHub release](https://github.com/BobClawblaw/blockyard/releases/tag/v0.1.0),
152
+ and announced on
153
+ [bitcointalk](https://bitcointalk.org/index.php?topic=5594141.msg67144312) — questions, bug
154
+ reports and reviews are welcome there and in [issues](https://github.com/BobClawblaw/blockyard/issues).
155
+ It ships **hardened**: bound to this machine, sign-in on, HTTPS with a certificate it makes itself,
156
+ and **zero telemetry** — no outbound connection to anyone but your node until you tick the market
157
+ polling switch yourself.
158
+ The test suite is
159
+ comprehensive (945 tests, plus a live smoke run), the monitoring side is solid, and the
141
160
  explorer's biggest gap is closed: **address history and balances**, which Bitcoin Core cannot
142
161
  answer at any setting, now come from an **address index BlockYard builds itself** from the
143
162
  node's block and undo files and keeps current as blocks arrive. It is checked against the node
144
- (every balance equal to `scantxoutset`, to the satoshi) and costs ~30 minutes on 16 workers and
145
- 124 GB of disk, built in the background the first time BlockYard starts and paced so the node's
163
+ (every balance equal to `scantxoutset`, to the satoshi) and costs a few hours on the default four
164
+ workers (~30 minutes on 16) and 124 GB of disk, built in the background the first time BlockYard starts and paced so the node's
146
165
  RPC stays responsive; without one, the address page says *not indexed* rather than showing a
147
166
  zero. An address's unspent outputs are listed too (for a history of up to 100 transactions).
148
167
  What it does not yet have: an address's mempool transactions.
package/bin/blockyard.js CHANGED
@@ -27,11 +27,12 @@ const COMMANDS = {
27
27
  start: 'server/main.js',
28
28
  'index-build': 'scripts/index-build.js',
29
29
  users: 'scripts/manage-users.js',
30
+ tls: 'scripts/tls.js',
30
31
  };
31
32
  const cmd = process.argv[2];
32
33
  if (!COMMANDS[cmd]) {
33
34
  const version = JSON.parse((await import('node:fs')).readFileSync(path.join(root, 'package.json'), 'utf8')).version;
34
- process.stdout.write(`BlockYard ${version}\n\n blockyard setup ask where the node is, check it, write the config, build the index\n blockyard start run the monitor\n blockyard check the same checks as setup, any time\n blockyard index-build build the address index by hand (--out <dir> [--workers N])\n blockyard users manage accounts\n\nconfig ${process.env.BLOCKYARD_CONFIG}\ndata ${process.env.BLOCKYARD_DATA}\n`);
35
+ process.stdout.write(`BlockYard ${version}\n\n blockyard setup ask where the node is, check it, write the config, build the index\n blockyard start run the monitor\n blockyard check the same checks as setup, any time\n blockyard index-build build the address index by hand (--out <dir> [--workers N])\n blockyard users manage accounts\n blockyard tls remake this monitor's own HTTPS certificate (--san to add names)\n\nconfig ${process.env.BLOCKYARD_CONFIG}\ndata ${process.env.BLOCKYARD_DATA}\n`);
35
36
  process.exit(cmd ? 2 : 0);
36
37
  }
37
38
  // the scripts decide "am I being run directly?" by comparing argv[1] to their own path, so hand
package/docs/API.md CHANGED
@@ -89,7 +89,7 @@ Other statuses: `204` for `OPTIONS` on any path (`Allow: GET,POST,DELETE,HEAD`).
89
89
 
90
90
  Each route in the table has one of three auth levels:
91
91
 
92
- | Level | Accounts off (default) | Accounts on (`BLOCKYARD_AUTH=1`) |
92
+ | Level | Accounts off (`BLOCKYARD_AUTH=0`) | Accounts on (the default) |
93
93
  |---|---|---|
94
94
  | `none` | Open. | Open. No session needed. |
95
95
  | `any` | Served as the built-in anonymous user (`role: "viewer"`). | Any valid, non-disabled session. Without one: `401`. |
@@ -97,14 +97,14 @@ Each route in the table has one of three auth levels:
97
97
 
98
98
  The roles are `viewer` < `operator` < `admin`. No route in the table requires `viewer` or `operator` by itself. Those two roles matter in two places only: each node action names a minimum role (section 14), and `POST /api/password` needs `admin` to change *another* user's password.
99
99
 
100
- **Open mode (the default, `auth.enabled=false`).** No sign-in. Anyone who can reach the port can read everything (state, charts, events, peers, mempool, explorer, markets, the read-only RPC console) as `viewer`. The ceiling is fixed and nothing can raise it. As a result:
100
+ **Open mode (`auth.enabled=false`, a choice; the default is accounts on).** No sign-in. Anyone who can reach the port can read everything (state, charts, events, peers, mempool, explorer, markets, the read-only RPC console) as `viewer`. The ceiling is fixed and nothing can raise it. As a result:
101
101
 
102
102
  - user administration, `/api/audit` and password changes are closed;
103
103
  - node writes (`/api/action`) are refused unless `BLOCKYARD_ALLOW_WRITES_WITHOUT_AUTH=1` was set deliberately;
104
104
  - `/api/login` answers `403 accounts_disabled`;
105
105
  - `GET /login` redirects (`302`) to `/`.
106
106
 
107
- **Accounts mode (`BLOCKYARD_AUTH=1`).** Sign-in, roles, sessions, CSRF protection and a per-user audit trail. On first start with no users, an `admin` account is created. Its password comes from `BLOCKYARD_ADMIN_PASSWORD`, or is generated and printed once to the server log.
107
+ **Accounts mode (the default).** Sign-in, roles, sessions, CSRF protection and a per-user audit trail. On first start with no users, an `admin` account is created. Its password comes from `BLOCKYARD_ADMIN_PASSWORD`, or is generated and printed once to the server log.
108
108
 
109
109
  ### Session cookie
110
110
 
@@ -224,8 +224,8 @@ Auth `none`, not rate limited. Built for uptime probes. `ok` is `true` when at l
224
224
  {
225
225
  "ok": true,
226
226
  "degraded": [],
227
- "version": "0.0.9",
228
- "build": "0.0.9-fd620adc52",
227
+ "version": "0.1.0",
228
+ "build": "0.1.0-fd620adc52",
229
229
  "scheme": "http",
230
230
  "tls": false,
231
231
  "uptimeSec": 1519,
@@ -242,7 +242,7 @@ Auth `none`, not rate limited. Built for uptime probes. `ok` is `true` when at l
242
242
  What the About page shows: the monitor's version and live build, and the **shape** of the machine it runs on.
243
243
 
244
244
  ```json
245
- { "version": "0.0.9", "build": "0.0.9-a6ecedff3c", "platform": "linux", "release": "7.0.0-31-generic",
245
+ { "version": "0.1.0", "build": "0.1.0-a6ecedff3c", "platform": "linux", "release": "7.0.0-31-generic",
246
246
  "arch": "x64", "cpus": 32, "cpuModel": "AMD Ryzen 9 9950X3D 16-Core Processor",
247
247
  "totalMemGb": 132.3, "node": "v22.23.2", "uptimeSec": 2355 }
248
248
  ```
@@ -261,9 +261,9 @@ Auth `none`. Answers "is the code in my tab the code on disk?" The build id is `
261
261
 
262
262
  ```json
263
263
  {
264
- "version": "0.0.9",
265
- "build": "0.0.9-5223f98d84",
266
- "bootBuild": "0.0.9-fd620adc52",
264
+ "version": "0.1.0",
265
+ "build": "0.1.0-5223f98d84",
266
+ "bootBuild": "0.1.0-fd620adc52",
267
267
  "matchesClient": null,
268
268
  "scheme": "http",
269
269
  "tls": false,
@@ -295,6 +295,7 @@ Top-level keys:
295
295
  ```
296
296
  id label color online chain ibd tip sync progress warnings difficulty hashrateEstEh hashrateNote
297
297
  avgBlockGapSec sizeOnDisk pruned chainwork uptimeSec network mempool peers net attribution blocks
298
+ network (the Mining tab's network row: rewards over 144 blocks, adjustment, halving, adjustments[], hashrate { networkHashPs, series[] }, pools { blocks, luckPct, pools[], filled, todo }; collect/network.js)
298
299
  fees mining utxo chaintxstats indexes tips deployments rpcInfo log health series app user seq
299
300
  ```
300
301
 
@@ -331,7 +332,7 @@ Trimmed example:
331
332
  "health": { "rpc": { "online": true, "...": "..." }, "cadence": { "fast": { "configuredMs": 4000,
332
333
  "effectiveMs": 4000, "stretched": false, "lastRunMs": 120 } }, "quality": [] },
333
334
  "series": { "mempool": { "hour": [ { "t": 1789154820000, "v": 18780 } ], "...": "..." } },
334
- "app": { "version": "0.0.9", "build": "0.0.9-fd620adc52", "scheme": "http", "uptimeSec": 1536,
335
+ "app": { "version": "0.1.0", "build": "0.1.0-fd620adc52", "scheme": "http", "uptimeSec": 1536,
335
336
  "sseClients": 5, "self": { "rssMb": 175.6, "heapMb": 42.8, "cpuPct": 2.71 }, "serverTime": 1789155688322 },
336
337
  "user": { "username": "anonymous", "role": "viewer", "id": "anonymous", "disabled": false, "lastLoginAt": null },
337
338
  "seq": 406
@@ -1029,8 +1030,9 @@ To poll incrementally, keep `maxSeq` and pass it back as `since`. The filters ar
1029
1030
 
1030
1031
  Exchange prices from the public REST APIs of Coinbase, Kraken, Bitstamp, Bitfinex and OKX. **This is the only outbound connection BlockYard makes that is not to the node.** It runs server-side, because the page's CSP allows `connect-src 'self'` only.
1031
1032
 
1032
- - **On demand.** Nothing is fetched until someone calls `/api/markets` or `/api/markets/depth`. Each call "touches" the feed. The dashboard's Overview makes that call by default (Display settings Markets & Price Price line on Overview), so a monitor with anyone on its landing page is polling. While touched, it polls tickers every 15 s, hourly candles every 5 min and order books every 30 s. It stops 10 minutes after the last touch.
1033
- - `BLOCKYARD_MARKETS=0` (or `markets.enabled=false`) turns it off. Both endpoints then answer `{ "ok": true, "enabled": false, "note": "market data is off on this monitor (...)" }`.
1033
+ - **Off by default.** Polling runs only while the Display setting **Markets & Price Enable market polling** is on (`markets.polling` in the shared settings file, read per request). With it off, both endpoints answer `{ "ok": true, "enabled": false, "polling": false, "note": "market polling is off ..." }`, the call parks the feed, and the monitor makes no outbound connection but to the node.
1034
+ - `BLOCKYARD_MARKETS=0` (or `markets.enabled=false`) removes the feed altogether; both endpoints then answer `{ "ok": true, "enabled": false, "note": "market data is off on this server ..." }` whatever the setting.
1035
+ - **On demand.** With polling on, nothing is fetched until someone calls `/api/markets` or `/api/markets/depth`. Each call "touches" the feed. The dashboard's Overview makes that call by default (Display settings → Markets & Price → Price line on Overview), so a monitor with anyone on its landing page is polling. While touched, it polls tickers every 15 s, hourly candles every 5 min and order books every 30 s. It stops 10 minutes after the last touch.
1034
1036
  - An exchange that fails keeps its last data and reports `error`. It is never dropped or zero-filled.
1035
1037
 
1036
1038
  ### `GET /api/markets`
@@ -1222,7 +1224,7 @@ If the node refuses, the answer is `200` with `{ "ok": false, "action", "method"
1222
1224
 
1223
1225
  ## 15. Accounts, sessions, users and audit
1224
1226
 
1225
- These routes are meaningful only with `BLOCKYARD_AUTH=1`. In open mode they answer as noted.
1227
+ These routes are meaningful only with accounts on (the default). In open mode they answer as noted.
1226
1228
 
1227
1229
  The user object returned by these routes (`publicUser`):
1228
1230
 
@@ -1378,7 +1380,7 @@ The monitor's own health: process, RPC client, log tail, stream clients and the
1378
1380
  ```json
1379
1381
  {
1380
1382
  "self": { "t": 1789155700000, "rssMb": 175.6, "heapMb": 42.8, "sseClients": 5, "usersActive": 0,
1381
- "cpuPct": 2.71, "eventRate": 0, "build": "0.0.9-fd620adc52" },
1383
+ "cpuPct": 2.71, "eventRate": 0, "build": "0.1.0-fd620adc52" },
1382
1384
  "nodes": [
1383
1385
  { "id": "main",
1384
1386
  "rpc": { "nodeId": "main", "url": "http://127.0.0.1:8332", "cookieSource": "...", "online": true,