My Projects
Explore my coding experiments and technical innovations
13 projects, 2024–2026 · 2 hardware, 11 software · Python (2) · JavaScript / Node (11)
A Star Map for Any Date, Drawn in the Browser
How the Polyatic star map turns a date, a time and a place into the sky that was overhead: the 1,630-star catalogue it ships, the four coordinate steps from that catalogue to the paper (with the real function names).
A One-Thumb Action RPG in PixiJS: Keeping a Crowd of Monsters Moving
How DankLoot, a one-thumb dungeon game that runs in a browser tab, keeps hundreds of monsters on screen: a fixed-step simulation under PixiJS's frame loop, object pools that stop allocating once a fight starts.
Friend Duels Over a WebSocket Referee: a Small Server That Checks Every Move
How the Duel mode of a browser strategy game is refereed by a small Node process: the 5 browser and 11 server message types on the wire, a server that imports the very rules modules the page runs and refuses illegal moves.
One Exact Answer per Page: How a Symbol-Lookup Site Was Built, and What Found It in Its First Weeks
How semiatic, a static site that tells you what a symbol on a laundry label, car dashboard, oven dial or package means, is built: symbol data in JSON with sources recorded entry by entry, drawings generated from code.
One Node Script, No Framework: How an Essay Site Is Built, and Which Essays ChatGPT Sent Readers To
How aitheism, a site of essays on AI, mind and belief, is generated by one Node script from one array of essays, with no framework and no dependencies; the tests that keep it honest (a rebuild that must reproduce every committed byte.
Two Thousand Pages From One City File: Operating a Programmatic Static Site
How 2,197 static pages come out of a 152-entry city file and one 11,156-line Node script (measured 2026-09-05) with no framework and no dependencies.
Generating 3D-Printable Parts From Code
A dependency-free Node geometry kernel and binary-STL writer that turns parameters into printable parts, guarded by a solid-interpenetration check, a caliper-style fit measurement, a re-parse of the written bytes by a separate reader.
Two Transports for One Chess Game: a WebSocket Relay and a WebRTC Data Channel
Why the online board on dankchess.com sends moves over a WebSocket relay and chat over a WebRTC data channel between the two browsers — the seven-message relay vocabulary, the per-match byte arithmetic, and what the split costs.
Routes With No File Behind Them: Prerendering a Single-Page App Without Cloaking
How a client-routed site whose URLs have no file behind them stays legible to search: an unknown-path fallback that returns the app shell, a prerendered document per advertised route served behind a User-Agent allowlist.
XRechnung and EN 16931 Invoice Validator
A zero-dependency Python conformance validator for EN 16931 invoices — UBL 2.1, UN/CEFACT CII, the German XRechnung CIUS, and the XML embedded in Factur-X / ZUGFeRD PDFs.
Raspberry Pi Bluetooth Tracker
A Node.js scanner for the Raspberry Pi 5 that drives bluetoothctl through node-pty and turns each device's RSSI into metres in data.json. The write-up covers the nine-line formula, the hard-coded -59 dBm TxPower and why distances stretch.
WiFi Security Monitor
Two Python programs for Linux that read a monitor-mode WiFi adapter: a deauth detector scoring every attack 0-100, and a device monitor tracking what joins the network. The write-up walks setup, every config key and the four threat bands.
Oscillationa X/Twitter Bot
An X/Twitter bot that interacts with people on X/Twitter and responds to replies.
What these 13 write-ups have in common
Each one is a thing I built and can still open the source of, written up afterwards by someone trying to work out what it actually does rather than sell it. That shows up most plainly in what the pages refuse to claim: the tracker write-up ends on a section headed “What the Code Does Not Do”, the parts generator opens by stating that none of its four parts has been printed by anyone, and the bot write-up carries a section headed “What this page does not claim”. They run from 2024 to 2026. 2 of them are Python; 11 are JavaScript or Node.
2 of them point at hardware — Generating 3D-Printable Parts From Code and Raspberry Pi Bluetooth Tracker. The tracker reads real radios on a Raspberry Pi 5 and turns what they report into metres; the parts kernel turns parameters into binary STL files whose destination is a 3D printer. The other 11 run on the machine you already have, with one caveat worth knowing before you clone anything: the WiFi Security Monitor is ordinary Python, but it needs a WiFi adapter that supports monitor mode — “the one part you cannot substitute”, in its own words — and its page notes that built-in laptop WiFi typically does not.
Which one to open first
If you arrived from a search, this is the shortest route from the thing you asked to the page that answers it.
- Detecting deauthentication attacks, or getting a card into monitor mode on Linux — WiFi Security Monitor. A deauth detector that scores every attack 0-100 and a separate network device monitor, both Python. The page walks every config key, the four threat bands, the adapters its README lists as confirmed working, and the limit that costs you the most: a monitor-mode radio hears one channel at a time, so on the shipped five-channel hop it is on any given channel 20% of the time.
- Turning a Bluetooth signal into a distance in metres — Raspberry Pi Bluetooth Tracker. Node driving
bluetoothctlthrough node-pty on a Raspberry Pi 5. The distance formula is the free-space path-loss model, TxPower is hard-coded at -59 dBm for every device, and the page works back from the 158 m circle on its retired map to the single -103 dBm reading that drew it. - Building a site of thousands of pages out of one data file — Two Thousand Pages From One City File. 2,197 HTML files written by one Node script from a file of 152 cities, with no framework and no dependencies: the content-hash asset URL that turns a one-line stylesheet edit into a 2,197-file diff, the 18 guards that run before a commit, and the 675 pages live 21 or more days that no search engine has ever referred anyone to.
- Making a client-routed single-page app legible to crawlers — Routes With No File Behind Them. An unknown-path fallback that returns the app shell, plus one prerendered static document per advertised route (18,214–22,621 bytes on the wire) served behind a User-Agent allowlist — and the argument for why that branch is not cloaking: where the responses differ, the crawler gets less, and every prerendered file is a snapshot of what a visitor's browser renders at the same URL.
- Getting moves and chat between a pair of browsers — Two Transports for One Chess Game. Moves ride a WebSocket relay; chat rides a WebRTC data channel opened directly between the players. The relay's whole vocabulary is a short fixed list of message types, a move frame measures about 110 bytes of JSON against a 1,024-byte ceiling, and durability is zero on purpose — 0 bytes on disk.
- Checking an e-invoice against EN 16931 without uploading it anywhere — XRechnung and EN 16931 Invoice Validator. A Python conformance validator built on
the standard library alone — no
lxml, no Java runtime, no Schematron or XSLT toolchain, no network calls — that grades UBL, UN/CEFACT CII, the German XRechnung CIUS and the XML embedded inside Factur-X / ZUGFeRD PDFs, and exits with a code a CI job can gate on. - Emitting a printable part from parameters instead of from clicks in a
modeller — Generating 3D-Printable Parts From Code. A CommonJS geometry kernel
whose every
requireis a Node builtin or a sibling file, writing binary STL at exactly 84 + 50 × triangles bytes, checked by a solid-interpenetration test, a caliper-style fit measurement and a re-parse of the written bytes by a separate reader. What none of that can tell you is how a part behaves once it is out of the printer, and the page leads with that rather than burying it. - The oldest entry here, from 2024 — Oscillationa X/Twitter Bot. An AI persona that publishes to X and to its own gallery. The write-up is a measurement of what is visible from outside — 899 works, 337 tag pages and its collection pages, reconciled against a sitemap of 1,292 URLs — because the generating side is private, was not inspected, and the page says so.