JasonFlatford
Skip to content

Architecture

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.

Interested in cross-platform architecture?

I'd enjoy discussing ports-and-adapters patterns, monorepo strategies, or building game engines with pure business logic. Whether you're shipping on multiple platforms or solving similar challenges, let's compare notes.

Return to top

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