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;