An ARPG engine prototype, built as a playground for exploring functional game development patterns in F# and MonoGame.
Kipo is an isometric action-RPG engine written entirely in F#. It's a technical sandbox where serious engineering meets game development curiosity. If you've ever wondered what an RPG engine looks like built from the ground up with functional principles—here it is.
This isn't a finished game. It's a working prototype with real systems: combat, AI, skills, projectiles, visual effects, and more. The architecture is designed for performance and maintainability, but the scope is still evolving.
State is strictly separated from logic. We prioritize using immutable data structures that flow through pure transformation functions, aiming for code that is easier to reason about, test, and parallelize.
The engine is built with a focus on minimizing GC pressure. We aim to keep critical paths low-allocation by using struct discriminated unions, pooled array buffers, and explicit command queues. State writes are designed to be batched and flushed once per frame.
2D game logic is projected into 3D isometric space via a parallelized command-based renderer. Entities, terrain, and particles are submitted as render commands, which the engine attempts to sort and draw efficiently.
Enemy behaviors are defined using archetypes and decision trees—all in JSON. The architecture supports modular perception, memory, and skill selection systems, avoiding hardcoded enemy logic.
Particles aren't just billboards. The VFX system is designed to support both 2D textures and 3D mesh particles (spinning coins, rising pillars, tumbling debris) with full physics integration.
Skills, items, AI archetypes, animations, model rigs, and particle effects are configured in JSON files. This structure allows designers to iterate without touching code.
The core library (Pomo.Core) is designed to run on Windows (DirectX), Linux/macOS (DesktopGL), and Android. iOS scaffolding is available but less tested.
Kipo/
├── Pomo.Core/ # Shared game logic (F#)
│ ├── Domain/ # Types and data models
│ ├── Systems/ # Game systems (AI, Combat, Rendering, etc.)
│ ├── Rendering/ # Emitters and render math
│ └── Content/ # JSON configs and assets
├── Pomo.DesktopGL/ # Desktop runner (Linux/macOS/Windows)
├── Pomo.WindowsDX/ # Windows DirectX runner
├── Pomo.Android/ # Android runner
├── Pomo.Core.Tests/ # Unit tests
└── docs/ # Additional documentation
- .NET 10 SDK or later
- MonoGame (pulled via NuGet)
# Clone the repository
git clone https://github.com/AngelMunoz/Kipo.git
cd Kipo
# Restore .NET tools
dotnet tool restore
# Restore .NET workloads (aka android, wasm-tools, etc.)
# run with `sudo` on Linux/macOS if necessary
dotnet workload restore
# Restore dependencies
# Expected error on Linux: error NETSDK1178: The project depends on the following workload packs that do not exist in any of the workloads available in this installation: Microsoft.iOS.Sdk: .net10.0_26.2
dotnet restore
# Run the DesktopGL version
dotnet run --project Pomo.DesktopGL/Pomo.DesktopGL.fsprojdotnet test Pomo.Core.TestsNote
These bindings are for testing and will likely change but overall this is how the keybindings are structured
There's currently 3 action sets, you can change them by pressing 1, 2 or 3 in your keyboard The action sets span in a "square" in the keyboard
Q, W, E, R A, S, D, F
Those keys contain the skills.
Action Set 1
Q -> press Q then click anywhere, no need to select enemy entity W, E, R -> Press the Key, then click on an enemy entity A, S -> press to "activate buffs"
Action Set 2
Q -> HP Potion W -> HP Regenerating potion
Action Set 3 Q, W -> Press Key then click in the direction you want to launch the attack E, R -> Press Key then click on enemy entity A -> Press Key then click in the direction you want to launch the attack S -> Press Key then click anywhere to launch a charged attack in the selected position
Rider / Visual Studio: Open Pomo.slnx. Should work out of the box for desktop targets.
VS Code: Install the Ionide extension for F# support. Press F5 to debug.
See LICENSE for details.
