Portfolio
Developer portfolio with embedded Tetris WASM game

Overview
This portfolio is more than a showcase — it's a technical demonstration. Built with Next.js 15 and React 19, it features an embedded Tetris game running entirely in the browser, powered by a Rust game engine compiled to WebAssembly via the Bevy ECS framework.
The goal was to push beyond the typical developer portfolio and demonstrate full-stack range — from modern React and server components on the frontend, to systems-level Rust programming for a real-time game engine. Everything is tied together with a code-editor-inspired dark theme that reflects the craft of building software.
Built for recruiters, hiring managers, and fellow developers who want to see what's possible when web technologies meet native performance.
Technical Highlights
Architecture: Next.js 15 app router with full server component support. Pages are statically rendered at build time, with client components only where interactivity is needed — like the Tetris game overlay and score tracking.
WASM Integration: The Tetris game engine is written in Rust using the Bevy ECS framework, compiled to WebAssembly with wasm-pack. The WASM module renders to an HTML canvas while communicating game state to React through browser CustomEvents — a clean bridge between two runtimes.
State Management: Jotai was chosen over Redux for game state because the state graph is simple and flat — score, level, lines, phase. Jotai's atom-based model avoids boilerplate and integrates naturally with React's rendering cycle, even when updates come from outside React (via the WASM event bridge).
Styling: Tailwind CSS with SCSS for complex animations. The code-editor aesthetic uses Fira Code monospace, dark navy backgrounds, green and orange accents, glassmorphism effects with backdrop blur, and inset shadows for depth.
Key Features
- Embedded Tetris Game: Fully playable Tetris running in Rust/WebAssembly with Bevy ECS, rendered on an HTML canvas
- High Score Tracking: Local high scores persisted in localStorage with top-3 leaderboard and date tracking
- Animated Start Screen: CSS-animated falling blocks, controls hint, and best score teaser to encourage play
- SEO Optimized: Per-page metadata exports, OpenGraph images, and semantic HTML throughout
- Responsive Design: Adapts from mobile to ultrawide with CSS grid, container queries, and responsive typography
- Blog Section: Pure server-component blog pages with typography system for consistent content presentation
- Contact Form: Server-side email delivery with Nodemailer and Zod validation
Challenges & Solutions
WASM ↔ React Bridge: Bevy's game loop runs independently of React's render cycle. The solution was a CustomEvent-based bridge — the Rust side dispatches browser events with game state, and a React hook listens and updates Jotai atoms. This keeps both systems decoupled while staying in sync.
Game Over Event Storm: The WASM engine was emitting state updates every frame (~60/sec), even when nothing changed. After game over, this created an infinite log spam. Fixed by adding state deduplication on the Rust side — only emitting events when score, level, lines, or phase actually change.
SSR + localStorage: High scores are stored in localStorage, but Jotai atoms initialize during SSR where window is undefined. Solved with a client-side hydration effect that reads localStorage on mount and updates the atom.
Canvas Focus Management: After clicking the "restart" overlay button, the canvas lost focus and stopped receiving keyboard events from Bevy. Fixed by programmatically refocusing the canvas element after restart.
Tech Stack
Next.js 15
Framework, SSR, routing
React 19
UI layer, server components
TypeScript
Type safety across the stack
Tailwind CSS
Utility-first styling
Rust
Game engine language
WebAssembly
Browser game execution
Bevy
Rust ECS game framework
Jotai
Atomic state management
What I Learned
- Bridging native Rust code with web UIs through WebAssembly and browser event APIs — two very different runtime models working together
- Performance considerations for real-time game loops in browsers: minimizing allocations, deduplicating events, and managing render cycles
- State management patterns for hybrid WASM/React applications, where updates originate outside the React tree
- Building a cohesive design system with Tailwind that scales from game UI to content pages while maintaining a consistent aesthetic