Wingman

RustWin32Ollama

Wingman lives behind the Copilot key on my own machine. Press it and it takes a screenshot of the active monitor, hands that to a vision model, and shows the verdict on a small card in the corner: no chat window, no back and forth. One action exists today, Check my work, and it runs against a cloud provider with your own key or entirely against a local Ollama model.

The rule I care most about is the offline one: switch to Offline mode and the app refuses any non-loopback network call before a socket ever opens, so there is a code-level guarantee behind the privacy claim rather than a promise in a settings screen.

Wingman, measured
MeasurementResultSource
Idle footprint~2 MB, 0% CPU until presseddocs/positioning.md, comparison table row 1
Card auto-dismiss12 seconds by defaultREADME.md, Settings worth knowing table (ui.card_seconds)
Offline moderefuses any non-loopback network call, enforced in codedocs/offline.md

GitHub

Syringe Pump

C++ArduinoAccelStepperGoogleTest

A NEMA 17 stepper turns an 8 mm lead screw through a flexible coupling, so the plunger speed, and with it the flow rate, is set directly by the step rate. The firmware drives an A4988 at 1/16 microstepping through AccelStepper, and an LCD shows the rate and the time left as it runs. A potentiometer sets the rate live, but it is wired backwards in hardware, so the firmware flips it with a constant named POT_REVERSED. A normally-closed limit switch and a set of LED interlocks handle the end of travel.

I no longer have the hardware. The pump math and the state machine are unit tested on a PC against the original firmware’s numbers, so the logic still has a way to prove itself even without a board on the bench.

Syringe Pump, measured
MeasurementResultSource
Flash used14,426 of 32,256 bytes (44%)README.md, Numbers table
RAM used791 of 2,048 bytes (38%)README.md, Numbers table
Steps per revolution3,200README.md, Numbers table
Flow rate range0 to 7.5 mL/min, 0.1 mL/min stepsREADME.md, Numbers table
Host unit tests40, all passingREADME.md, Numbers table

GitHub

AI-Song-lyrics-Generation

PythonPyTorch

This started as a Keras LSTM that wrote lyrics one character at a time. I rebuilt it in PyTorch to separate how much of the quality came from the model and how much from the data, so it now trains an LSTM, a GRU and two transformers on the exact same split and token budget and scores them against each other rather than picking a favourite by eye.

The model that writes the best text by that measure also copies the most from its training data on the n-gram check. That is the honest trade in this project: quality and originality pulled in opposite directions, and the table says so rather than just showing the nicest sample.

the answer my friend

Generated by the transformer (BPE) checkpoint, artist: Bob Dylan, prompt: "the answer my friend", temperature 0.9, top-k 40, top-p 0.9, repetition penalty 1.2

the answer my friend, it’s the fame I don't feel like me to be your eyes? Oh you hear me again, I won't leave us, I could fall with this world When I go back on And that we go through the street is gone In the door of the day that the wind With an old direction of my window And he’s so fixed but his head Well, don’t you can’t need someone for me to say To stay here I can tell him why you know what it’d like

AI-Song-lyrics-Generation, measured
MeasurementResultSource
Training tokens12.3M, same split and seed for all four modelsdocs/experiments.md, Setup
Test bits per characterLSTM 2.608 down to transformer (BPE) 1.892README.md, Results table
Novel 6-grams (memorization check)LSTM and GRU 1.000, transformer 0.998, transformer (BPE) 0.972, held-out real lyrics 0.462README.md, Results table and docs/experiments.md

GitHub

AI-Handwritten-Character-Recognition

PythonKerasTensorFlowNumPy

I built this to read handwritten digits and letters from image files with a small Keras CNN: two convolution blocks with batch norm and dropout, then a dense layer. It started as a tutorial MLP on MNIST, and that original baseline is still in the repo behind an --arch mlp flag so the CNN’s gain has something honest to measure against.

Preprocessing is most of what makes it work on real photos rather than just the test set: it crops to the ink, scales the longer side to 20 pixels and recenters by center of mass in a 28 by 28 frame, the same way MNIST itself was built, so an outside image ends up looking like the training data before it ever reaches the model.

AI-Handwritten-Character-Recognition, measured
MeasurementResultSource
MNIST (10 classes)MLP 98.09%, CNN 99.39%README.md, Results table
EMNIST balanced (47 classes)MLP 83.84%, CNN 88.46%README.md, Results table
EMNIST letters (26 classes)CNN 94.16%, MLP not trainedREADME.md, Results table

GitHub