
Neuron-1
Contract rebuild of an EEG neurofeedback app, from Unity and C# to React Native.
Software Engineering Contractor · Mar 2026 – present · Live
React Native · Expo · TypeScript · XState · BLE · GitHub Actions
Solo rewrite, with a CI gate that proves the ported math still matches the reference
BioSoftPro makes an EEG neurofeedback trainer. A headset streams brain activity, the app reduces it to a single number in real time, and that number drives a set of feedback games. I rebuilt the mobile client on my own, porting it off Unity and C# onto React Native and Expo: about 16 screens across 8 flows, 4 real-time games, the Bluetooth stack, and the whole signal path. Neuron1 is on the App Store. The last two images are renders of the amplifier it talks to.
The problem
The app worked, but it was a Unity project inside a company whose other products are not. Every change to the signal code meant a multi-hop build: publish a library, copy it into Unity's plugin folder, rebuild the app. The team ran Windows only and had never produced an iOS build.
The shared core also could not be carried into an app-store binary as it stood. The question I was hired to answer was whether leaving Unity was possible at all.
Constraints
One constraint dominated everything else. The company's desktop products and the mobile app are supposed to compute the same score from the same signal, and they did that by sharing one compiled core. React Native cannot run that core on a phone.
So the moment I ported the math to TypeScript, I owned a second implementation that could drift from the first without anyone noticing. The reference is closed source, so I could not read it, and its owner keeps changing it. I could not get a golden test vector either.
What I built
I wrote a harness that runs the real reference once over a real recording and dumps its output to JSON, then a test that runs my TypeScript port over the same input and compares the two element by element. That test runs on every push.
A second job runs on a schedule, checks whether the upstream owner has changed the compiled reference, and if so rebuilds the goldens, re-runs the comparison, and turns the build red with a numeric diagnosis and a re-port runbook. Because the phone runs a different JavaScript engine than CI does, I also built an on-device replay screen that repeats the same comparison on real hardware.
What I owned
All of it. I wrote the rebuild plan, ran an architecture audit that rejected a shared-native-core approach on determinism and build-fragility grounds, then executed the port: the screens, the session state machine, the four games, the Bluetooth stack, the Firebase backend, the CI, and the release pipeline.
That audit was AI-assisted, a tool I used to pressure-test my own plan, not a team behind me. The hardware, the firmware, and the original signal-processing design are the client's. My job was to make the phone agree with them.
Results
The port shipped. The team has its first iOS build, one codebase instead of Unity plus a native plugin chain, and hot reload where there used to be a multi-step rebuild.
Parity with the reference is proven on every push and on the phone itself, not only in CI. On the hardware side I wrote the Bluetooth stack against the real headset and verified streaming end to end, which meant root-causing defects below my own layer.
What I would change
I would write the drift gate before the port, not after. I ported first and built the comparison harness once I had something to compare, which left a stretch where I was writing signal code with no way to check it beyond reading numbers and squinting. Building the harness first would have made every step verifiable from the start.
I would also push harder and earlier for the reference's source, or at least a committed test vector. I worked around having neither, and the workaround is good, but some of that engineering exists because a conversation did not happen.