Skip to content

Portfolio · est. golden hour

George Zhang

CS at the University of Waterloo, building thoughtful software — from Android Automotive at Ford to computer-vision rehab tools and a few too many games.

Currently: SWE Intern @ Ford · Android Automotive OS

The Collection

Selected Work

A few things I've built — games, tools, and research apps. Step inside the museum to see them on pedestals.

No. 01

Portfolio Website

An interactive personal portfolio with two faces: a fast, content-first web portfolio at /, and a lazy-loaded pixel-art museum game you can step into — built on a custom HTML5 Canvas game engine with a 60fps requestAnimationFrame loop, tile-based AABB collision, A\ pathfinding, particle systems, and a procedurally generated map. Walk a character through auto-built themed rooms and open exhibits showcasing projects, skills, experience, and contact info; both faces render from a single content source. Other visitors drift through the museum as warm glowing "ghost" wisps — a lightweight multiplayer-presence feature that records anonymous movement paths and replays them with their own exhibit-visiting AI. Project, skills, and competitive-programming data (GitHub, LeetCode, DMOJ) refreshes automatically through a daily GitHub Actions pipeline. Built with Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS, and Upstash Redis. Dual experience — a fast static web portfolio and an explorable canvas museum, both driven by one projects.ts content source (edit once, both update).; Seamless portal — a continuous camera-pan transition hands off from the DOM site into the game and back, with a prefers-reduced-motion crossfade fallback.; Explorable museum — move with WASD / arrow keys / click-to-move / an on-screen touch joystick; press E to inspect glowing exhibits.; Ghost trails (multiplayer presence) — other visitors appear as drifting wisps that wander between exhibits and linger to "view" them; their paths are recorded, stored, and replayed back to future visitors.; Live, self-updating content — GitHub repos populate Projects + Skills and LeetCode/DMOJ stats populate a competitive-programming panel — all refreshed daily, no manual edits.; Dynamic documents — résumé and transcript PDFs are parsed on the fly into structured, themed popups.; Atmosphere — a slow golden-hour day/night colour wash, ambient dust, footstep audio, a live minimap, and a hidden easter egg. Engine ↔ React split. A standalone canvas GameEngine runs the 60fps game loop and never imports React; it talks to the UI only through an onEvent callback. The web portfolio (SiteShell / Portfolio) is server-rendered for instant load, and the heavier GameCanvas is lazy-mounted only once a visitor steps inside. Rendering & world. The scene draws in three y-sorted passes (floor/walls → entities → glow) for a top-down 2.5D depth effect — entities further south draw last and appear in front. The whole museum map (rooms, doorways, perimeter walls) is procedurally generated from a list of branch definitions, so adding a room is one array entry. Movement uses tile-based AABB collision detection decoupled from tile type (sprites can overhang their tiles), and click-to-move / minimap taps run A\ pathfinding — 8-directional with diagonal corner-cut prevention and a line-of-sight string-pulling smoothing pass. Ghost trails. The engine samples the player's path; on leave it's POSTed to a route handler and stored in Redis (Upstash REST API) as a capped, trimmed list. New visitors fetch the recent paths and a GhostSystem replays them as additive-blended particle wisps that pathfind between exhibits, respect collisions, hover, and never revisit the same one — degrading gracefully to fully procedural wanderers when the store is empty or unconfigured. Data pipeline. A daily GitHub Actions cron scans the owner's repos (languages, dependency manifests, READMEs, demo videos) and fetches LeetCode (GraphQL) + DMOJ stats, committing them as static data the site reads — so the live site never makes those third-party calls at runtime. A CI workflow gates every PR on tsc + lint + tests, and Dependabot keeps dependencies current. Game engine architecture — a decoupled 60fps requestAnimationFrame game loop with fixed delta-time updates, kept entirely separate from React; HTML5 Canvas rendering — a three-pass, y-sorted scene draw for top-down 2.5D depth sorting;

TypeScriptJavaScriptGitHub ActionsVitestFramer MotionNext.jsReactESLint
No. 02

Robotics

Code for an autonomous maze-solving robot built for the RoboCupJunior Maze category, competed at the 2023 World Championship in Bordeaux, France. The robot navigates an unknown maze entirely on its own — perceiving walls, rescue tiles, and floor markings with an onboard camera and LiDAR, and deciding where to go with no external input. The robot navigates an unknown maze autonomously, detecting walls, colored rescue tiles, and black/white floor markings using an OpenMV camera and LiDAR sensors. It maps its path in real time and makes navigation decisions without any external input. All logic runs on-device in MicroPython (OpenMV / pyb framework). Every cycle the robot runs a perception → decision → actuation loop entirely on the OpenMV camera. Computer vision in the LAB color space classifies the tile underneath it — distinguishing red, green, yellow, blue, black, and white using tuned thresholds — while LiDAR reads distances on all four sides to detect walls. Each maze cell's four walls are encoded as a bitmask so the robot can remember the layout it has explored, and tile classification (rescue tile, checkpoint, or floor type) triggers the appropriate behavior. Motor commands (forward, turn, reverse, stop) are issued through a control interface over a low-level driver, and inter-device messages are validated with a cyclic redundancy check (CRC). The navigation logic evolved through successive rewrites — Nav through Nav6 — each refined against the physical robot during testing, with dedicated calibration scripts for color and sensing. OpenMV Cam — onboard vision processor running all navigation logic; LiDAR sensors — wall detection and distance measurement on all four sides; Servo motors — drive and steering control; Color sensor — backup floor tile detection The support modules (Control.py, Sensor.py, motor2.py, Stop.py, CRC.py) are documented helper scripts for motor control, sensing, and UART integrity. Test files (TestBlack.py, TestColor.py, TestSensing.py) were used during hardware calibration, and the earlier navigation drafts (Nav through Nav5) are kept to show the iterative development behind the final Nav6.py. Color detection in LAB color space — distinguishes red, green, yellow, blue, black, and white tiles using tuned thresholds; Wall mapping — encodes each cell's four walls as a bitmask for path memory; Tile classification — identifies rescue tiles, checkpoints, and floor type to trigger appropriate behavior; Iterative development — Nav through Nav6 represent successive rewrites as the robot's behavior was refined through testing Autonomous navigation — real-time maze traversal with no external input; Robotics & embedded programming — MicroPython on an OpenMV vision processor; Computer vision — LAB color-space tile detection with tuned thresholds; Image processing — onboard camera frame analysis for floor and rescue-tile classification; Sensor integration & fusion — combining LiDAR, camera, and a color sensor for perception; Motor control — drive and steering via servo motors over a low-level driver; Maze mapping — per-cell four-wall bitmask encoding for path memory; Algorithmic navigation — wall-aware decision logic for traversal; Bitmasking & state encoding — compact representation of maze cells; Serial communication — CRC (cyclic redundancy check) error detection; Real-time control loop — perception, decision, and actuation on-device; Iterative engineering — successive Nav rewrites refined through hardware testing; Hardware calibration — dedicated color, black-line, and sensing test routines Python / MicroPython (OpenMV pyb framework); OpenMV Cam (onboard vision processor); LiDAR sensors (four-directional distance sensing); Servo motors + low-level motor driver; Color sensor (backup tile detection); LAB color-space image processing; CRC (cyclic redundancy check) for communication integrity

PythonComputer VisionTestingRobotics & EmbeddedProcessingAutonomous navigationRobotics & embedded programmingComputer vision
No. 03

My Fridge

A clean, modern Android app for tracking what's in your fridge, getting notified before things expire, and keeping your shopping organised — all in one place. Built with Kotlin and Jetpack Compose on an MVVM architecture, and published on the Google Play Store. Fridge tracker — add items with an expiry countdown; items sort automatically by urgency (expiring first); Expiry labels — colour-coded: grey for future, orange for today, red for expired; Smart notifications — a background worker runs daily at your chosen time and alerts you when something is about to expire; configure how many days in advance you want the warning; Shopping list — keep a running list with per-item quantities; swipe to remove, or tap Move all to My Fridge after a shop; Saved items — store your regular items as templates and add them to the fridge or shopping list in one tap; Search — instant filter on every list screen; Undo delete — swipe to dismiss or tap the delete icon; a brief snackbar lets you undo before it's gone; Expiry badge — the My Fridge tab shows a live count of items needing attention; Dark mode — full Material You colour scheme, works in light and dark system themes; Settings — choose your daily notification time (clock picker) and expiry warning window (0–30 days) The app follows an MVVM architecture. A MainViewModel holds the UI state and business logic and exposes it as StateFlow, which Jetpack Compose observes to recompose screens automatically. Data is persisted locally with a Room database (entity, DAO, and an ItemRepository interface backed by an OfflineItemRepository), using KSP for annotation processing. Screens are wired together with Navigation Compose, and user settings persist via Jetpack DataStore / SharedPreferences. Expiry reminders are powered by WorkManager: a daily CoroutineWorker recalculates each item's days-until-expiry and fires a local notification at the user's chosen time, with a configurable lead window — scheduled so it survives app restarts and device reboots. Shared UI is factored into reusable composables (ItemCard, EditCard, TopBar), and the whole interface is themed with Material 3. MVVM architecture — ViewModel + repository + Room, with UI state exposed as StateFlow; Declarative UI — Jetpack Compose with Material 3 (Material You) theming; Reactive state management — Compose state and StateFlow driving automatic recomposition; Asynchronous concurrency — Kotlin coroutines and Flow for non-blocking data access; Local persistence — Room database (entity, DAO, repository) with KSP annotation processing; Repository design pattern — ItemRepository interface with an offline implementation; Background processing — WorkManager CoroutineWorker for a daily expiry check; Local notifications — scheduled alerts with a user-configurable lead time; Navigation — multi-screen routing with Navigation Compose; Preferences storage — Jetpack DataStore / SharedPreferences for settings; Component reuse — shared composables (ItemCard, EditCard, TopBar); Material Design 3 — light/dark theming, colour scheme, and typography; UX engineering — swipe-to-delete with undo snackbar, instant search, urgency sorting, live badges; Lifecycle awareness — boot receiver and lifecycle-aware scheduling; Gradle build system — Android Gradle Plugin, Compose BOM, and KSP; Shipping to production — published on the Google Play Store Get it on Google Play: play.google.com/store/apps/details?id=com.iamtherealgeorge.myfridge

KotlinGradleJUnitConcurrencyProcessingJetpack ComposeMVVM architectureDeclarative UI
No. 04

Rubiks Cube

An interactive 3D Rubik's Cube built from scratch in Processing 4 (Java / P3D OpenGL), with a from-scratch CFOP solver that solves any scramble and animates the solution move-by-move. The solver runs on a background thread, was property-tested against thousands of random scrambles, and uses no external cube or solving libraries. ▶ Watch the demo on YouTube Real-time 3D cube — 27 chamfered cubies with per-face lighting, beveled edges, and z-fight-free stickers, rendered in P3D (OpenGL).; Natural controls — grab any face and drag to turn it (ray-cast picking + axis-locked slice dragging), spin the whole cube to look around, or drive it from the keyboard.; From-scratch CFOP auto-solver — Cross → F2L → OLL → PLL, no external libraries. Solve the whole thing automatically, or step through it one move at a time.; Runs off the UI thread — the solver computes on a background worker so the interface never freezes; the solution is streamed into the animation queue when ready.; Polished UX — scramble, timer with persisted best time, move counter, undo (animated, reaches back through scrambles and solves), light/dark themes that follow the OS, and cross-platform fonts/labels (macOS · Windows · Linux). A complete CFOP ("Fridrich method") pipeline implemented over the cube's sticker model: The whole pipeline was validated against thousands of random scrambles (a standalone Java port of the cube + solver) before shipping — 0 failures over 1500 scrambles. A hidden t key re-runs that self-check live from the console. While building the solver I discovered the cube model itself was subtly wrong: it passed casual play but failed the classic identity (R U R' U')⁶ = solved. Property-style testing (checking cubie groupings across thousands of scrambles, then move-order identities) isolated a corner-cycling bug that was invisible to edges and centers — a reversed strip in two of the turn functions. Fixing it made the model a mathematically valid cube and the solver correct. The sketch is split into focused tabs: 3D graphics programming — real-time P3D / OpenGL rendering of 27 chamfered cubies with lighting and bevels; Ray-cast picking — face selection via ray–geometry intersection; Interaction design — axis-locked slice dragging for natural click-and-drag face turns; Algorithm design — a from-scratch CFOP (Cross → F2L → OLL → PLL) solver with no libraries; Breadth-first search — optimal cross over a reduced ~190k state space; State-space reduction — cross-preserving F2L search and bounded last-layer coset searches; Multithreading & concurrency — solver runs on a background worker; the UI thread never blocks; Producer–consumer queue — one animation queue fed by scramble, solve, step, and undo; Property-based testing — validated over 1500+ random scrambles with a standalone Java port (0 failures); Debugging with invariants — isolated a corner-cycling bug via move-order identities ((R U R' U')⁶); Object-oriented design — focused modules for cube, solver, renderer, input, and raycasting; Data modelling — six char[3][3] faces and the 18 canonical face turns; Persistence — best time and theme saved as JSON in the home directory; Cross-platform packaging — jpackage produces self-contained apps for macOS, Windows, and Linux; CI/CD automation — GitHub Actions builds and attaches all three OS apps on v tags; UX engineering — animated undo through scrambles/solves, OS-following dark mode, live timer Java; Processing 4 (PApplet, P3D renderer); OpenGL via JOGL / GlueGen (the P3D backend); Python (a small build-time sketch preprocessor); jpackage (self-contained native app bundles); GitHub Actions (multi-OS release CI); JSON persistence (~/.rubikscubeprefs.json) 📺 Watch the demo on YouTube; ⬇️ Download the latest release

ProcessingGitHub ActionsConcurrencyTesting3D GraphicsJavaROpenGL
No. 05

Box Head 2 Play

A top-down endless survival shooter built in Java with the Processing framework, inspired by the classic Flash game BoxHead 2 Play and modernised with Survivor.io-style mechanics. It features a procedurally generated infinite map, BFS flow-field pathfinding, seven enemy types, six weapons, and a 30+ card upgrade system — all built on a shared object-oriented entity model. Procedural infinite map — value-noise terrain generates a unique layout every run; enclosed floor pockets are detected and broken open at runtime via BFS connectivity analysis; BFS flow-field pathfinding — dual fields (standard + clearance-inflated for large enemies) rebuild on player tile change; enemies navigate through complex corridors without getting stuck; 7 enemy types with wave-scaled stats — Zombie, Skeleton, Shooter, Gunner, Brute, Marksman, and Devil (boss), each with distinct AI behaviour; 6 weapons — Pistol, Shotgun, SMG, Minigun, Sniper Rifle, Rocket Launcher; all acquired through procedural crate drops and upgradeable via level-up cards; Comprehensive upgrade system — 30+ upgrades across weapons, bullet modifiers, and defensive items; each upgrade is one-per-run and applied globally across all owned guns; Bullet modifier stack — Ricochet (up to 3 bounces), Chain Strike (arcs to 4 enemies), Frag Rounds (AoE splash per hit), Cryo (slow), Incendiary (burn DoT); all modifiers propagate to drones and turrets in real time; Defensive items — Force Field (contact-absorbing shield), Combat Drones (orbiting auto-turrets that mirror the player's active weapon), Blade Spin (rotating melee), Damage Aura, Shockwave pulse, Pickup Magnet; Kill-streak XP multiplier, floating damage numbers, elite enemy variants, wave events (Boss Rush, Supply Drop, Enemy Horde), and danger zones Shared entity model — a common Entity base handles physics, status effects (slow, burn), hit-flash, and HP bars; weapon logic lives in a unified Gun class used by the player, enemies, drones, and turrets alike, with concrete enemy and weapon subclasses extending the shared behaviour.; BFS flow-field pathfinding — two distance fields (a standard field and a clearance-inflated one for large enemies) are rebuilt from the player whenever the player crosses a tile boundary, so every enemy can follow the gradient to the player through complex corridors.; Reactive map repair — WorldMap.wouldIsolate uses a local 9×9 BFS to prevent small enclosed pockets at generation time; the Pathfinder.fixEnclosures pass catches larger rings after each flow-field rebuild and permanently opens wall tiles via WorldMap.openWall.; Shield absorption model — the shield intercepts the total HP delta from entity-contact damage before committing the kill flag; bullet damage intentionally bypasses the shield for difficulty.; Upgrades propagate to allies — syncAlliedGuns runs every frame, copying the full bullet style (pellet count, spread, speed, AoE radius, penetration, and all modifiers) from the player's active gun to every drone and turret. Object-oriented design — 30+ classes for entities, weapons, enemies, and items; Inheritance & polymorphism — enemy and weapon hierarchies over a shared Entity / Gun base; Entity–component modelling — physics, status effects, hit-flash, and HP bars on a common base; Game AI — seven enemy types with distinct behaviours, wave-scaled stats, and elite variants; BFS flow-field pathfinding — dual distance fields rebuilt on player movement; Graph connectivity analysis — BFS enclosure detection (wouldIsolate, fixEnclosures) and runtime wall opening; Procedural generation — value-noise infinite terrain with runtime connectivity repair; Collision detection & physics — entity contact, bullet hits, knockback, status effects; Spatial partitioning — tile grid for navigation and world representation; Game systems design — 30+ upgrades, a bullet-modifier stack, defensive items, and wave events; Real-time state propagation — per-frame weapon-style sync from player to drones and turrets;

JavaGame AIProcessingObject-oriented designInheritance & polymorphismEntity–component modellingBFS flow-field pathfindingGraph connectivity analysis
No. 06

Ai File Organizer

A command-line tool that automatically sorts messy folders into a clean, hierarchical category tree using either a free offline semantic-embedding model or a bring-your-own-key Large Language Model — Claude, GPT, Gemini, or any OpenAI-compatible provider. It combines multi-provider LLM classification (with vision-based image understanding, prompt caching, structured JSON outputs, concurrent requests, and exponential-backoff retries) with crash-safe file operations (append-only journaling and one-click undo), secret-safe API key management, and content extraction from PDF, Word, PowerPoint, Excel, and images via OCR. Two interchangeable backends — a free, fully offline embedding classifier (sentence-transformers), or a bring-your-own-key LLM for higher accuracy.; Every major provider through one key — Anthropic Claude, OpenAI, Google Gemini, Groq, Mistral, DeepSeek, Together, OpenRouter, a local Ollama server, or any custom OpenAI-compatible endpoint.; Vision-based image sorting — image files are sent to multimodal models and classified by what they actually show, not just their filename.; Token-frugal LLM mode — request batching, Anthropic prompt caching, content truncation, and schema-constrained outputs keep cost low; each run prints a token/cache-hit summary.; Concurrent classification — batches run in parallel with a cache-warming first request, plus automatic retry/backoff on rate limits and server errors.; LLM category discovery — let the model propose a category tree from your own files, or supply a custom tree as JSON/YAML.; Crash-safe organization — every move is journaled to disk as it happens and an undo script is generated even if the run is interrupted; dry-run and copy modes included.; Secret-safe keys — API keys come from the environment, a gitignored .env, or a hidden prompt; they are masked in output and never written to config, logs, or undo scripts.; Privacy controls — exclude sensitive files via .organizerignore or --exclude globs, a notice before any data leaves your machine, and a fully offline mode.; Spend guard — a pre-run token estimate and a hard file-count cap prevent surprise bills.; Low-confidence Review folder — uncertain placements are quarantined instead of mis-filed.; Interactive setup wizard plus content extraction for PDF, DOCX, PPTX, XLSX, images (OCR), and text/code files. Files flow through a four-stage pipeline: scan → extract → classify → move. 1. Scan discovers files recursively, skipping hidden/system files and anything matched by a .organizerignore file or --exclude glob. 2. Extract pulls text from each file using a format-specific extractor (PDF, Word, PowerPoint, Excel, image OCR, or plain text), with character-encoding detection. 3. Classify assigns each file a path in a hierarchical category tree using the selected backend. 4. Move relocates (or copies) files into the destination tree, recording every operation to a crash-safe journal and emitting an undo script. Classification backends. The local backend embeds filenames and content with sentence-transformers and matches them to category descriptions by cosine similarity, walking the tree level by level and falling back to an "Other" folder when confidence drops below a per-node threshold — entirely offline, no key, no network. The LLM backend instead asks a language model to place each file directly into the tree, which handles messy or ambiguous files far better. Token frugality. The LLM backend classifies many files per request so the (large, fixed) category tree is sent once per batch rather than once per file. On Anthropic that tree lives in a cached system prompt (cachecontrol: ephemeral), so every batch after the first is dramatically cheaper. Responses are constrained with JSON-schema structured outputs (with defensive parsing as a fallback for providers that only support JSON-object mode), and per-file content is truncated to a short snippet. Vision.

PythonGitHub ActionsMakepipNumPyscikit-learnPyTorchPillow
No. 07

Image To Text

A desktop Java application that converts raster images into ASCII art in real time. Built from scratch with a fully custom Swing GUI, an off-screen rendering pipeline for O(1) scroll/zoom, background processing via SwingWorker, and smooth zoom/pan interaction. The app takes any JPG, PNG, or GIF image, converts each pixel to a grayscale luminance value using the Rec. 601 standard, and maps it to one of 70 ASCII characters ordered by visual density (Paul Bourke gradient). The result is rendered into a scrollable, zoomable panel and the intermediate grayscale image is saved to disk automatically. Conversion reads pixels directly from a BufferedImage (getRGB), computes per-pixel luminance with the Rec. 601 luma coefficients (0.299R + 0.587G + 0.114B), and maps each value through a static lookup table to one of 70 density-ordered ASCII characters. The hot pixel loop uses a StringBuilder for O(n) assembly, and the whole conversion runs on a SwingWorker so the UI never blocks. The rendered ASCII is drawn once into an off-screen buffer, so scrolling and zooming stay O(1) regardless of image size — nearest-neighbor interpolation keeps it crisp when zoomed in, bilinear keeps it smooth when zoomed out. Interaction is handled with a MouseAdapter for drag-to-pan (using screen coordinates for stable deltas) and getPreciseWheelRotation for smooth Ctrl+scroll zoom, with an InputMap/ActionMap shortcut system scoped to the focused window. Swing GUI from scratch — custom layouts, components, and event handling; Multithreading & concurrency — SwingWorker keeps the UI responsive during conversion; Off-screen rendering — pre-rendered BufferedImage makes scroll and zoom O(1) at any image size; Image processing — pixel-level RGB manipulation via getRGB / setRGB; Grayscale conversion — Rec. 601 luma coefficients (0.299R + 0.587G + 0.114B); Algorithm/data-structure use — static lookup table for the brightness → character mapping; Image scaling — SCALESMOOTH downscaling with zoom-aware nearest-neighbor / bilinear interpolation; Keyboard shortcut system — InputMap / ActionMap with WHENINFOCUSEDWINDOW scope; Performance optimization — StringBuilder over concatenation in hot pixel loops for O(n); Pan & zoom UX — drag-to-pan, precise Ctrl+scroll zoom, and fit-to-window on every transform; Layout management — responsive nested BorderLayout so zoom controls stay visible at any width; Error handling — IOException propagation with user-facing dialogs, no silent failures; Object-oriented design — separate converter, text panel, and prompt components; JAR packaging — distributed as a standalone runnable JAR Java 17+; Java Swing / AWT (BufferedImage, Graphics2D, SwingWorker, InputMap / ActionMap, MouseAdapter); Packaged as a standalone runnable JAR (ImageToText.jar)

JavaConcurrencyProcessingSwingSwing GUI from scratchMultithreading & concurrencyOff-screen renderingImage processing

Archive

No. 08

PONG

A fully playable Pong game built in Java with Swing, featuring local two-player multiplayer and a single-player mode against a predictive AI that simulates the ball's full trajectory — including wall bounces — to anticipate where it will land. https://github.com/user-attachments/assets/54ef0b10-a559-49a8-9805-efe1b83df394 Single-player mode — AI that simulates the ball's full trajectory (including wall bounces) to predict its landing position, with a speed cap and randomised error margin so it's challenging but beatable; Two-player local multiplayer — both players share the keyboard; Physics-based ball mechanics — bounce angle depends on where the ball strikes the paddle; ball speed increases 5% per volley up to a maximum, rewarding longer rallies; Clean menu UI with keyboard navigation The game runs on a javax.swing.Timer firing at 60 FPS on the Event Dispatch Thread, so updates and repaints stay smooth without ever blocking the EDT with Thread.sleep. Ball physics are vector-based: each return angle is computed from the hit position relative to the paddle centre (rel × 60°), so edge hits produce steep angles and centre hits produce flat returns, with the velocity decomposed via cos/sin. Speed builds 5% per volley up to a hard cap (MAXSPEED), making long rallies progressively harder to control. The AI opponent projects where the ball will land by running a frame-by-frame physics simulation (predictBallY) that mirrors the wall-bounce logic. To stay beatable, it recomputes its target only every ~15 frames, applies a ±25px position error, moves slightly slower than the player, and drifts back to centre when the ball is travelling away — so it can be consistently beaten by pushing the ball into the corners at high speed. Object-oriented design — game state, rendering, and input separated across classes; Event-driven programming — Java Swing event dispatch and key handling; Game loop architecture — javax.swing.Timer at 60 FPS, no blocking on the EDT; Game physics — vector velocity, trigonometric bounce angles, per-volley speed ramping; Collision detection — ball-versus-paddle and ball-versus-wall response; Game AI — predictive opponent via frame-by-frame trajectory simulation; Vector math & trigonometry — cos/sin angle decomposition from paddle hit position; 2D rendering — custom Graphics drawing of paddles, ball, scores, and menu; Input handling — multi-key state tracking and keyboard menu navigation; Java Platform Module System — modular build with module-info.java; JAR packaging — runnable modular Java application Java 17+; Java Swing / AWT (JPanel, JFrame, Graphics, javax.swing.Timer); Java Platform Module System (module-info.java, requires java.desktop); Packaged as a runnable modular JAR (PONG.jar)

JavaGame PhysicsGame AISwing
No. 09

Cockroach

A real-time 2D Java desktop game where cockroaches swarm in from the edges of the screen. Squash them before they eat your crumbs. The cockroaches run a lightweight greedy-steering AI to seek food and flee from fast cursor movement, all rendered with procedural Graphics2D animation. https://github.com/user-attachments/assets/1be13148-a2f2-4951-9818-146e4dd8ade0 Cockroaches spawn continuously from all four edges and wander across the screen. Drop bread crumbs to lure them — cockroaches use greedy steering to seek the nearest crumb and will eat it down to nothing. Move your cursor too quickly near a cockroach and it will scatter. Left-click to squash; a splat mark fades on the floor where it died. Swing game loop — javax.swing.Timer drives all updates on the EDT, giving thread-safe state mutation without locks while keeping repaint latency low.; Greedy steering AI — cockroaches find the nearest crumb and pick the 8-directional heading with the highest dot product against the target bearing, replacing an earlier pixel-level BFS that allocated a fresh 600 × 600 visited array per entity per tick.; Flee behaviour — peak cursor speed is sampled between direction-update cycles; any cockroach within 100 px when the speed threshold is exceeded steers directly away for ~0.8 s.; Custom 2D renderer — entities are drawn with Graphics2D transforms (translate → rotate → scale): body oval, head, eyes, antennae, and three leg pairs, all rotated to face the direction of travel. Death plays a squish-and-fade animation by scaling the transform over 100 frames.; Persistent splat marks — squash events stamp a dark oval into a separate list that fades over ~5 seconds independently of the entity lifecycle.; Crumb consumption — each crumb has 10 health points; stopped cockroaches bite stochastically (~3 % chance per frame), and the crumb shrinks visually in proportion to remaining health. Object-oriented design — Cockroach, Entity, Mouse, and Layout classes; Event-driven programming — Java Swing mouse handling and timer-driven updates; Game loop architecture — javax.swing.Timer on the EDT for lock-free, thread-safe state; Game AI & steering behaviours — greedy seek toward nearest crumb, flee on fast cursor; Vector math — 8-directional heading chosen by maximum dot product against the target bearing; Performance optimisation — replaced a per-tick 600×600 BFS scan with O(1) greedy steering; Collision & hit detection — click-to-squash hit testing and crumb proximity; Custom 2D rendering — Graphics2D affine transforms (translate/rotate/scale), procedural sprites; Animation — squish-and-fade death and time-decaying splat marks; Object lifecycle management — independent entity, crumb, and splat lists; Stochastic behaviour — probabilistic crumb biting and randomised spawning; Input handling — left-click squash, drag-and-throw, right-click crumb placement; Java Platform Module System — modular build with module-info.java; JAR packaging — runnable modular Java application Java 17+; Java Swing / AWT (JPanel, Graphics2D, javax.swing.Timer, MouseListener); Java Platform Module System (module-info.java); Packaged as a runnable JAR (cockroach.jar); Eclipse IDE

JavaGame AITestingSwing
No. 10

Exorcist

A 2D infinite climbing platformer built in Java (Swing). Jump between procedurally generated platforms, fight four enemy types with a responsive combat system, and climb as high as you can. Built on an object-oriented entity hierarchy with state-machine AI, custom collision physics, and a sprite-sheet animation system. Procedural generation — platforms, hazards, and enemy placements are generated on the fly with increasing difficulty as you ascend; Four enemy types with distinct AI behaviors: melee aggression, ranged cursing, aerial pursuit, and heavy tanking; Fluid combat — attack, double jump, and a stamina-based shield that rewards timing; Persistent high score saved between sessions; Polished animations — per-entity sprite sheets with state-driven animation (idle, walk, attack, death); Responsive game feel — fall damage, knockback, curse DoT with visual feedback, half-heart regeneration The game is organised around an object-oriented entity model: a shared Entity base provides movement, health, and animation state, and each enemy (Wolf, Golem, Witch, Bat) and the Player extends it with its own state-machine AI. GamePanel drives the update/render loop, CollisionChecker resolves platform and combat collisions, and TileManager builds the world from map files while scrolling infinitely upward and generating fresh content as you climb. Each entity animates from sprite sheets driven by its current state (idle, walk, attack, death). Physics covers gravity, jumping and double-jumping, knockback, and fall damage for long drops. Input is split between KeyHandler and MouseHandler, audio plays through javax.sound.sampled via a dedicated Sound class, and the high score persists to disk between sessions. Move, double jump, attack, and shield; 5 hearts HP with 2 bonus overflow hearts (earned from kills); Shield with stamina bar — blocks frontal attacks, depletes on sustained use; Half-heart regen every 20 seconds; Fall damage for drops over 10 tiles Object-oriented design — Entity base with Wolf / Golem / Witch / Bat / Player subclasses; Inheritance & polymorphism — shared entity behaviour specialised per enemy; State-machine AI — per-entity behaviour and animation states; Game AI — four distinct enemy behaviours (melee lunge, ranged kiting, aerial pursuit, tank); Procedural generation — infinite upward platform, hazard, and enemy generation with scaling difficulty; Collision detection & physics — CollisionChecker, gravity, double jump, knockback, fall damage; Sprite animation system — state-driven sprite-sheet animation (idle/walk/attack/death); Game loop architecture — GamePanel update/render cycle; Custom 2D rendering — Java Swing Graphics2D with AlphaComposite effects; Input handling — separate keyboard and mouse handlers; Audio playback — sound effects via javax.sound.sampled; Tile-map system — TileManager loading map files with infinite scrolling; File I/O — persistent high score and map loading; Combat systems design — stamina shield, curse DoT, half-heart regen, overflow hearts; Java Platform Module System — modular build with module-info.java; JAR packaging — runnable modular Java application Java 17; Java Swing / AWT (Graphics2D, AlphaComposite, 2D rendering); javax.sound.sampled (audio); Java Platform Module System (module-info.java); Packaged as a runnable modular JAR (Exorcist.jar); Eclipse IDE

JavaGame AISwingObject-oriented design
No. 11

Minesweeper

A fully-featured Minesweeper clone built in Java with a custom dark-themed UI, a probability-based AI solver, BFS flood-fill reveals, and dynamic tile scaling. Custom rendered board — 3D bevel tiles drawn with Graphics2D, distinct highlight/shadow edges for unrevealed vs. revealed states; Probability-based AI solver — constraint propagation fixpoint loop deduces guaranteed mines; remaining cells ranked by local mine probability; random tie-breaking when probabilities are equal; Auto Solve mode — checkbox triggers the AI on a 500 ms Swing Timer; runs on the EDT without blocking the UI; Configurable grid — dialog lets you set columns, rows, and mine count; tile size auto-scales to fill the screen while keeping tiles between 20–60 px; Restart — resets board, AI state, and mine counter without reopening the setup dialog; Instructions dialog — in-game "How to Play" reference; Dynamic mine counter — tracks remaining unflagged mines in real time; Platform-aware icon — programmatically generated app icon reusing the same drawRaised / drawMine helpers; set on the macOS dock via the Taskbar API The game logic, AI, and UI are kept in separate classes (MineSweeper, AI, Main). Revealing an empty cell triggers a BFS flood-fill that cascades outward through all connected zero-count cells, opening their neighbours in one sweep. The AI solver runs a constraint-propagation fixpoint loop: it repeatedly scans every numbered cell, and whenever a cell's number equals its count of adjacent unknowns it flags those as guaranteed mines (and conversely opens cells that are provably safe), iterating until no new deductions are possible. When pure deduction stalls, it falls back to probabilistic reasoning — ranking the remaining unknown cells by their local mine probability and breaking ties randomly — so it can keep making the statistically best move. Auto-solve mode steps this engine on a 500 ms Swing Timer, entirely on the Event Dispatch Thread so the UI never freezes. Object-oriented design — game logic, AI solver, and UI in separate classes; Event-driven programming — Swing mouse and window listeners, timer-driven auto-solve; 2D rendering — Graphics2D 3D-bevel tiles with highlight/shadow edges; BFS flood-fill — cascading reveal of connected zero-count cells; Constraint-propagation solver — fixpoint deduction of guaranteed mines and safe cells; Probabilistic reasoning — local mine-probability ranking with random tie-breaking; Algorithm design — combined deterministic + probabilistic AI strategy; Dynamic UI scaling — tile size auto-scales (20–60 px) to grid and screen size; Procedural graphics — programmatically generated app icon and dock integration via Taskbar; Input handling — mouse listener for reveal/flag, window listener for lifecycle; Layout management — Swing layout managers and SpringUtilities; JAR packaging — distributed as a standalone runnable JAR Java 17; Java Swing / AWT (JFrame, JPanel, Graphics2D, javax.swing.Timer, layout managers); Taskbar API for the macOS dock icon; Packaged as a standalone runnable JAR (MineSweeper.jar)

JavaSwingObject-oriented designEvent-driven programming
No. 12

Instagram Non Follower Finder

A desktop app that automates finding Instagram accounts you follow that don't follow you back. Built with Python, Selenium WebDriver, and CustomTkinter — it drives a real browser to scroll and extract your follower/following lists, applies hand-rolled anti-bot stealth, and presents the diff in a clean dark-mode GUI with cross-browser support. Cross-browser — Chrome, Firefox, Edge, Safari; Stealth mode — patches automation fingerprints to reduce bot detection across browsers; Manual login flow with full 2FA and captcha support; Auto-downloads browser drivers (no PATH setup required); Accumulates users across virtual-scroll batches so no one is missed; Results copyable to clipboard The app launches a real browser through Selenium WebDriver and lets you log in manually (so 2FA and captchas just work). To reduce automation detection, it injects a small stealth script that redefines navigator.webdriver — via the Chrome DevTools Protocol (Page.addScriptToEvaluateOnNewDocument) on Chromium browsers and executescript on Firefox — alongside flags like --disable-blink-features=AutomationControlled and Firefox's dom.webdriver.enabled = false. It then opens your followers and following dialogs and uses ActionChains with ScrollOrigin to scroll the virtual-scrolling lists, accumulating usernames across batches until the full list is captured. A set difference between following and followers yields the accounts that don't follow you back. All of this runs on a background threading worker so the CustomTkinter UI stays responsive, with per-browser error dialogs when a driver fails to start. Browser automation — Selenium WebDriver driving Chrome, Firefox, Edge, and Safari; Cross-browser abstraction — per-browser options and driver setup behind one flow (match/case); Anti-bot stealth — CDP navigator.webdriver patching and disabling automation fingerprints; Dynamic web scraping — ActionChains + ScrollOrigin to drive virtual-scroll list extraction; Set operations — diff of following vs. followers to surface non-followers; Multithreading & concurrency — background threading worker keeps the GUI responsive; GUI development — CustomTkinter dark-mode desktop interface; Robust error handling — per-browser driver-failure dialogs and captcha/2FA-friendly login; Automatic driver management — webdriver-manager for Firefox/Edge; Chrome 115+ self-manages; Clipboard integration — one-click copy of results; Application packaging — PyInstaller native build via build.py Python 3.10+ (match/case); Selenium WebDriver (Chrome, Firefox, Edge, Safari); CustomTkinter (dark-mode GUI); webdriver-manager (Firefox / Edge driver management); Chrome DevTools Protocol (stealth script injection); threading (responsive UI); PyInstaller (native app packaging)

PythonpipSeleniumConcurrency
No. 13

Biquadris

A two-player competitive Tetris variant built in C++ with an object-oriented design. Originally developed as a final project for CS 246: Object-Oriented Software Development at the University of Waterloo (Fall 2025) by a team of three students, then refactored and extended into a cross-platform, SDL2-rendered game. The game has since been refactored and extended beyond the original submission: bugs fixed, the X11 graphics layer replaced with SDL2 for cross-platform support, and the build system migrated to CMake for easy packaging. Biquadris is a turn-based, two-player spin on Tetris. Both players share one screen — each managing their own 11×18 board. Players alternate turns: you make one move, then your opponent does. Clear two or more lines in a single drop and you earn a special action to punish your opponent. The game ends when a player can no longer place a new block. The codebase is organized around a small set of well-encapsulated classes. Game owns the two Board models and drives the turn loop; each Board tracks its grid, score, level, and active effects; Block encodes the seven tetromino shapes and their rotations; Level generates the next block according to the current difficulty; and the rendering is handled by interchangeable views — a TextDisplay for the terminal and an SDL2 Xwindow for graphics. Two design ideas carry most of the weight. Special actions are a polymorphic effect system (Strategy-style): an abstract Effect base class declares apply, onDrop, isExpired, and getName, and concrete BlindEffect, HeavyEffect, and ForceEffect subclasses implement each behaviour. An EffectManager holds the active effects per board, applies them on activation, ticks them after every drop, and retires them when they expire — so new actions can be added without touching the board logic. The model is fully decoupled from the views: the boards know nothing about how they're drawn, so the same game state renders identically to the terminal or to SDL2. Memory is managed entirely through std::uniqueptr (RAII — no manual new/delete), collision detection validates every move and rotation against the walls and settled cells before committing it, and a single codebase compiles either text-only or with graphics via conditional compilation (ifdef BIQUADRISGRAPHICS). Commands are parsed with unique-prefix matching and numeric multipliers, the high score persists between sessions, and a ghost-block preview shows where the current piece will land. Clearing 2 or more lines in a single drop earns a special action against your opponent: Line clear: (currentlevel + linescleared)² points; A block that scores zero lines resets the combo; clearing any lines resets the no-clear counter (relevant for Level 4 penalty blocks); High score is saved across sessions in .biquadrishighscore Object-oriented design — encapsulated Game, Board, Block, Level, and Effect classes; Polymorphism & abstract base classes — Effect interface with Blind / Heavy / Force subclasses; Inheritance — virtual methods and virtual destructors across the effect hierarchy; Strategy-style effect system — runtime special actions managed by an EffectManager; Model–view separation (MVC) — board state decoupled from the text and SDL2 renderers; RAII & smart pointers — std::uniqueptr ownership throughout, no manual memory management; Modern C++20 — const-correctness, standard containers, move semantics; Collision detection — move and rotation validation against walls and settled cells; Conditional compilation — one codebase builds text-only or with SDL2 graphics; Command parsing — unique-prefix matching with numeric multipliers; File I/O — high-score persistence and script-driven block sequences; Cross-platform build system — CMake with Homebrew SDL2 discovery on macOS; CI/CD release automation — GitHub Actions builds and bundles a distributable macOS app; Game logic — line clearing, level progression, ghost-block preview, and squared scoring C++20;

C++GitHub ActionsCMakeSDL2
No. 14

Go Board Game

A fully playable 19×19 Go board game built in Java using the Processing library. It enforces the Chinese ruleset, handles all the tricky game logic (ko, suicide, group capture via BFS liberty checking), and renders smooth 3D-style stones with real-time hover feedback. https://github.com/user-attachments/assets/b50b9cbb-6e3c-4c03-96b8-1c9e5ed455c8 This project implements the ancient strategy game of Go as a standalone desktop application. It enforces Chinese ruleset scoring, handles all edge-case game logic (ko, suicide, group capture), and renders smooth 3D-style stones with real-time hover feedback — built on top of Processing's Java2D rendering pipeline. Chinese rules — area scoring (stones + territory) with 7.5 komi for White; Capture detection — BFS flood-fill liberty checking for individual stones and connected groups; Ko rule — rejects moves that recreate the previous board position; Suicide prevention — illegal self-capture moves are blocked before placement; Pass & Reset — pass your turn or restart the game at any time; Game end — two consecutive passes trigger automatic scoring and declare a winner; Territory visualisation — empty intersections are marked at game end to show each player's scored regions; 3D stone rendering — each stone is drawn with shadow, radial gradient, and specular highlight layers; Hover preview — semi-transparent ghost stone follows the cursor for precise placement; App icon — custom logo displayed on the window, taskbar, and macOS Dock The board state and rules live in a Go logic class, kept separate from the Sketch class that handles all Processing rendering and input. Captures are resolved with a BFS flood-fill: when a stone is placed, each adjacent enemy group is flooded to count its liberties, and any group with zero liberties is removed. The same liberty check, applied to the just-placed stone, enforces suicide prevention. The ko rule is implemented by snapshotting the previous board position and rejecting any move that would recreate it. At game end (two consecutive passes), the engine performs Chinese area scoring — counting each player's stones plus the empty territory they fully enclose, adding a 7.5 komi for White, and declaring the winner. Stones are rendered as layered 2D primitives (drop shadow, radial gradient body, specular highlight) for a 3D look, and a translucent ghost stone tracks the cursor for precise placement. Object-oriented design — game logic (Go) separated from rendering/input (Sketch); Game-rule engine — complete Go ruleset with Chinese area scoring and komi; BFS flood-fill — stone and connected-group liberty/capture detection; Graph connectivity — flooding adjacent groups to evaluate captures; Ko-rule detection — rejects moves that repeat the previous board position; Suicide-move prevention — illegal self-capture blocked before placement; Territory scoring — enclosed-region detection for end-game area scoring; Custom 2D rendering — layered 3D-style stones (shadow, radial gradient, specular highlight); Interactive UI — real-time hover ghost-stone preview; Game state management — turn order, pass, reset, and automatic end detection; Processing framework — PApplet with the Java2D renderer; Application packaging — window/taskbar/Dock icon and a runnable JAR Java 17; Processing (PApplet, Java2D renderer; core.jar); JOGL / GlueGen (bundled native libraries shipped with Processing for cross-platform support); Packaged as a runnable JAR (Go.jar)

JavaGoProcessingObject-oriented design
No. 15

Snake

A fully playable, built-from-scratch Snake game written in Java Swing — my first independent software project. It implements a complete fixed-timestep game loop, custom 2D rendering, collision detection, and persistent high-score storage using only the Java standard library, with no game engine or third-party dependencies. https://github.com/user-attachments/assets/86964c33-f588-46e8-9a75-cb2526216e93 Grid-based snake movement on a 60×30 board with wrap-around borders; Apple spawning that never lands on the snake's current body; Real-time score plus a persistent high score saved across sessions; Start and game-over overlays, with instant restart (R) without relaunching; WASD and arrow-key controls, with 180° reversal protection; Custom-drawn HUD, snake, food, and translucent message overlays The game is driven by an event-driven loop built on a javax.swing.Timer that fires about 12 times per second (FPS = 12). On each tick the game applies buffered input, advances the snake one cell, runs collision checks, and triggers a repaint. Input is deliberately decoupled from movement: a keypress only sets a pending direction (nextXv / nextYv), which is committed at the start of the next tick. A guard rejects any direct 180° reversal — this eliminates the classic bug where two quick keypresses between frames fold the snake back onto itself. The playfield wraps at every edge, so leaving one side re-enters from the opposite one. The snake's body is stored as a trail of grid coordinates; each tick appends the new head and trims the tail to the current length. Self-collision is detected by scanning the trail for the head's position, and food is re-rolled until it lands on an empty cell. The high score is persisted to a dotfile (~/.snakehighscore) in the user's home directory — loaded on startup, written on every new record, and flushed again on exit (window close or Esc). All visuals are produced in a single custom paintComponent override using AWT Graphics primitives. This was my first programming project, written to learn the fundamentals of Java, event-driven GUI design, and game-loop architecture from the ground up. It has since been refactored to fix several original bugs — timer misuse on the event dispatch thread, game logic embedded in the paint method, and incorrect high-score tracking — while preserving its original structure and scope. Object-oriented design — game model, rendering, and input separated across classes; Event-driven programming — built on Java Swing's event dispatch model; Game loop architecture — fixed-timestep loop via javax.swing.Timer (~12 FPS); 2D rendering — custom paintComponent / Graphics drawing of every element; Collision detection — self-collision and boundary wrap-around; Input handling — buffered direction changes with 180° reversal prevention; Separation of concerns — KeyListener decoupled from game and render logic; File I/O — persistent high-score storage across sessions; Application lifecycle handling — save-on-exit via a WindowListener; Java Platform Module System — modular build with module-info.java; JAR packaging — runnable modular Java application Java 11+; Java Swing (JPanel, JFrame, javax.swing.Timer); AWT (Graphics, Color, Font, FontMetrics, KeyListener / KeyEvent); Java Platform Module System (module-info.java); java.io file I/O; Packaged as a runnable modular JAR (Snake.jar)

JavaSwingObject-oriented designEvent-driven programming
No. 16

Learning

A collection of programming projects spanning my learning journey — from writing my first lines of Java and C++ through implementing classic graph algorithms and teaching others. It ranges across language fundamentals, data-structure and graph-algorithm implementations, small utilities, and material I prepared as a high-school programming instructor. Foundational Java projects built through a structured course, including GUI programs, sound playback, and user input handling. Entry point into object-oriented programming. Java practice workspace from 2022, used for experimenting with new concepts alongside formal coursework. Selected projects from a guided Java curriculum — includes a Length Converter, Word Counter, and an image display program. Focused on practical application of core Java APIs. Implementations of classic graph and tree algorithms in Java: Material prepared and taught as an instructor in a high school programming club. Includes introductory exercises and guided problems written to help beginners get started with Java. Small utilities written for personal use — prime number tools and helper scripts for everyday tasks. Stars and Bars — combinatorics calculator; Galois 2022 4 — solution to a Galois Contest problem; Change Finder — coin change problem variant 26 single-topic programs covering the full introductory C++ curriculum: Variables · Data Types · Numbers · Strings · Arrays · 2D Arrays · User Input · If Statements · Switch Statements · For Loops · While Loops · Functions · Return Values · Pointers · Classes & Objects · Constructor Functions · Getters & Setters · Object Functions · Inheritance · Calculator · Guessing Game · MadLibs · Exponent Function · Comments · HelloWorld Each program isolates one concept, making this a clean reference for C++ fundamentals. Object-oriented programming — Java and C++ fundamentals through to small projects; Data structures — binary search trees and disjoint-set union; Graph algorithms — Dijkstra's shortest path, Prim's & Kruskal's MST, Tarjan's & Kosaraju's SCC; Graph traversal & validation — Eulerian paths and directed/undirected cycle detection; Algorithm implementation — classic graph and tree algorithms written from scratch; Combinatorics & math — stars and bars, coin change, and contest math problems; GUI programming — Java Swing projects with sound playback and user input; C++ fundamentals — 26 single-topic programs (pointers, classes, inheritance, and more); Practical utilities — converters, a word counter, image display, and prime-number tools; Teaching & mentoring — prepared and taught high-school programming-club material; Self-directed learning — a multi-year progression across two languages Java; C++; Java Swing (GUI projects); Eclipse IDE

JavaCSSC++Swing
No. 17

Competitive Programming

Solutions to competitive programming problems from the Canadian Computing Competition (CCC) and DMOJ, written in C, C++, and Java. The collection spans 150+ solved problems across algorithms, data structures, dynamic programming, graph theory, string processing, and computational geometry. The CCC is Canada's premier annual high school programming competition, organized by the University of Waterloo. This repository contains Senior division solutions spanning 15 years (2000–2014), as well as class materials and practice problems from two competition seasons (2022–2024). Sorting & Searching — binary search, merge sort, quicksort, dual-pivot quicksort, BST; Graph Algorithms — BFS, DFS, shortest path, cycle detection, Eulerian paths; Dynamic Programming — coin change, knapsack, frog DP, sequence DP; Data Structures — binary search trees, hash tables, disjoint sets, segment trees; String Processing — pattern matching, compression, encoding (Huffman, Morse, CRC); Math & Combinatorics — modular inverse, fast exponentiation, RSA numbers, Fibonacci; Geometry — Voronoi diagrams, triangle problems, spiral patterns Solutions to problems from DMOJ: Modern Online Judge, an online judge for Canadian high school competitive programming. Competitive programming — CCC and DMOJ contest problem solving; Algorithms & data structures — broad coverage across 150+ solved problems; Graph algorithms — BFS, DFS, shortest path, cycle detection, Eulerian paths, max flow; Dynamic programming — coin change, knapsack, and sequence DP formulations; Sorting & searching — binary search and merge / quick / dual-pivot quicksort; Tree & set structures — binary search trees, disjoint sets, segment trees, hash tables; String processing — pattern matching, compression, and Huffman / Morse / CRC encoding; Math & combinatorics — modular inverse, fast exponentiation, RSA, Fibonacci; Computational geometry — Voronoi diagrams, triangle and spiral problems; Multi-language fluency — solving the same class of problems in C, C++, and Java; Complexity & optimization — meeting contest time and memory limits C; C++; Java; Eclipse IDE (CCC / DMOJ workspaces)

JavaC++CProcessing

Curriculum Vitae

Experience

May 2026 – Present

Ford Motor Company

Software Developer Intern

Working on Android Automotive OS (AAOS) development at Ford, contributing to the in-vehicle Car Dialer app for Ford's infotainment system. Work spans call management via the Android Telecom framework, Bluetooth Hands-Free Profile (HFP) integration, UI development across multi-module architecture, and unit testing with Robolectric.

JavaKotlinXMLAndroid SDKAndroid Automotive OSBash/ShellGroovyGit

Jun 2025 – Aug 2025

University of British Columbia

Undergraduate Research Assistant

Worked under Dr. Martin McKeown and Prof. Z. Jane Wang at the Djavad Mowafaghian Centre for Brain Health, contributing to PIKA — an AI-driven Parkinson's care platform deployed at Vancouver Coastal Health. I owned development of two full-stack hand rehabilitation apps within the platform. HandEase gamifies rehab as a farming-style game where hand gestures control gameplay (finger tapping summons rain to water plants), making exercises feel engaging rather than clinical. Palm & Plant is the medical counterpart, designed for structured clinical sessions with detailed progress tracking. Both share the same core: a computer vision pipeline (OpenCV + MediaPipe) that detects 7 hand gestures at ~90% accuracy in real time (<100ms latency), running entirely on-device to meet PIPEDA and GDPR privacy requirements. I also built activity heatmap dashboards that cut practitioner monitoring overhead by 30%, giving clinicians a clearer picture of patient progress between appointments. Presented at the 11th Singapore International Parkinson Disease & Movement Disorders Symposium, with projected deployment across hospitals in 10+ countries.

PythonOpenCVMediaPipeNumPyPandasMatplotlib

Aug 2021 – May 2024

Kumon Inc.

Math & Reading Instructor

Recruited directly by the Kumon supervisor after standing out as a top-performing student in both Math and Literature — a distinction that made me more effective as an instructor from day one. Over three years, worked with 100+ students across a wide range of skill levels, adapting explanations on the fly to match each student's pace rather than following a rigid script. The core challenge was balancing class-wide flow with meaningful one-on-one attention — reading where each student was at, adjusting in the moment, and delivering feedback precise enough to move them forward without overwhelming them. Consistently saw improvement in both test results and student confidence over time.

The Toolkit

Skills

Languages

Languages across my repositories, by usage.

TypeScriptJavaScriptPythonJavaCSSC++CKotlinProcessing

Concepts

Computer VisionMachine LearningData AnalysisWeb DevelopmentBackend / APIsGame DevelopmentMobile DevelopmentDevOpsAlgorithms & DSAutomation / ScrapingOOP & Design PatternsConcurrencyNetworkingGame PhysicsGame AITesting3D GraphicsRobotics & Embedded

Frameworks

ReactNext.jsSwingJetpack ComposeSDL2

ML / Data

NumPyscikit-learnPyTorch

Tools

GitHub ActionsMakeCMakeTailwindVitestESLintTypeScriptGradlepipJUnitSelenium

Soft Skills

CollaborationTechnical Writing

More

Framer MotionRGraphQLRESTPillowRequestsOpenGLGo

The Grind

Competitive Programming

Problem-solving, pulled live from LeetCode and DMOJ.

The Curator

About

My mom signed me up for a summer Java course over Zoom — AP Computer Science, mostly to get me to stop playing video games. It backfired beautifully: I got hooked on building things instead, and now I build an unreasonable number of games anyway. I'm a CS student at the University of Waterloo, and what really gets me is figuring out how something works and then making something people can actually use — lately that's been Android Automotive at Ford and computer-vision rehab tools at a UBC research lab. Longer term I'm aiming for the deep end — the large-scale systems, AI, and quant work that the biggest tech, research, and trading firms are built on — and I'm at my best with a genuinely hard problem in front of me. Off the clock I'm usually on a snowboard, partway up a climbing wall, or somewhere new.

Off the clock — Snowboarding and skiing in winter, climbing and hiking the rest of the year, and travelling somewhere new whenever I can — usually chasing good coffee and food along the way. Otherwise: board games and chess, a rotating lineup of film and anime, books, music, and building games and little open-source side projects for the fun of it.

Stay in touch

Let's talk