I was heavily inspired by the addictive character-raising gameplay loop of Uma Musume: Pretty Derby. I loved the tension of training a character over a series of turns and testing their build in races/battles. However, I wanted to change the focus: shifting from raising athletes to forging gritty, battle-hardened military commanders. In Bannerfall, you train raw recruits into legendary, immutable generals whose "ghosts" will represent and defend your rank in your subreddit's arena.
What it does
Bannerfall (working title: Tiny Tacticians) is a turn-based tactical roguelike that lives directly inside a Reddit post. Players run short, 8-turn training sessions to customize a recruit. After the run, the server mints an immutable General with unique stats, tiers, and abilities. Players then deploy their general to an asynchronous arena to battle the "ghost" units of other redditors in the community, climbing the daily leaderboard, completing daily challenges, and upgrading their permanent settlement.
How I built it
I built the project from the ground up for the Reddit Devvit Web platform using:
- Client-side: Phaser 4 and TypeScript for responsive, high-performance webview rendering and animations.
- Server-side: Express 5 running inside Devvit's serverless runtime (src/server/index.ts).
- Persistence: Devvit-managed Redis for high-speed atomic transactions, matchmaking, and leaderboard scores.
- Integrity: A shared deterministic engine (simulateRun.ts and simulateBattle.ts) written in TypeScript that runs on both client and server to guarantee absolute anti-cheat validation.
Challenges I ran into
My primary game design challenge was balancing the short 8-turn training loop. Because runs are brief, I faced a high risk of players quickly optimizing their choices, leading to an influx of identical, "perfect" generals that would saturate the leaderboard and make PvP dull.
To prevent this and keep every minted general unique, I implemented a system of diminishing training returns in balance.ts. If a recruit's stat $S_t$ at turn $t$ approaches the absolute limit $S_{max}$, the stat increase is mathematically throttled:
$$S_{t+1} = S_t + \max\left(1, \left\lfloor \Delta_{base} \cdot \left(1 - \frac{S_t}{S_{max}}\right) \cdot D_{seed} \right\rfloor\right)$$
Where $D_{seed} \in {0.5, 1.0, 1.5}$ represents the outcome coefficient of the seeded dice roll in dice.ts (Fail, Normal, or Critical). This logarithmic approach ensures that while players can optimize their strategies, achieving perfect stats is mathematically restricted, preserving the value of rare high-tier generals.
Accomplishments that I'm proud of
- 100% Authoritative Server: Built a zero-trust model where the client never has authority over stats or battle outcomes. The server re-runs the simulation log to mint generals and resolve combats.
- Async Ghost Arena: Created a matchmaking system that pairs players with saved generals from the community, ensuring the arena is always active even without real-time netcode.
- Optimized Resource Management: Managed to squeeze a full tactics game engine, rich visuals, and persistence into Devvit's serverless execution limits (30s timeout, Redis memory).
What I learned
I learned that building games for constrained social platforms like Reddit requires a different architectural mindset. By shifting from a traditional client-server state sync to a pure deterministic simulation replay model, I was able to bypass high latency and cheating concerns completely.
What's next for Tiny Tacticians
I plan to expand the game with new advisor archetypes, seasonal PvE campaigns, and richer settlement customization. I also want to explore guild-like military alliances within Reddit communities to make the asynchronous arena experience even more collaborative.
Built With
- devvit
- express.js
- phaser.js
- redis
- vite
- vitest
Log in or sign up for Devpost to join the conversation.