booting lab…
45% Keyboard — Patrick Fan×
← Back
https://patrickfan.dev/projects/keyboard45
45% Keyboard screenshot
  • PCB designed in KiCad, SMDs hand-soldered
  • Aluminium case CNC-machined from my own CAM setup
  • Custom QMK-based firmware brings it to life

What it is

A fully custom 45% mechanical keyboard, built solo from bare components to a working daily tool. Every layer is mine: the PCB designed in KiCad, the case CNC-machined from aluminium, the SMD components hand-soldered, and the firmware written to tie it all together.

The build

The 45% form factor squeezes a full typing experience into a board smaller than a compact 60% — which means the matrix, controller placement and case geometry all had to be worked out from scratch. CAM toolpaths for the case were programmed and machined as part of the project.

CAM toolpaths over the keyboard case model
CAM: the case machining toolpaths, programmed from scratch.
CNC-machined aluminium keyboard case on the workshop bench
Fresh off the CNC: the aluminium case, still showing its toolmarks.

KiCadCNC machiningSMD solderingQMK firmwareCAD/CAM

Done — keyboard45.html loaded
Nothing Playground — Patrick Fan×
← Back
https://patrickfan.dev/projects/playground
Nothing Playground screenshot
  • Describe a widget in chat — it builds, deploys to your phone
  • 112 merged PRs across web, backend, Android app, and infra
  • Built the usage/credits system, observability, beta onboarding

What it is

Nothing Playground is Nothing's AI widget-builder: describe an app or widget in plain language and it gets built, previewed, and deployed to your phone's home screen — then shared with the community for others to install and remix. It shipped publicly with Nothing OS 4.0.

Essential Apps gallery on playground.nothing.tech showing community-built widgets
The community gallery: Tetris, transit maps, weather outfit tips — all built by users in chat.

What I built

I worked across the whole platform — web, backend, the Android builder app, and the infrastructure underneath — from before the beta to well past launch: 112 merged PRs across the product's three repos.

  • Usage metering & credits — the billing system end to end: schema and migrations, the charge/gate services, rate-limit handling in the API, token pricing, and the usage UI in both the web app and the Android builder.
  • Android builder app — the widget snapshot pipeline that captures on-device thumbnails and syncs them to the backend, plus Figma-matched share cards for posting creations to the sharesheet.
  • LLM serving reliability — provider failover with regional round-robin and exponential backoff so widget builds survive capacity spikes, load-tested end to end.
  • Product observability — distributed tracing with LLM-call instrumentation, browser and mobile session telemetry, and funnel and cost dashboards (build failure rates, deploy tracking, token usage).
  • Beta onboarding pipeline — turned a manual process into an automated invite → survey → whitelist flow in the admin dashboard, with batch emails and a background job keeping the community beta group in sync.
  • CI/CD & cloud infrastructure — Terraform-managed infra, secrets management, release tooling for signed Android builds, and a CI overhaul that builds only the apps a change touches and parallelizes rollouts.

Try it

Browse community-built apps at the live site — or build your own if you have a Nothing phone.

TypeScriptPython / FastAPIKotlin / ComposeTerraformAWSDatadogPostgres

Done — playground.html loaded
BLE Recorder — Patrick Fan×
← Back
https://patrickfan.dev/projects/blerecorder
BLE Recorder screenshot
  • One mechanical key: press to record, press to send
  • nRF52840 firmware streams ADPCM audio over BLE
  • Android + iOS apps, custom enclosure — every layer mine

What it is

A pocket voice recorder that is just one mechanical key. Press it and the onboard mic starts recording; press again and the audio lands on your phone as a WAV file. No screen, no pairing dance — the link stays connected and reconnects on its own.

Every layer is custom: the firmware on a Seeed XIAO nRF52840 Sense, the BLE audio protocol, the Android and iOS companion apps, and the 3D-printed enclosure around a single MX-style switch.

How it works

  • The PDM mic captures 16 kHz / 16-bit mono into a ring buffer via DMA; audio is IMA-ADPCM encoded and packetized on the wire.
  • Streaming rides BLE notifications on a 2M PHY link — MTU 247, 15 ms connection interval, ~34 packets per second.
  • The phone app reassembles the stream, checks for sequence gaps, writes WAV files as data arrives, and shows link quality and battery.
  • Runs off a 140 mAh LiPo charged over the same USB-C used for flashing — idle power mattered in every design decision.

nRF52840Embedded CBLEADPCMAndroidiOSCAD / 3D printing

Done — blerecorder.html loaded
Foodscape — Patrick Fan×
← Back
https://patrickfan.dev/projects/foodscape
Foodscape screenshot
  • Real London buildings re-skinned as their best restaurant's food
  • Voice agent flies the camera: “find me italian”
  • Autonomous agent keeps the food-city true to the real world

What it is

An isometric.nyc for London — built out of food. Every tile is the real building at that London spot (its actual massing, storeys, roofline, footprint) re-skinned in the signature food of the best restaurant there: a Soho townhouse rebuilt out of sushi, a Victorian terrace re-skinned as spaghetti, a railway arch made of tacos.

It is not a one-shot generator — an autonomous agent keeps the food-city true to the real world.

Zoomed view of Soho blocks with individual food buildings
Up close: each colored building is a real address wearing its best restaurant's dish.

Try it

Open the live site, click the glowing blue orb and say "find me italian" — the camera flies to the matches, rings them, and JARVIS answers out loud. Drag to pan, scroll to zoom.

TypeScriptVercelPixel artVoice agent

Done — foodscape.html loaded
Wing Flutter Control — Patrick Fan×
← Back
https://patrickfan.dev/projects/flutter-wing
Wing Flutter Control screenshot
  • 1.2 m flexible wind-tunnel wing, simulated in SHARPy then built for real
  • ESP-32 closes the loop over an accelerometer and load cell
  • Active control cut flutter oscillations by 40%

What it is

My final-year masters project at Imperial College London (Oct 2024 – Jun 2025): stopping a flexible wing from shaking itself apart. Flutter is the aeroelastic instability where aerodynamic forces and a wing's own structural dynamics feed each other until the oscillation grows — and the fix was to sense it and actively fight it in real time.

I simulated and designed the wing in SHARPy, an open-source aeroelastic solver, then built and tested a fully functional 1.2 metre wind tunnel model around it.

The build

The model wing carries an integrated accelerometer and load cell, read and acted on by an ESP-32 running the control loop. In the wind tunnel, the closed-loop controller reduced flutter oscillations by 40%.

SHARPyPythonESP-32Embedded systemsWind tunnel testing

Done — flutter-wing.html loaded
Layout Learner — Patrick Fan×
← Back
https://patrickfan.dev/projects/layout-learner
Layout Learner screenshot
  • Guided drills for alternate keyboard layouts
  • On-screen keyboard shows what your fingers should do
  • Live on Vercel

What it is

A web application that helps anyone learn alternate keyboard layouts and shortcuts — guided, in the browser, with an on-screen keyboard that shows what your fingers should be doing.

Why

Switching layouts (Colemak, Dvorak, or a custom split-board setup) has a brutal cold-start. Layout Learner shortens it with focused drills instead of raw typing tests.

Define any layout

Layout viewer rendering a Dvorak keyboard from a JSON definition
Layouts are plain JSON — paste one (or pick a preset) and the viewer renders the board you'll drill on.

TypeScriptReactVercel

Done — layout-learner.html loaded