JasonFlatford
Skip to content

Case study

Slotomancer — Cross-platform roguelike with hexagonal architecture

A wizard-themed roguelike slot-battler built from the ground up with platform-agnostic game engine, shared UI components, and thin platform adapters. Solo technical leadership from architecture to cloud infrastructure, achieving ~100% code sharing between desktop and mobile platforms.

  • Desktop (Tauri) + Mobile (Expo)
  • 100% code sharing
  • Hexagonal architecture
  • Privacy-first telemetry
  • 350+ cards

The challenge

As a solo founder, I needed to ship simultaneously on desktop and mobile while maintaining the agility to iterate on game balance, add content rapidly, and gather player insights without sacrificing privacy.

  • Solo development constraints: Limited time meant choosing between platforms or finding a way to support both without duplicating work.
  • Content at scale: A roguelike needs hundreds of cards with varied mechanics, but writing custom code for each would create an unsustainable bottleneck.
  • Player trust: Modern gamers expect privacy-first analytics, not invasive data collection—especially from indie developers.

Architecture approach

Multi-shell monorepo pattern

Hexagonal architecture with platform-agnostic game engine and thin platform adapters:

apps/mobile, apps/desktop  (shells: routing/bundling only)
           ↓
packages/game-state        (shared zustand store)
           ↓
packages/screens           (screen compositions)
           ↓
packages/ui                (UI primitives)
           ↓
packages/game-core         (game engine: pure TS, zero platform deps)

Key architectural decisions

  • Platform-agnostic core: Game engine has zero React, React Native, or platform dependencies — pure TypeScript business logic.
  • Dependency inversion: Core engine has no knowledge of platforms that consume it; dependencies point inward only.
  • Shared everything: Screens, UI components, state management, and game logic shared across all platforms.
  • Deterministic gameplay: Seeded RNG enables testing, debugging, and future replay systems.

Key outcomes

Shipped two platforms as one person

100% code sharing meant feature parity by default—no duplicate work, no platform-specific bugs.

Eliminated content bottlenecks

Standard effects system handles 95% of cards declaratively; Content Forge lets non-engineers create game-ready assets with AI assistance.

Built player trust

Opt-in telemetry with hashed IDs, automatic retention limits, and instant opt-out earned beta community confidence.

Game engine design

Turn structure

An 11-phase canonical turn eliminates race conditions and timing ambiguity:

  1. Start of turn → passive effects trigger
  2. Spin the slot machine → draw symbols
  3. Mana symbols → add to pools
  4. Spells → execute effect chains
  5. Player creatures → attack opponent
  6. Enemy creatures → attack player
  7. End of combat → cleanup triggers

Determinism for testing

Seeded RNG (never Math.random()) means every test can reproduce exact gameplay sequences—critical for debugging card interactions and validating balance changes.

Core systems

Meta-progression loops

  • Card unlocks: Win battles and complete achievements to expand your permanent collection across all runs.
  • Ascension perks: Earn points from victories to purchase permanent modifiers (max 5 active)—build synergies between runs.
  • In-run economy: Spend 10 mana for tactical choices like artifacts, HP refills, deck removal, or rarity upgrades.

Effects system at scale

Standard effects (dealDamage, apply, mana, modify, spawn, cleanse, draw) handle 95% of the 350+ cards declaratively:

  • Every effect supports conditions (mana/HP/turn thresholds) and repeat counts
  • Targeting helpers (adjacent, surrounding, all creatures) prevent manual bugs
  • Custom effects registry exists only for truly unique mechanics

Privacy-first telemetry

Designed an analytics system that earns player trust: opt-in only, hashed IDs, automatic data deletion, and instant opt-out. Built with Terraform for infrastructure as code.

What gets tracked

  • Sessions: platform, OS, duration (no device fingerprinting)
  • Run outcomes: victory/defeat with final deck composition and artifacts
  • Player choices: which cards/artifacts offered vs. selected
  • Errors: crash reports (always sent if telemetry enabled)

Client-side safeguards

  • SHA-256 hashed profile IDs—never plain text
  • Event batching with 45-second flush + exponential backoff retry
  • 24-hour local discard policy for undelivered events

Content Forge: AI-assisted creation

Built a Python desktop app that lets non-engineers create wizards, cards, and artifacts with AI-generated pixel art—then export game-ready JSON + sprites in one click.

Workflow

  1. Describe the card/wizard/artifact in natural language
  2. AI generates pixel art + suggested effects
  3. Refine mechanics using the effects palette
  4. Export validates against Zod schemas
  5. Drop JSON + sprites into game content directory—auto-loaded on next launch

Development practices

Testing philosophy

"Game-true" unit tests model real gameplay sequences with seeded RNG:

  • Card contracts: verify rules text matches actual behavior
  • Effects battery: comprehensive coverage for standard + custom effects
  • Phase-aware timing: assert effects fire in correct turn phases
  • Reproducible runs: seeded tests catch non-deterministic bugs

Monorepo structure

  • pnpm workspaces for dependency management
  • Shared TypeScript config across packages
  • Vitest for unified testing

By the numbers

100%
Code sharing (desktop + mobile)
~60%
Faster iteration vs. dual-codebase
<500
Lines per platform shell
350+
Cards (95% declarative)
17+
Technical docs
Zero
Platform deps in game-core

Lessons learned

What worked

  • Ports-and-adapters from day one: Testing game logic without launching a mobile emulator or desktop window saved hundreds of hours.
  • Documentation as a first-class artifact: Writing rules/architecture docs enabled effective AI pair programming and async collaboration.
  • Opt-in telemetry with no compromises: SHA-256 hashing, 90-day auto-delete, and instant opt-out built beta community trust from day one.
  • Tooling investment pays dividends: Content Forge turned content creation from a week-long engineering task into a minutes-long design task.

What I'd do differently

  • Event-driven from the start: Refactoring from phase-based to event-driven mid-development was painful; should have started there.
  • GUI-first for Content Forge: Started as a JSON editor; building the visual UI from day one would have accelerated non-engineer adoption.
  • Replay system earlier: Deterministic RNG enables replays for free; wish I'd built this for debugging and content creation sooner.
  • Smaller, composable effects: Some custom effects are monolithic; more aggressive composition would improve extensibility.

Let's connect

I'm available to discuss the architecture, technical decisions, and product thinking behind Slotomancer. Happy to dive deep into cross-platform architecture, game engine design, or infrastructure as code.

Back to top ↑

Press Esc to close • ⌘K / Ctrl K to open