Wisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it now
Wisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it nowWisteria is now live — try it now

Projects

Wisteria
Featured

Wisteria

RustAudioLocal-first

Local-first voice dictation

Hold a key, speak, release — clean, formatted text appears at your cursor in any app. No cloud round-trip, no account, no telemetry. Everything runs on your machine.

Why it exists

Dictation tools either ship your audio to someone else's server or feel clunky enough that you stop reaching for them. Wisteria is the opposite: press-to-talk muscle memory, instant insert, private by default. Your voice never leaves the device.

How it works

  • A global hotkey captures audio only while the key is held.
  • Speech is transcribed locally and lightly formatted — capitalisation, punctuation, sentence breaks — so it reads like something you typed, not a raw transcript.
  • The result is injected at the active cursor through the OS input layer, so it lands in your editor, your browser, your chat box — wherever the caret is.

Built in Rust

Written in Rust for a small, fast, dependency-light binary that starts instantly and sits quietly in the background. Low latency between "release key" and "text on screen" is the whole point, and a native binary is how you get there.

Open-source and hackable — bring your own model, remap the key, tune the formatting.

Imposter Game

Imposter Game

Node.jsExpressWebSockets

One player gets a different word

Everyone is handed the same word or question — except one player, who quietly gets a different one. Each person describes theirs out loud, then the room votes on who's lying. Simple to explain, genuinely hard to win.

Built for a full table

  • Real-time rounds over WebSockets — no refresh, no polling, no lag.
  • 110+ curated word and question sets, so games stay fresh across a long night.
  • Rolling history so prompts don't repeat themselves round to round.

Under the hood

A tight Node.js + Express backend drives the game loop: lobby creation, role assignment, the describe phase, voting, and scoring all coordinated server-side so every client stays in sync. The frontend stays deliberately thin — the server is the single source of truth for game state.

What it taught me

Real-time multiplayer is where "works on my machine" goes to die: race conditions, reconnects, players who close the tab mid-round. Making it feel instant and correct for a whole room at once was the real project.

Useless Tokenizer

Useless Tokenizer

PythonNLP

Proof that depth and usefulness are different axes

very_useless_tokenizer is exactly what it says on the tin: a from-scratch tokenizer built to understand tokenization end to end — not to be imported by anyone, ever.

The point

Reading about byte-pair encoding is one thing; implementing it until the edge cases stop surprising you is another. This project is the second thing. It is deliberately impractical and deliberately educational — a place to get the concepts wrong a few times in private.

What it actually does

  • Builds a vocabulary from raw text the slow, legible way.
  • Merges tokens step by step so you can watch BPE happen instead of trusting a library.
  • Encodes and decodes round-trip, mostly to prove the mental model holds up.

Why keep it public

Because the best way to learn something is to build the useless version first, and then leave it out where the next person can see the working — bugs, dead ends, and all. It's a study project, and it wears that honestly.