Verdant Depths

A roguelite dungeon crawler built at a game jam

Posted by Clement Wang on June 4, 2026 • Calculating...

Verdant Depths is a roguelite dungeon crawler I built in Python for a game jam in May 2026. Fight through 7 floors of procedurally generated forest ruins, collect perks and relics, and defeat a boss on each floor.

Game trailer

Floor 1 Floor 5
Iron Warden Void Sovereign

The game

Clear all rooms on each floor, defeat the boss, pick a relic, and descend. 7 floors total. Reach the bottom to win.

Controls

Input Action
ZQSD / WASD / Arrows Move
Mouse Aim
Left Click Shoot arrow
Space Dash (invincible while dashing)
Esc Pause/Quit

Game modes

Main menu

The game has three modes. Dungeon is the main run: 7 floors of procedurally connected rooms, perks after combat rooms, a shop per floor, and a relic choice after each boss. Run stats and a best-run high score are tracked.

Arena is a practice mode. Pick any enemy or boss, an optional relic, and fight in a sealed room. No coins, no progression, no healing.

Endless puts you in a sealed room with infinite waves. Every 5-wave cycle rewards HP, perks, and relics. Wave 5 of each cycle spawns a boss and grants a full heal. By cycle 6, every boss wave spawns 3 bosses at once.

Enemies and bosses

12 regular enemies unlock progressively across the 7 floors: melee chasers, teleporting casters, fast erratic bats, and slugs that drop burning patches on the floor.

Enemies

One unique boss per floor, each with a Phase 2 triggered around 50% HP. Phase 2 adds new attacks rather than just speeding up cooldowns. The Ancient Tree gains a continuous thorn pinwheel. The Iron Warden starts charging across the room.

Boss showcase

Boss in action

Perks and relics

After clearing a combat room, pick one of 3 random perks. After each floor boss, pick one of 2 relics. 12 perks and 20 relics total.

Perks are stat upgrades: piercing arrows, double shot, faster dash, larger coin pickup radius. Relics enable build synergies. Venom Gland + Echoing Shot + Piercing Shot turns every arrow into a poison-spreading reflected chain. Curse of Greed doubles coin drops but empties your wallet at the start of each floor.

Perks

Relics

Context

A friend of mine, Guillaume, organized a 3-day game jam over May 24–26, 2026. Paris was in the middle of a heatwave. Guillaume invited six friends to either make something or just hang out in an open space in the center of the city. In the end most people played board games. I still wanted to build something, so I started working on a game on the side, between board game sessions.

The day after, I went to Fontainebleau to boulder on real rock, so I didn’t get much done during the jam itself. The game ended up being built over two weeks of evenings after work.

I first tried Ursina Engine, a Python library for 3D game development. It wouldn’t run on my Mac, so I moved to Pygame and 2D.

I spent a few hours on a game where a tourist walks around Paris, visits landmarks, and dodges sunrays. It was bad, there was no reason to keep playing. So I started over and landed on the roguelite idea: procedural content is easy to generate and gives a lot of content with little work.

Technical highlights

Wall-aware enemy steering. Enemy._steer_toward probes 8 compass directions ahead, scores each by dot-product with the goal vector, and subtracts a penalty for directions that hit a wall tile. The highest-scoring direction becomes the velocity. No pathfinding graph, no nav-mesh, O(1) per enemy per frame. Getting this right took several hours: enemies have circle hitboxes and kept getting stuck on wall corners.

State machine. The game has 18 states: MENU, PLAYING, TRANSITIONING, UPGRADE, SHOP, FLOOR_CLEAR, RELIC, VICTORY, DEAD, ARENA_SELECT, ARENA_RELIC_SELECT, ARENA, ARENA_WIN, ARENA_DEAD, ENDLESS_SELECT, ENDLESS, ENDLESS_BETWEEN, ENDLESS_DEAD. Each state has a dedicated event handler, update function, and draw function. Room transitions use a smooth-step pan over 0.38s.

Web deployment with pygbag. I wanted anyone to be able to play the game without installing anything. pygbag compiles a Pygame project to WebAssembly so it runs directly in the browser. The output is a static bundle that I uploaded to itch.io, which gives the embedded player you see above.

Game balance. For the shop, I computed the expected number of coins per floor from the enemy count and spawn tables. I then set HP vial and perk prices so that clearing all combat rooms affords exactly one of each per floor, with prices scaling across the 7 floors. Boss HP follows the same logic: it is tuned against the player’s expected damage output at that point in a run, accounting for stacked perks and relics. I probably made it too hard since that’s what I personally like.

Conclusion

I have been focused on my PhD thesis for the past few months, and this was a good break. This won’t be the game of the year, but I like it quite a bit. I probably played it for more than 10 hours over the two weeks.