Inspiration

We set out to merge two seemingly opposite design philosophies: the deliberate, punishing combat of Dark Souls and the agile, fluid traversal of Hollow Knight: Silksong. But instead of a dark gothic palette, we wrapped our mechanics in a Pokémon-style retro RPG world.

The result is Soulsong: a 2D pixel-art hack-and-slash where overworld exploration feels nostalgic—colorful villages, grassy routes, dungeon tilesets—while combat delivers precision-driven duels.

Our north star was simple: create a mastery-driven experience where difficulty feels earned. A fair but punishing design loop where

skill × timing × anticipation = satisfaction.


What it does

Soulsong is a combat-first adventure set in a retro, tile-based world. Players explore a Pokémon-style overworld with routes, towns, and NPCs—but when enemies engage, the system shifts to real-time duels that demand precision.

Core mechanics:

  • Readable telegraphs (retro-sprite enemies with exaggerated windups)
  • Tight dodge and parry windows (skill > luck)
  • Resource trade-offs (stamina vs. opportunity)

The visual design emphasizes 16-bit nostalgia: vibrant palettes, tile-mapped environments, and charming overworld sprites. But once combat starts, dynamic lighting, hit-flash effects, and retro particle bursts add intensity. Think “Pokémon overworld meets Soulslike duel.”


How we built it

We approached development with a data-driven, iterative workflow:

  1. Combat Framework
  • Retro sprites are animated on a frame grid, letting us measure i-frames and attack cancels exactly.
  • Formula for dodge balance:

$$ \text{Survivability} = \frac{\text{Invincibility Duration}}{\text{Enemy Attack Window}} - \text{Stamina Cost Factor} $$

Our target was a survivability ratio of ~0.8–1.0.

   // Dodge tuned to retro pacing
   if (Phaser.Input.Keyboard.JustDown(this.keys.Z) && this.playerStamina >= 15) {
     this.player.setData("isDodging", true);
     this.playerStamina -= 15;

     this.time.delayedCall(180, () => this.player.setData("invincible", true));
     this.time.delayedCall(360, () => this.player.setData("invincible", false));
     this.time.delayedCall(500, () => this.player.setData("isDodging", false));
   }
  1. Enemy AI
  • Instead of chaotic RNG, each retro enemy telegraphs with sprite windups—a “blink” animation or a glowing tile.
  • Players always see a cue before damage.
   if (distance < 100 && this.time.now > this.enemy.getData("nextAttack")) {
     this.enemy.play("windup"); // retro sprite flash
     this.time.delayedCall(300, () => this.enemy.play("attack"));
     this.enemy.setData("nextAttack", this.time.now + 1000);
   }
  1. Animation Blending
  • Heavy swings originally felt stiff.
  • We added cancel windows—retro animation can chain at 60% progress.
   this.player.play("sword_heavy");
   this.player.setData("locked", true);

   this.time.delayedCall(480, () => {
     this.player.setData("locked", false); // chain at 0.48s
   });
  1. Retro Optimization
  • Overworld uses tilemaps for Pokémon-style environments.
  • Particle pooling ensures effects (slash arcs, dust clouds) cost <5% frame time.
   if (!this.slashEmitter) {
     this.slashEmitter = this.add.particles("spark").createEmitter({
       speed: { min: -100, max: 100 },
       lifespan: 400,
       quantity: 3,
       on: false
     });
   }
   this.slashEmitter.emitParticleAt(x, y);

Challenges we ran into

  • Tone Balance: Retro Pokémon charm vs. Soulslike intensity.
  • Clarity vs. Nostalgia: Keeping telegraphs obvious while staying in an 8×8 or 16×16 sprite grid.
  • Performance: Tile-based maps plus dynamic combat effects pushed memory usage.
  • Combat Readability: Retro overworld sprites weren’t enough—so we added glow/tile effects for attacks.

Accomplishments we’re proud of

  1. Hybrid Aesthetic: Overworld exploration feels like Pokémon Red/Blue, but combat feels like Souls.
  2. Combat Mastery Loop: Playtesters describe duels as “brutal but fair.”
  3. Cohesive Retro Visual Identity: Pixel tiles + sprite telegraphs + chiptune audio = unique identity.
  4. System Interconnection: Overworld exploration feeds into combat; stamina/positioning drive moment-to-moment decisions.

What we learned

  • Fairness is measurable—even in a retro system.
  • Scope matters: building the overworld in a Pokémon-style tilemap gave us fast iteration.
  • Performance is gameplay: optimized effects = smooth duels at 60 FPS.
  • Retro doesn’t mean simple: we can have nostalgia and depth.

What’s next for Soulsong

  • Expanded Overworld: New biomes (icy routes, lava caves, haunted forests).
  • Enemy Archetypes: Retro bosses with multi-phase duels.
  • Player Progression: Unlockable weapons, abilities, retro-style equipment menus.
  • Public Demo: To validate the hybrid identity with retro RPG + Soulslike fans.

The takeaway

Soulsong proves you can marry retro RPG charm with Soulslike precision combat.

It is evidence of a team that can:

  • Frame design as measurable systems,
  • Solve problems with disciplined iteration,
  • Build a game that balances Pokémon nostalgia with Dark Souls intensity,
  • And scale toward a commercially viable release.

The foundation is solid, the vision is unique, and the execution is systematic. The next stage is to expand this retro-Soulslike hybrid into a full content-rich release.

Share this project:

Updates