Hobby Projects

Things built for fun, mostly to learn something new.

Live
Vanilla JS WebSockets Node.js
Battleships
A real-time two-player Battleships game built for the family. Players join via QR code or room code on any device. Built to learn WebSocket-based multiplayer — a custom Node.js server handles all game state and relays moves in real time, with no third-party backend.
↗
PHP Solis API Solcast HMAC Auth Chart.js
Solar Dashboard
Built to learn third-party API authentication and data visualisation. Live generation, consumption and battery data is fetched from a Solis inverter via their Cloud API (HMAC-SHA1 signed requests). Solar forecast data comes from Solcast. Results are cached server-side and rendered as charts.
↗
PHP MariaDB Strava API Open-Meteo Gmail IMAP Leaflet
Running Log
Built to learn REST API integration, OAuth token management and server-side data caching. Activity history is synced from the Strava API and stored in MariaDB. Each run shows pace splits, HR zones, a Leaflet map with km markers, weather from Open-Meteo, and official parkrun times parsed directly from Gmail via IMAP.
↗
Vanilla JS Firebase ElevenLabs
Learning Adventure
A daily maths and English app built for my two children, each at a different key stage — they pick themselves at the start and get their own companion, question bank and progress. Built to learn client-side state sync: progress is mirrored to Firebase Realtime Database so it follows each child between devices. All speech is pre-generated with ElevenLabs into static audio, so the app ships no API key and makes no calls at runtime.
↗
Three.js WebGL Canvas Textures
3D House Walkthrough
A walkable 3D tour of a house we were buying, built from nothing but the real estate agent's floorplan and listing photos. Built to learn 3D geometry and texturing from scratch: room outlines, walls, doors and windows are traced and scaled from the floorplan into real-world metres, then every surface — tile, carpet, brick, paint — is a texture painted procedurally onto a canvas, not a photo or downloaded asset. WASD movement with pointer-lock mouse look, a live minimap synced to the floorplan, and a side-by-side toggle against the original listing photos to check the model against reality.
↗