Sam Poplett

This page plays by itself. Scroll to take over.

Seven projects

Each project is one page of the album. Each claim names a file. The file name is a link to that file on GitHub.

A comic panel: the astronaut takes one tall album from a long shelf of books in the small library of the ship. A round porthole shows a ringed planet.

Provenance

A live globe of public open data

TypeScript, Next.js 15, React 19, MapLibre GL

The Provenance landing page. A dark globe with teal cable lines and coloured dots sits behind the headline 'You already paid for this.'

Governments and agencies publish live data for free, in formats that few people can read. Provenance draws those feeds on one globe that flattens into a map. Every layer carries a card with its publisher, its method, a confidence class and a limitation.

  • 405 unit test files at commit e1efc15. tests/unit
  • 92 stars and 15 forks on GitHub on 8 October 2026.
  • Licence: AGPL-3.0 for the code. Each data source keeps its own terms. LICENSE
  • The Provenance console: a dark world map covered in clustered dots of cameras and events.
    The console at /app, world view.
  • A dark page headed 'Every dot has a receipt.' A block of raw earthquake JSON from the United States Geological Survey points with an arrow to a panel.
    A raw earthquake record beside the pin that it becomes.
  • A camera page titled 'A406 Billet Upass E'. A road camera still sits above a table of source, location, coordinates, status and refresh time.
    One camera page. The still is from TfL Open Data.

Unote

A notes app for university students

TypeScript, React 19, Express 5, Postgres, Electron

The Unote editor. A note titled Dijkstra's algorithm shows a callout, a formula and a table, with a list of notebooks on the left.

Lecture notes, flashcards, sources and boards in one place. A note is made of blocks: maths, code, tables and callouts. The source library resolves a DOI or an ISBN and says if the record agrees. The same build runs in the browser and in an Electron shell.

  • 46 server test files, 47 web test files and 22 browser test files at commit 014376a. server/test
  • Licence: AGPL-3.0. LICENSE
  • The Unote source library with ten sources. Each row carries a label such as Verified, Refuted or Unreachable.
    The source library, with a verdict on each row.
  • The Unote study view with a flashcard that asks why Dijkstra fails on negative edge weights.
    Flashcards.
  • A Unote board with coloured sticky notes for four shortest-path algorithms.
    A board.

Kitchen Vision

A camera that follows people and knows them

Python, CUDA, InsightFace, FastAPI, React

The Kitchen Vision dashboard on its Live tab: the camera feed of a room with tracking lines drawn over it, beside status tiles.

Two machines. The head is a Raspberry Pi with a camera on a servo. The brain is a laptop with an NVIDIA GPU: it recognises faces, tracks several people, and writes what they do to a timeline. Face data stays on the laptop.

  • The Pi only captures video and moves the servo. The laptop does all the machine learning.

    The file head/agent.py

  • The servo runs on the hardware PWM of the Pi, not on a software timer.

    The file head/agent.py

  • To delete a person deletes their face data, sightings, events and activity log.

    The file brain/kitchenvision/store/db.py

  • 96 test functions in 11 files at commit c4d56ca. They run with no camera. brain/tests
  • The Analytics tab: a bar chart of presence time for each person and a chart of events.
    Presence time and events.

NewsScraper

World news, turned into events on a map

Python, SQLite, DeepSeek, systemd

A comic panel: the astronaut holds a paper tape from a wall machine and presses a pin into a round wall map.
This project has no screen to show. The picture is a drawing, not a screenshot.

A pipeline in separate stages: scrape, extract, resolve the place, cluster, publish. Each stage is one command on one SQLite store and goes on where it stopped. A model reads each story. Code then checks the answer of the model against the text.

  • A quote that says where a person spoke to a reporter is not proof of where an event happened. The check rejects it.

    The file newsfeed/extract.py

  • Each stage is a separate command on one SQLite store.

    The file newsfeed/__main__.py

  • The snapshot that goes to Provenance carries an HMAC signature.

    The file newsfeed/sign.py

  • 656 test functions in 22 files at commit 3b7de04. tests

Prospector

A Reddit miner for unmet needs

Python, SQLite, FastMCP

A comic panel: the astronaut kneels at a stream and holds a sieve pan with three orange nuggets among grey pebbles.
This project has no screen to show. The picture is a drawing, not a screenshot.

A topic is one YAML file: the subreddits, the search terms and a list of weighted patterns. The tool reads public posts, scores each one, and writes a report of needs that come back again and again. Each need shows its links and its quotes.

  • 163 test functions in 12 files at commit 499c09f. tests
  • Licence: MIT. LICENSE

TrafficNerd

London traffic cameras in a terminal

Python, Textual, httpx, Pydantic

The TrafficNerd Situation Room in a terminal: a map of dots, a camera list, a disruption feed and tube status.

A console for the terminal. It lists the public JamCam feeds, plots them on a map made of characters, and estimates congestion from two frames of one camera. Provenance took the same idea to a browser and to the whole world.

  • A terminal full of blue dots that draw the shape of London: one dot for each camera.
    Every camera by latitude and longitude.
  • A road camera picture drawn in block characters in a terminal, with a list of nearby cameras.
    One camera, drawn in block characters.

EasyBooks

Receipts to tax records, on a phone

Python, FastAPI, HTMX, SQLAlchemy

The EasyBooks capture screen on a phone, with a large green button to scan a receipt.

An installable web app for a phone. A vision model reads the amount, the date and the vendor of a receipt. The person confirms, and the entry maps to a box of the SA103 tax form. One tap builds a pack for the accountant.

  • Every database query goes through one object that adds the user id.

    The file app/db.py

  • It runs with an empty .env file. Each cloud service has a local stand-in.

    The file app/config.py

  • Sign-in is a 6-digit code by email, with no password.

    The file app/security.py

  • A phone screen that shows what the app read from a receipt, with the amount in large figures.
    Confirm what the app read.
  • A phone screen of records for one tax year: money in, money out and what is left.
    Records by tax year.
  • A phone screen that says where the person stands against the tax threshold.
    Where you stand.

The next page is not drawn yet

For a role or a project, write to me.

Write to me