Pixel Art Game Development: What I Learned Hitting the Walls
These are my honest notes from building a pixel-art game inside a Next.js portfolio, with AI assisting much of the code. The game started as a fork of another developer's portfolio, and the hardest unsolved problems turned out to be in the art, not the code. AI-generated character sprites kept coming out with the wrong proportions at small sizes like 16×16 and 32×32: heads too big, limbs misaligned, walk cycles that looked robotic. Keeping a tileset cohesive was a systems problem too, because everything has to share one palette, one pixel density, and one art style, or the whole scene reads inconsistent. Even the code had friction: running a game engine (Phaser) inside a framework that server-renders by default meant every import crashed the build until I isolated it with a no-SSR dynamic import.
The game itself is a Pokemon-style world you walk through to explore my career story: themed buildings, NPC dialogue, grid-based movement, and collision. It works, and you can play the current version. But this stays the most honest page on the site, because that honesty is the point. What follows is what works, what still looks like a prototype rather than a finished piece, and what I actually learned about where AI-assisted game development falls short.
Play the current versionGame mechanics that work
- Grid-based character movement with 4-directional walking
- Overworld map with themed buildings (Innovation Labs, Leadership Tower, Tech Hub)
- Building interaction system, walk up, press Enter, get dialogue
- Pokemon-style dialogue box with professional content
- Animated water with wave effects
- Mobile touch controls (D-pad overlay)
- Dynamic loading via Next.js dynamic import (no SSR for Phaser)
Pixel art for game developers: where AI and small sprites break down
Building a game inside a web framework designed for documents is full of friction. Here's every major problem encountered, solved or not.
Phaser.js + Next.js SSR conflict
SolvedPhaser requires the DOM and window object. Next.js server-renders by default. Every Phaser import crashed the build. Solution: dynamic(() => import(...), { ssr: false }) wrapper. Took multiple iterations to get right.
Programmatic vs hand-drawn pixel art sprites
OpenThe initial approach generated pixel art via HTML5 Canvas at runtime, colored rectangles for buildings, basic shapes for the character. It works technically but looks like a prototype, not a portfolio piece. Professional tilesets are needed.
Pixel art character sprite proportions (16×16, 32×32)
OpenAI-generated pixel art characters kept having wrong proportions, heads too big, limbs misaligned, walk cycles that looked robotic. Pixel art is a specialized skill that current AI tools struggle with at small sprite sizes (16×16, 32×32).
Tileset consistency: shared palette and pixel density
OpenMixing programmatic sprites with hand-drawn or AI-generated tiles creates visual inconsistency. Everything needs to share the same palette, pixel density, and art style. This requires either commissioning a tileset or finding a cohesive free pack.
Mobile performance
ManagedPhaser.js game engine running inside a React app inside a mobile browser is three layers of overhead. Touch controls need to be responsive without interfering with browser gestures (scroll, back swipe). Ongoing tuning.
Name attribution in forked assets
SolvedThe game was initially forked from another developer's portfolio. Original names were embedded deep in sprite filenames, frame references, and game config. Required a full audit to rename every reference, 15+ files touched.
Choosing the stack: Phaser over CSS, and running it in Next.js
Phaser.js over CSS animations
Needed real game mechanics: collision detection, sprite management, camera following, tile maps. CSS can't do this.
Dynamic import, no SSR
Phaser needs window/DOM. Wrapping in dynamic(() => import(), { ssr: false }) isolates it from Next.js server rendering.
Programmatic sprites (for now)
Faster to iterate than managing sprite sheets. Will replace with professional assets once the game mechanics are solid.
Separate /game route
Game is heavy (~200KB component). Isolating it prevents impact on homepage load performance and SEO.
How the game is built
Game Engine
Phaser.js 3Handles rendering, physics, input, sprites, camera. Runs in a canvas element inside the React tree.
React Wrapper
Next.js dynamic importHomepageGame component (208 lines) loaded client-side only. Manages Phaser lifecycle within React.
Assets
Programmatic (Canvas API)Sprites generated at runtime via Canvas. No external sprite sheets yet, this is the main quality bottleneck.
Interaction
Keyboard + TouchArrow keys on desktop, virtual D-pad on mobile. Enter key triggers building dialogues.
What's next for the game
- ○Professional tileset, cohesive 16-bit art style
- ○Proper character sprite with smooth walk animation
- ○Interactive career exploration, enter buildings to learn about each role
- ○NPC dialogues with career highlights
- ○Sound design, ambient music, interaction sounds