Skip to main content
Engineering Resume

Nate Sproul

Software engineer. I build the whole thing — protocol up to interface, and the deploy underneath it.

Sole engineer on a manufacturing ERP in production. Every number here is measured from the repository.

Availability
Open to work
Remote, or relocating for the right role
Projects
24
Commits
3,608
Lines of code
576,488
Primary languages
Rust · Python · TypeScript · Java · JavaScript
Professional

Manufacturing ERP

Sole engineer/Metals manufacturing/2026 — present

Design, build, and operate the production system a metals manufacturer runs its floor on. Sole engineer on the project: architecture, backend, frontend, deploys, backups, and the on-call when something breaks at shift change.

Order intake through scheduling, weigh-in, pouring, finishing, shipping, and the paperwork each step is legally required to leave behind. Runs on the shop floor on kiosks as well as at desks, which means the interface has to work for someone in gloves who has not been trained on it.

Commits
2,381
Lines
251,377
Files
4,069

The client is not named here, and no screenshots of their system appear on this page. Their work stays theirs. Happy to talk through the architecture in an interview.

  • Sole engineer across backend, frontend, infrastructure, and production support.
  • Event-sourced audit trail — every state change is attributable after the fact, which the industry the client works in requires.
  • Floor-facing kiosk mode built separately from the back office, because operators and administrators want opposite things from the same data.
  • Nightly encrypted off-box backups with restore actually rehearsed, added after an incident proved the previous pipeline had been silently dead.
  • Automated deploys to on-premise hardware with health verification, so a bad release is caught before the floor sees it.
PythonFastAPIPostgreSQLTypeScriptReactDockerAlembicMinIO
Selected Work

Independent projects. Each one is here for a specific engineering problem rather than because it shipped.

01

spud

Rust

A Minecraft Java Edition client for machines that cannot run the real one. No JVM, no game engine, protocol written by hand.

Vanilla wants 1.5–3 GB of RAM and a GPU. spud holds 228 MB at render distance 8 and ships two renderers behind one interface — OpenGL, and a rasteriser that runs on the CPU with no window, no context, and no graphics hardware at all. The software path is the point: it is what makes "a machine that cannot run Minecraft" mean a machine with no GPU, not merely a slow one.

What it demonstratesWorking to a hard resource budget on hardware you do not get to choose, and writing the fallback path yourself when the fast path is unavailable.

Lines
41,191
Tests
353
Resident
228 MB
Block states
27,866
RustOpenGLCustom protocolPython tooling
Loading renderer
measuring

Every surface in that scene comes out of this atlas — shown here at twice its real size. It is generated at startup from a hash function, so the whole texture set costs a few kilobytes and belongs to nobody.

Running now, in this tab. No GPU and no WebGL — the same Rust rasteriser the desktop client uses, compiled to WebAssembly (95 KB gzipped, no third-party glue). Drag or use the arrow keys to rotate.
02

callroster

Python

A call-schedule solver for a surgical group — who works which night, fairly, under real constraints.

Call scheduling is a constraint problem people solve by hand in spreadsheets and then argue about. The solver assigns shifts against hard rules (rest windows, availability, coverage) while balancing the soft thing everyone actually cares about: whether the split is fair once part-time status and last year's carry-over are accounted for. It shows its reasoning, because a schedule nobody trusts does not get used.

What it demonstratesTurning a political, human problem into a constraint model — and making the output explain itself, because an answer nobody trusts does not get adopted.

Lines
15,206
Tests
131
PythonConstraint solverJavaScript
The callroster scheduler showing a solved year — twelve month calendars with every day colour-coded to the person on call, and a chip per provider carrying their day count. Provider names are demo placeholders.
The running app on a solved demo year. Provider names are placeholders, not real people.
03

shoalrun

Python

A rock and shoal hazard map for an unsurveyed Maine lake, built from satellite imagery.

The lake has no navigational chart. shoalrun derives hazard candidates from persistence across 30 Sentinel-2 scenes — a rock that shows up in most of them is probably a rock — and ships the result as an offline boating alert app. It is labelled a navigation aid and not a chart on every screen, because the honest version of this tool is the only safe one.

What it demonstratesDeriving a usable signal from noisy real-world data, and being disciplined about what the result is not allowed to claim when someone could get hurt.

Lines
17,721
Tests
102
Scenes
30
PythonSentinel-2JavaScriptOffline PWA
See it running
The shoalrun app running — a bathymetric map of Millinocket Lake with submerged shoal and exposed rock markers, a depth-under-boat readout, a proximity alarm, and an on-screen notice that it is an aid and not a chart.
The app running against the real hazard set, with a location on the lake supplied to the browser.
04

vodcut

Python

Turns a long recording into a tight edit. Local transcription, editorial cut list, frame-accurate render.

Most auto-editors score footage for "boringness" and cut on the score. vodcut deliberately does not: cheap signals only narrow attention, and the keep-or-cut call stays editorial. What it automates instead is everything mechanical around that decision — word-accurate cut boundaries, scene-snapped edges, reaction lead-ins, and motion graphics rasterised from HTML. It also reverse-engineers the cut list out of somebody else's finished video so you can measure their pacing against yours.

What it demonstratesKnowing which half of a problem to automate and which half to leave to judgement, then making the automated half frame-accurate.

Lines
11,081
Tests
358 passing
Cloud calls
None
Pythonfaster-whisperffmpegFastAPIHeadless Chrome
A contact sheet of nine vodcut motion-graphics templates captured mid-animation: title, lower-third, stat, bars, quote, points, chapter, code and compare.
Nine of the graphics templates, rendered by the tool at the same point in their animation.
05

mason

JavaScript

A bot that queues into a long-running anarchy server, walks a very long way from spawn, and builds procedural geometric statues.

The interesting part is not the building, it is surviving the trip. Hours-long login queues, a hostile world, nether-to-overworld routing over highways, and disconnects that have to be recovered from mid-journey without losing the mission. The statue at the far end is the proof the travel worked.

What it demonstratesLong-running autonomous processes that recover from failure mid-job instead of starting over.

Lines
18,485
Tests
325
Commits
268
Node.jsMinecraft protocolPathfinding
An isometric render of a voxel torus knot, 2,688 blocks, in the dark stone and netherrack palette the bot builds with near a nether highway.
The statue design the bot builds, 2,688 blocks — same shape and seed, rendered by mason's own isometric previewer.
Also Built
Python
A 6x6x6 lattice of 216 tap-code cells drawn in perspective, one cell lit gold as a message passes through it, its coordinates 1-4-2 and cost of 7 taps read out in the corner, and the layout's 13.62 taps per word alongside.

Tap code treated as a channel with unequal symbol costs, to find how few taps a word can possibly take.

A run of k taps costs k, which makes this an unequal-cost channel with a computable capacity and therefore a floor: 8.99 taps per spoken word. The constructed code reaches 9.02 against a standard grid's 21.98. The two things the construction had to get right were that the Kraft-style inequality is necessary but not sufficient here, so codeword lengths are made feasible by walking the tree rather than by trusting the bound, and that four of the bound's premises are load-bearing: relaxing the free word-boundary pause puts the best code at 6.24, straight through the floor.

Lines
8,598
Commits
16
Floor
8.99 taps/word
Python
The playtest harness printing a state digest — location, hit points, gold, the in-world clock — then two turns of resolved actions beneath it.

A single-player role-playing game where a language model narrates but never decides anything.

The save file is the only source of truth. Dice, rules, world generation and the clock are ordinary deterministic code; the model renders prose from that state and is structurally unable to invent a canonical fact. Every subsystem sits behind an interface, so the rules engine can be swapped without touching the narrator.

Lines
20,155
Tests
711
Commits
50
Python
The kinematics bench: the arm posed inside its reachable ring, a straight-line move drawn against the arc the joints would sweep instead, and a resolution panel reading 0.172 mm per microstep at full reach.

A printed four-axis robot arm and the software that drives it — kinematics, path planning, calibration, motion.

Aiming at a tenth of a millimetre of repeatability with printed plastic parts, which is a geometry problem before it is a control problem: both rotary axes are vertical so gravity loads the bearings in compression instead of bending the links.

Lines
5,046
Tests
148
Target
0.1-0.3 mm
TypeScript
Chapter one of Alice's Adventures in Wonderland with fifteen Japanese words woven into the English, furigana printed above each, and a margin panel counting the words woven so far.

Start a book in English and finish it in another language. Words swap over as you learn them.

A word is only ever woven in after you have met it as a flashcard, scheduled by the same algorithm Anki uses — so the text stays readable while it drifts, rather than becoming a wall of unknown words.

Lines
3,439
Tests
42
Commits
18
An ASCII dump of the world after 400 steps — three plants grown up from a sand bed, water pooled at the base, springs above — with a benchmark line underneath reading 940.3 Mcell-updates per second.

A falling-sand sandbox in C where the elements form little ecosystems that live, oscillate or collapse.

The eventual target is a search over element rules for ecosystems that sustain themselves, and a search is only worth starting if one simulation step is cheap — hence a SIMD path, a hand-written assembly kernel, and a measured 940 million cell updates a second.

Lines
1,862
Commits
11
Elements
8
TypeScript
A phone-sized terminal, two shell sessions in a tab strip, real command output from the desktop machine, and a row of one-tap keys along the bottom.

A command line on a desktop machine, reachable from a phone, with no inbound ports open.

The desktop dials out to a relay rather than listening for connections, so nothing has to be exposed to the internet: the phone talks to the relay, the machine talks to the relay, and TLS terminates at the edge.

Lines
2,653
Open ports
None
TypeScript
The lodestone board with four clips laid out on the infinite canvas, the media list on the left and the board tools along the bottom.

A video editor with no timeline. Clips, filters and outputs are objects on an infinite board that you snap together.

Stacking a filter onto a clip and placing a clip beside another are different operations, so the editor keeps them different gestures rather than collapsing both into one node graph.

Lines
15,218
Tests
328
JavaScript
The tvwindow scene: a room rendered behind the screen with clock, weather and inbox panels floating in it, drawn with an off-axis projection.

Turns a TV into a window. A webcam tracks your head and the scene behind the glass moves with you.

Head-coupled perspective fights stereo cues rather than adding to them, so the whole build is about tracking latency and honest depth rather than 3D tricks.

Lines
31,755
Commits
22
Java
The tvhome launcher on an Android TV: four large tiles, two of them dimmed and labelled not installed, over a particle background.

A home screen for an Android TV with four things on it and no advertising.

Built without Gradle, and defensive about a detail the platform gets wrong: the same app carries different package ids on different devices, so a tile whose apps are all missing renders dimmed rather than looking live and doing nothing.

Lines
33,086
Commits
89
Rust
Terminal output from portal list and portal ping, showing the saved servers and a live ping reporting protocol, players, latency and whether a modpack was advertised.

A Minecraft launcher where you pick a server, not an instance.

Inverts the usual model: the server you want to join is the thing you choose, and the launcher works out what version and mods that implies.

Lines
14,354
Commits
19
TypeScript
The homestream browse screen with a featured title, description and play controls, over a full-bleed backdrop.

A private media server for family, hardened until a non-technical user could not break it.

Deploys use blue/green slots specifically so shipping a release never cuts a stream someone is in the middle of watching.

Commits
239
Files
482
Python
A Physarum simulation: pale branching filaments forming a self-organising transport network on a dark background.

A slime-mould simulation that renders to the desktop wallpaper.

Runs as a headless PNG rewrite rather than a compositor plugin, which keeps it at roughly 3% of one core and leaves the desktop shell at zero.

Lines
509
Tests
8
CPU, one core
~3%
Terminal output from two athanor verify runs, the reference oracle and the native simulator agreeing exactly on all four metrics.

A solver for Opus Magnum, a game about building chemical assembly machines. The part that exists is the referee.

Before a search can optimise anything it needs a simulator it can trust, so the native one is differentially tested against the reference implementation over a 4,500-solution community corpus — every solution run through both and compared.

Lines
7,523
Commits
39
Corpus
4,500
Python
The vault browser interface, unlocked: a list of five sample documents with categories and tags, and a preview pane showing one of them.

An encrypted store for personal records — medical, financial, legal — that is safe to carry on a USB stick.

Each document is encrypted separately, so the store is nothing but ciphertext and a lost stick leaks nothing. Plaintext is only ever written to tmpfs, and the README says plainly that disk-backed swap breaks that guarantee rather than pretending it doesn't.

Lines
13,568
Tests
422
Python
A table comparing direct speech translation against a cascade for Chinese, Spanish and Japanese, with chrF, BLEU and speed.

Two people wear a pair of glasses each and talk in languages they don't share. Each hears the other in their own.

Published latency figures are not comparable between models, so this is a measurement harness before it is a product: every engine timed in the same condition, end to end, with a written list of what has not been measured yet.

Lines
4,461
Tests
81
Python
A rendered factwire digest: stories grouped by category, each with fact bullets, a where-they-diverge note, and the outlets that carried it.

A twice-daily news digest that tries to be neutral by construction rather than by tone.

Neutrality is enforced mechanically, not editorially: a wire-service base layer, a corroboration threshold a story has to clear across outlets before it is included, and spectrum tagging on what survives.

Lines
2,717
Tests
102
Status
Running daily
Python
The chaoslock desktop app showing its chaos chamber: balls and bumpers scattered across a physics playfield, with sliders for particles, energy and time limit.

Encryption built on a chaotic physics simulation: set the starting conditions from your input, run it, read off where everything landed.

The same primitive gives a time-lock — opening costs a fixed grind, because the simulation cannot be skipped ahead. Written up with its own limits stated: the construction is heuristic rather than a proven verifiable delay function, and unaudited.

Lines
3,419
Tests
39
TypeScript
The sealrender editor with an intarsia seal-and-kelp panel traced into 239 numbered pieces, layers and wood species listed down the left, and the audit panel reporting piece widths.

A vector editor for intarsia — wood inlay — that turns a photo of a panel into a numbered pattern, a cut list, and a DXF.

The export is the hard part: a DXF a CNC will actually read, rather than one that opens in a viewer and fails on the machine.

Lines
6,247
Commits
22
TypeScript
A solved week of meals, each day showing breakfast, lunch and dinner with calorie and macro totals against the target.

Picks a week of meals against nutrition targets and a budget, then fills a grocery cart with the result.

The plan is solved rather than sampled from a recipe list, and the last mile is the awkward one: matching solver output to real store items, where the top search results are unlabelled ads for something else.

Lines
7,822
Tests
194
Capabilities

Systems

spud · portal · athanor

Hand-rolled binary protocols, software rasterisation, memory-budgeted rendering, simulators checked against a reference implementation, and Rust where the budget is tight.

Backend

the ERP · callroster · vodcut

Python and FastAPI over PostgreSQL, event-sourced audit trails, Alembic migrations, constraint solvers, and background pipelines that have to survive bad input.

Frontend

the ERP kiosk · tvhome · sealrender · lodestone

React and TypeScript, Next.js, canvas and WebGL rendering, plus D-pad and kiosk interfaces for people who are not sitting at a desk.

Infrastructure

the ERP · homestream

Docker, on-premise deploys with health verification, blue/green releases, encrypted off-site backups with rehearsed restores, and the monitoring that catches a pipeline that has quietly died.

Correctness

shoalrun · athanor · vodcut

Hypothesis property tests fuzzing a binary sonar-log parser with arbitrary bytes, a simulator checked against a reference implementation over a 4,500-case corpus, ground-truth fixtures for pipelines whose output is subjective, and a preference for failing loudly over silently coercing bad data.

Looking for work.

This page makes no third-party requests and renders completely with JavaScript disabled. Every figure on it is measured from the repository, not estimated.

request copper-distant-meadow · commit de13561 · rendered in 3,289μs · 2026-09-02 11:07:58ZServer-rendered for this request. Reload and these change.