The rectangles are gone. I repeat: the rectangles are gone. I have real pixels now. From a real artist. An actual human being made these sprites and I put them in the game and I cannot stress enough how much of a difference it makes when your bomb looks like a bomb and not a dark gray circle that my brother describes as “a depressed Oreo.”
If you missed devlogs #1, I built a Bomberman clone with colored rectangles, a 20Hz tick loop, and bot AI that occasionally chose violence over self-preservation. I’m temporarily calling it Medieval Boom — it’s still a Boom clone at heart, but the Tiny Swords assets give it a medieval vibe, and “untitled-bomberman-thing” was starting to hurt my feelings. Since then, three things happened: I got sprites, I built a map editor, and the lobby stopped looking like a debug panel someone forgot to style. Let’s go.
Real pixels, from a real artist

I’m using Tiny Swords by Pixel Frog. It’s a free asset pack — yes, free, because the best things in game dev are someone else’s generosity. 64×64 tile grid, PNG spritesheets, 10fps animations. It is exactly what happens when someone with actual talent makes the art that a programmer could not. Every frame is a reminder of what the game could have looked like if I’d drawn it myself: a crime.
Sprite loading happens in a dedicated PreloadScene — a Phaser scene whose only job is to load everything before handing off to GameScene. Every character sprite is a spritesheet keyed by {class}-{color}-{animation}. Five classes times five colors times four animations = 100 spritesheets. My hard drive is sending angry letters.
Animation frame counts live in a config table because the asset pack wasn’t designed to be uniform — it was designed to look good, and the artist succeeded:
const ANIM_FRAMES = {
warrior: { idle: 8, run: 6, attack: 4 },
archer: { idle: 6, run: 4, attack: 8 },
lancer: { idle: 12, run: 6, attack: 3 },
pawn: { idle: 8, run: 6, attack: 6 },
monk: { idle: 6, run: 4, attack: 11 },
}
The lancer’s idle is 12 frames. Twelve. The lancer is doing a full calisthenics routine while everyone else is breathing. Meanwhile the lancer attacks in 3 frames — one swing, done, back to the calisthenics. All animations run at 10fps, which is the asset pack’s intended framerate. Pixel art is the one domain where low framerate is “aesthetic” instead of “your computer is on fire.”
Tile sprites come from a tile-assets.json registry. Walls get 4 randomly-assigned rock variants (the assetId stores which one — pixel art seasoning). Breakable blocks are a custom pixel-art crate I made myself, which is why it looks like a crate designed by someone whose only reference was a verbal description of a crate. Bushes are animated. They sway. They are the only ambient life in this entire game and I will protect them. More tile types coming later — right now the palette is “functional,” which is artist-speak for “bare minimum.”
Everything sits on a depth layer system: Ground(0) → Tiles(1) → Powerups(2) → Bombs(2.5) → Entities(3, Y-sorted) → Bubble(3.5) → Explosions(4) → UI(5). Entities at depth 3 get 3 + y / 1000 so characters lower on screen render in front — the oldest trick in the 2D book.
The map builder

This is the feature I did not plan to build and could not stop building. It started as “wouldn’t it be nice to place tiles manually” and ended as a full tile editor with undo/redo, BFS-based validation, spawn point placement, and save/load. I have a problem. The problem is that building tools is more fun than building the thing the tool is for.
The builder is a Vue component rendering the 15×13 grid as a CSS grid. Three modes: Paint (select sprite, click-drag to paint, right-click erases), Eraser (click-drag to clear), and Spawn (click cells to place numbered spawn points P1–P8). Each tile carries a bitmask — Solid, Breakable, Pushable — with flag checkboxes in the sidebar. The system auto-constrains: Pushable requires Solid, because a pushable tile you can walk through isn’t pushable, it’s a suggestion.
The metadata panel captures maxPlayers (1–8), spawn point positions, powerupChance (0.0–1.0 probability per breakable block), and powerupWeights (per-type distribution). Map design is now a numbers game. You’re not just painting tiles, you’re tuning an economy. I am accidentally a game designer.
Validation runs three checks: spawn on solid (funny exactly once), spawn count vs maxPlayers, and a BFS flood-fill from all spawn points to detect unreachable tiles — the case where you accidentally wall off a section and create a little prison where powerups go to die.
Undo/redo is stack-based, 50 levels, Ctrl+Z / Ctrl+Y. I built this because I kept accidentally painting over my own maps and getting mad at myself, and the correct solution is not “be more careful” — it’s “build an undo system.” Maps save to a server endpoint, load by slug, or download as JSON. I shipped five pre-built maps. They are all balanced and thoroughly tested. That’s a lie. They are maps that exist and nobody has died on them yet.
Pick your fighter
Five classes. Each one a different way to ruin someone’s day:
| Class | Speed | Bombs | Fire | Vibe |
|---|---|---|---|---|
| Warrior | 4→7 | 2→5 | 2→5 | Balanced. The “I just want to play the game” pick. |
| Archer | 7→9 | 1→4 | 1→4 | Fast. The “you can’t catch me” pick. |
| Lancer | 5→6 | 1→4 | 3→7 | Range. The “I will reach you from across the map” pick. |
| Pawn | 5→6 | 3→7 | 1→4 | Bomb spam. The “coverage over quality” pick. |
| Monk | 5→7 | 1→5 | 2→5 | Balanced-but-slightly-faster. The “I read a tier list” pick. |
The lancer has max fire 7 — bombs that reach halfway across the map while moving like they’re wading through honey. The pawn starts with 3 simultaneous bombs and caps at 7, which is not a strategy, it’s a zoning violation. The monk exists because I had the sprite and needed a fifth option. This is how game design happens: “I have the art.”
Powerups cap at per-class maximums. Your class choice matters for the entire match. No refunds.
The lobby, now with opinions

The lobby in devlog #1 was “press start, hope for the best.” Now it has class selection, team color, bot configuration, and map choice. It looks like a real game menu. I almost shed a tear.
Team colors: blue, red, purple, yellow, black. Five factions. The color isn’t cosmetic — it determines team membership for the trapped/rescued mechanic from last time. Same-color entities rescue each other. Different-color entities kill each other. I went from two colors to five because I said “what if there were five teams” and my brother wasn’t in the room to stop me.
When you hit start, the lobby assembles an EntityConfig[], JSON-stringifies it, and passes it as a URL query parameter. Yes, through the URL. Yes, it’s a JSON blob in your browser bar. It’s temporary — once Colyseus is in, the room will handle all of this properly. But for now, no, I will not be taking architecture criticism.
Sub-cells: now with 178% more sub-cells
Remember the 3×3 sub-cell system from last time? I upgraded to 5×5. Each tile now has 25 sub-cells instead of 9, making the sub-grid 75×65. The sub-tile dodge still works, the math is unchanged (odd number, exact center), just with finer resolution. The entity hitbox is 5×5 sub-cells — same relative size, higher granularity. Wall sliding nudges ±2 sub-cells instead of ±1.
Why 5 instead of 3? Because 3 was fine for a prototype and I am no longer in prototype territory. I am in “polish the sub-pixel movement until it feels like butter” territory. That’s a real place. It’s where game devs go when they should be sleeping.
What’s next
Multiplayer. The real kind, with Colyseus, where actual humans connect and the server runs the authoritative tick. The fixed 20Hz loop from devlog #1 was designed for this moment. Will it work? Will it explode? Will my brother and I finally yell at each other in real time instead of taking turns? These are the questions that keep me up at night.
Also: real audio files to replace the oscillator symphony, a bubble sprite for the trapped state (currently reusing the aura effect, which makes it look like your character gained a protective glow from a skincare routine), and volume controls so you can mute the game instead of your entire browser tab.
Until then, the sprites are real, the maps are hand-crafted, the lobby has opinions about your class choice, and the lancer is still doing 12 frames of idle animation for absolutely no reason. See you in #3.