Divoom Ditoo Pro · Bluetooth LE
custom firmware
Divoom Ditoo Pro: reverse-engineered firmware
The Ditoo Pro is a 16×16 pixel-art Bluetooth speaker that only does what Divoom's phone app allows. I wanted to use it as a small screen and button pad for my smart home, so I reverse-engineered its firmware and Bluetooth LE protocol, added my own code to the firmware, and built a Home Assistant integration on top of it.
- Firmware: downloaded the stock images from Divoom's update server and patched out the version check (fixing the checksums), so the device accepts my own builds. I built a cross-compiler for its Andes CPU and wrote a Bluetooth flasher plus a checker that compares every build against stock, to keep flashing safe and going back to stock always possible.
- Remote mode: my own C code added to the firmware and hooked into the stock code. Through a new Bluetooth command, a computer can draw frames on the screen, receive button presses as live events and read the battery. A watchdog and an automatic exit when the connection drops keep the device from getting stuck.
- Home Assistant: a custom integration with automatic Bluetooth discovery. Brightness, volume, channel and battery show up as entities, every button can trigger automations (like toggling a lamp), and services show scrolling text, images and weather on the screen. It reconnects on its own after a disconnect.
Reverse engineeringEmbedded CBinary patchingCross-compilingBluetooth LEPythonHome Assistant
Little Fighter 2 for macOS
A Windows game turned into a native Apple Silicon app.
A tool that converts the classic Windows game Little Fighter 2 into a native macOS app by static recompilation, with no Wine, no emulator and no source code. It disassembles the original lf2.exe, translates every x86 function into C that runs on a simulated CPU, and compiles it for Apple Silicon together with a small runtime that re-implements the Windows APIs the game uses (window, input, DirectDraw graphics, DirectSound audio, music) on top of macOS frameworks. One command takes the original installer and produces a signed .app in about ten seconds.
Static recompilationx86CPythonWin32 APIAppKit
Kick Pixel-Art Canvas
A shared canvas painted by chat, streamed live to Kick.
Viewers place pixels on a 36×36, 16-colour canvas by typing chat commands (!pixel x y colour). Three cooperating services do the work: a Node.js + PostgreSQL API with a WebSocket feed that keeps every client's canvas in lockstep; an official Kick OAuth2 (Authorization Code + PKCE) app that receives chat.message.sent webhooks and parses the commands; and a compositor that renders the canvas to raw RGB24 frames, pipes them through ffmpeg, and pushes RTMPS to Kick's AWS IVS ingest, so the artwork is a live video the audience shapes in real time. A 10s per-user cooldown throttles spam.
Node.jsPostgreSQLWebSocketKick OAuth2 / PKCEffmpeg / RTMPSsystemd
pidash (Homelab Dashboard)
One control panel for every layer of my home server.
A Flask + Waitress web app that unifies real-time monitoring and control of the Pi homelab in one screen: system metrics (psutil), Docker containers, systemd services, listening sockets, live filtered journald logs, Pi-hole and Tailscale, with actions rather than just readouts (toggle Pi-hole blocking from the UI, manage a links list with full CRUD + validation). Built on a dependency-injected service layer around a central CommandRunner, running parallel link health-checks through a thread pool, and hardened by auto-detecting the host's Tailscale IP at startup and binding only to it.
PythonFlaskWaitressREST APIpsutilJavaScript
AI Video Generator
Turns plain text into vertical 1080×1920 short-form videos.
A modular, stdin-first pipeline that turns a block of text into a finished Short/Reel/TikTok clip. Stages: optional Gemini script generation → Edge-TTS narration that returns per-word timings → stylized word-by-word caption clips synced to speech → a random background video looped and cropped to the vertical frame → a MoviePy/FFmpeg export at a configurable x264 preset, emitting structured JSON metadata per render. Every stage composes in a shell (text in on stdin, media out), and an optional Gradio UI runs the same pipeline without the terminal.
PythonGeminiEdge TTSMoviePy / FFmpegGradio
Emotional Support Center
A platform for booking and running online support sessions.
A team-built React + Firebase web app for booking and running support sessions: authentication, session scheduling, and role-based access between users and therapists. Built for a software-engineering course and versioned in a shared GitHub organization.
ReactFirebaseJavaScriptAuth
Low-Latency Streaming System
Sub-3-second glass-to-glass live streaming.
An end-to-end MPEG-DASH live pipeline: OBS captures the source, FFMPEG encodes and segments it, and GPAC's Node.js low-latency DASH server (node-gpac-dash) serves it to a DASH.js player. To measure real latency I rendered dynamically updating QR codes carrying timestamps into the source and read them back off the player, then tuned segment duration and key-frame interval to push glass-to-glass delay under three seconds while keeping playback stable. A multimedia-systems course project.
MPEG-DASHGPACFFMPEGOBSNode.js
ROS Robotic Arm
A multi-joint arm driven by joystick and MoveIt motion planning.
Software for a rover's robotic arm on a ROS stack. Four joints of Dynamixel smart servos are driven over a serial bus the node scans at 1 Mbaud (setting goal position, speed and torque, then synchronize()), with additional joints reached through Arduinos bridged by rosserial. It supports two control modes: button-gated joystick teleoperation (sensor_msgs/Joy) and MoveIt motion planning that streams /joint_states to the hardware, plus a custom PID-tuning GUI (and matching Arduino PID test sketches) for dialing in each joint.
ROSMoveItDynamixelrosserialPythonArduino
Endless Platformer
A dash-and-jump endless runner with a pooling-based spawn system.
WASD movement with a double-jump and an air-dash (Left Shift); collecting coins mid-dash raises a score multiplier that resets if you grab them flat-footed, and platforms spawn procedurally forever. The engineering focus was an object-pooling system: a Queue-based pool that reuses deactivated platforms and coins instead of instantiating and destroying them, which I profiled in the Unity Profiler across 500 vs 5,000 objects, showing the pool cut the GC/memory churn and FPS drops that hit hardest during spawn and game-reset. Event-driven design with a central GameManager handling fall-detection, reset and scoring.
UnityC#Object PoolingUnity Profiler
Maze Game (Guard AI)
Sneak through a maze past patrolling guards.
A grid-based level loader (MazeLoader) instantiates the maze from a 2D integer layout, placing wall prefabs and spawning guards. Each guard patrols between waypoints with MoveTowards and runs layer-masked line-of-sight detection; catch the player in view and it ends the run via an end-game scene, with its own music manager and menus. A compact stealth loop in Unity / C#.
UnityC#Game AILine-of-sight
SDL2 Platformer
A 2D platformer built from scratch, no engine.
An endless 2D platformer written in C++ on SDL2, with hand-written platformer physics (gravity, jumping) and pixel-level collision detection. Just the game loop and rendering, done by hand.
C++SDL2PhysicsCollision