Mibo.Raylib
4.3.0
See the version list below for details.
dotnet add package Mibo.Raylib --version 4.3.0
NuGet\Install-Package Mibo.Raylib -Version 4.3.0
<PackageReference Include="Mibo.Raylib" Version="4.3.0" />
<PackageVersion Include="Mibo.Raylib" Version="4.3.0" />
<PackageReference Include="Mibo.Raylib" />
paket add Mibo.Raylib --version 4.3.0
#r "nuget: Mibo.Raylib, 4.3.0"
#:package Mibo.Raylib@4.3.0
#addin nuget:?package=Mibo.Raylib&version=4.3.0
#tool nuget:?package=Mibo.Raylib&version=4.3.0
Mibo
Install the templates:
dotnet new install Mibo.Templates dotnet new mibo-2d -o MyGame # MVU runtime dotnet new mibo-2d-adaptive -o MyGame # adaptive runtime cd MyGame dotnet run
NOTE for ADVENTURERS: raylib is a programming library to enjoy videogames programming; no fancy interface, no visual helpers, no debug button... just coding in the most pure spartan-programmers way.
Following that spirit, Mibo keeps it lean, just F# and the Elmish loop with a handful of commodities to get out of your way and let you enjoy the craft.
Mibo is an Elmish-based F# game framework with two interchangeable backends — raylib-cs and MonoGame (DesktopGL/OpenGL and WindowsDX/DirectX) — designed to allow developers to write games using familiar MVU patterns for all kinds of game genres and sizes.
Mibo aims to solve 80/20 of use cases for enabling developers to focus on game logic rather than boilerplate code, providing guidelines and architecture for structuring game code, handling input, rendering, asset management, and time management among others.
What's in the box?
- Elmish runtime (MVU loop) with
Cmd,Sub, optional fixed timestep, and frame-bounded dispatch - Input — raw input (
Keyboard,Mouse) + semantic mapping viaInputMap/ActionState - Assets — texture, font, sound, and model loading caches
- Rendering — Command buffer based rendering:
- 2D batch renderer with layers and multi-camera support
- 3D batch renderer with opaque/transparent passes and custom shader switching
- Escape hatches for custom GPU work
- Camera helpers with screen-to-world, orbit, and ray casting
- Layout — 2D procedural grid layout (
CellGrid2D) with platformer, top-down, and geometric primitives - Layout3D — 3D voxel-style grid layout (
CellGrid3D) with terrain, interior rooms, corridors, stairs, and procedural generation - Animation — sprite sheet slicing,
AnimatedSpritestate machines, and grid-based animation definitions - Mibo.Adaptive — a pull-based incremental computation library for tight-loop workloads:
CVal/AValroots and projections plus adaptive sets, maps, and lists with element-level deltas, allocation-free in steady state. The Mibo integration (AdaptiveProgram/AdaptiveHeadlessand the windowed hosts) is experimental. - Input Mapper — Listen to raw input and map it to semantic actions
- Performance — zero-allocation hot paths: spatial grid queries return a single result array per call, and per-frame dictionary lookups, light merging, and render-pipeline bookkeeping allocate nothing
Getting started
Prerequisites:
- .NET SDK 8 or later
- A working OpenGL setup
dotnet --version
dotnet tool restore
dotnet restore
dotnet build
dotnet test
To build the docs site locally:
dotnet tool restore
dotnet fsdocs build
# or for live editing:
dotnet fsdocs watch
Samples
The samples are stored in a separate repository: Mibo.Samples.
You'll find examples of:
2D:
- PlatformerSample - A 2D side-scrolling platformer with procedural world generation, sprite animation, lighting, particles, and sound. Uses Mibo's Elmish architecture with
InputMap,AnimatedSprite,CellGrid2D, andLightContext2D.- Mibo.Raylib targeting Desktop OpenGL
- Mibo.MonoGame targeting DesktopGL (cross-platform)
- SpaceBattle - A turn-based tactical strategy game on a hex grid with fog of war, laser combat, particle effects, faction-based turns (Human + AI), and animated unit movement. Demonstrates complex game state management, hex grid spatial queries, and multi-phase turn resolution.
- Mibo.Raylib targeting Desktop OpenGL
- PingPong - A networked multiplayer Pong game with a client-server architecture over WebSockets. The server runs game logic and broadcasts state; the client renders locally and sends input.
- Mibo.Raylib Client
- Mibo.MonoGame Client
- dotnet app acting as a server running Mibo.Core's headless support
3D:
ThreeDSample - A 3D platformer with procedurally generated voxel terrain, PBR lighting, shadow atlas, 3D character animation, minimap overlay, and physics. Showcases Mibo's
Renderer3D,ForwardPbrPipeline, andAnimation3DState.- Mibo.Raylib targeting Desktop OpenGL
- Mibo.MonoGame targeting DesktopGL (cross-platform)
FPSSample - A first-person shooter featuring enemy AI, weapon systems, health management, and atmospheric lighting. Demonstrates Mibo's composable systems architecture with per-system sub-models, event-driven cross-system communication, and a
Systempipeline with snapshot barriers.- Mibo.Raylib targeting Desktop OpenGL
- Mibo.MonoGame targeting DesktopGL (cross-platform)
- Mibo.MonoGame targeting WindowsDX (Windows only, DirectX)
License
Mibo is distributed under the zlib/libpng License.
Built on
Mibo is built on top of:
- raylib — the cross-platform graphics library that powers the raylib backend's rendering, input, and audio layers
- raylib-cs — the C# bindings that make raylib accessible from .NET
- MonoGame — the cross-platform framework that powers the MonoGame backend (DesktopGL/OpenGL and WindowsDX/DirectX)
- AdaptiveSlop — the pull-based incremental computation library by TheAngryByrd that Mibo.Adaptive was adopted from
Mibo.Adaptive originated from AdaptiveSlop — adopted in its entirety, renamed, and maintained as part of Mibo. All design and implementation credit goes to TheAngryByrd.
Feedback
Issues and PRs are very welcome. If you're interested in using F# for game development beyond simple 2D games, Mibo aims to be a practical, batteries-included framework that scales with your ambition.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FSharp.Core (>= 10.1.400)
- FSharp.UMX (>= 1.1.0)
- Mibo.Core (>= 4.3.0)
- Raylib-cs (>= 8.0.0)
-
net8.0
- FSharp.Core (>= 10.1.400)
- FSharp.UMX (>= 1.1.0)
- Mibo.Core (>= 4.3.0)
- Raylib-cs (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.5.0 | 36 | 8/19/2026 |
| 4.4.0 | 71 | 8/18/2026 |
| 4.3.0 | 86 | 8/16/2026 |
| 4.2.0 | 99 | 8/12/2026 |
| 4.1.0 | 82 | 8/10/2026 |
| 4.0.0 | 101 | 8/7/2026 |
| 4.0.0-rc-003 | 94 | 8/3/2026 |
| 4.0.0-rc-002 | 109 | 8/3/2026 |
| 4.0.0-rc-001 | 93 | 8/2/2026 |
| 4.0.0-beta-001 | 91 | 7/28/2026 |
| 3.3.0 | 103 | 7/26/2026 |
| 3.2.0 | 110 | 7/25/2026 |
| 3.1.1 | 105 | 7/23/2026 |
| 3.1.0 | 102 | 7/20/2026 |
| 3.0.0 | 98 | 7/18/2026 |
| 2.2.0 | 101 | 7/16/2026 |
| 2.1.0 | 107 | 7/11/2026 |
| 2.0.1 | 112 | 7/9/2026 |
| 2.0.0 | 114 | 7/9/2026 |
| 2.0.0-rc-003 | 98 | 7/7/2026 |
### Added
- **MonoGame 3D:** `ModelParts.ofModel(model)` turns a content-pipeline model into per-part records ready for `meshSlice`/`instancedSlice` — each part draws straight from the model's shared buffers (no per-part buffer copies) with its slice offsets, its absolute bone transform, and its material; results are cached per model and must be treated as read-only. Static models only — skinned parts render in their bind pose (use `animatedModelInstanced` for those). `InstancedRenderContext` accepts a parts resolver, so grid renderers can instance content models directly with correct bones and offsets.
- **MonoGame 3D:** `Draw.meshSlice`/`Draw.instancedSlice` draw a slice of a mesh within shared content-pipeline vertex/index buffers — pass the part's `vertexOffset`/`startIndex` (`0, 0` for self-contained buffers) and the mesh draws that part's own geometry instead of the first part's triangles. The offsets default to 0, so existing self-contained meshes call them unchanged. The mesh record must describe the part: `PrimitiveCount` is the part's triangle count and `Bounds` its local-space bounding sphere. Shared buffers with more than 65,536 vertices need a 32-bit index buffer (the merged-parts pipeline widens automatically).
- **Adaptive:** deferred work — the adaptive counterpart of `Cmd`. `AdaptiveContext.Intents` takes `unit -> unit` work from `Update` (or any thread) and runs it at the moment the name says: `post` (after this step's `Update`, drained until empty so reaction chains settle before the frame is forced), `postNextFrame` (top of the next step), `postTask`/`postAsync` (background work; the completion returns on the owner thread where root writes are legal). `AdaptiveHeadless.Post` injects work without holding the `Update` context.
- **Adaptive:** subscriptions — the adaptive counterpart of `Sub`. `AdaptiveInit.withSubscriptions` takes a keyed `amap` of `AdaptiveSub` specs (dynamic, state-driven subscription sets can use `AMap.custom`); the runner diffs it per step — gated on the map's version, so clean steps do no diff work — to attach, keep, or detach, and detaches everything on `Dispose`. Attach callbacks receive a posting surface: `Post` queues work for the frame boundary before `Update`, so input published right before a `Step` reaches the sim in that same step. `AdaptiveSub.ofObservable` and `AdaptiveSub.ofTimer` build subscriptions from the common sources, so most code never writes `Attach` by hand.
- **Adaptive:** semantic input mapping — `InputMapper.subscribeAdaptive`/`subscribeStaticAdaptive` (both backends) build an `ActionState` from the `IInput` delta observables and an `InputMap`, writing it into a `cval<ActionState<_>>` root through the pre-step lane; no message, no dispatch. The write settles before `Update`, so the update phase and the frame force read the mapped actions like any other root. Edge events (`Started`/`Released`) accumulate across the deltas within a step via the new `ActionState.mergeEdges` (pure, unit-tested in Core); `Held`/`Values` stay last-wins. The subscription clears the consumed edges after `Update` (after each fixed sub-step's `Update`; a fixed-step frame with no sub-step defers the clear to the next sub-step, so the edges are never lost) and before the frame is forced, so `Update` reads each edge exactly once; no manual clearing is needed, and a manual `ActionState.nextFrame` write stays legal and free. Consume `Held`-style state as projections. The `IInputMapper` service registered by `withInputMapper` is registered only — nothing polls it; the docs now say so.
- **Templates:** `Mibo.Templates` (the `mibo-2d`/`mibo-3d`/`mibo-mg-2d`/`mibo-mg-3d` starters) is now packed and published with each release, versioned from the repo changelog like the libraries.
- **Templates:** adaptive starters — `mibo-2d-adaptive`/`mibo-3d-adaptive` (raylib) and `mibo-mg-2d-adaptive`/`mibo-mg-3d-adaptive` (MonoGame) scaffold the adaptive runtime: roots plus a derived projection built once, an update that writes roots, a pure frame pack, input through the adaptive input-mapper subscription, and `AdaptiveRaylibGame`/`AdaptiveMonoGameGame` host wiring. The existing starters keep their names and stay MVU.
### Changed
- **Docs:** reorganized around the two program runtimes — the MVU guides (Elmish, programs, commands, subscriptions, system pipeline, headless, MonoGame migration) live under their own section; a new Adaptive section mirrors the MVU coverage (overview, programs, intents, subscriptions, systems, scaling, services, headless, background work, derived state); and a new Mibo.Adaptive section documents the incremental-computation library as its own package. Runtime-specific patterns (composable systems, background work, pre-computed state) move under MVU; Patterns keeps the runtime-agnostic pages (pooled particles, layered rendering). The scaling guide splits per runtime — the MVU complexity ladder lives under MVU, a new adaptive scaling ladder under Adaptive. The v1 (raylib-only) archive leaves the sidebar and is linked from the front page instead. Docs now build on fsdocs 22.1.0.
- **Breaking (experimental): Adaptive:** `AdaptiveProgram.Init` and the subscription projection now receive the new `AdaptiveFrameContext` (framework roots + `GameContext`, no work queue); only `Update` receives `AdaptiveContext` with `Intents` — the frame builder cannot defer work by construction.
- **Breaking (experimental): Adaptive:** `AdaptiveHeadless.RunAsync` yields `StepOutcome<'Frame>` (`GameTime` + `Frame`) instead of `struct (GameTime * 'Frame)`.
### Deprecated
- **MonoGame 3D:** `Draw.mesh`/`Draw.instanced` are deprecated on MonoGame — they draw from buffer offset 0, which renders the first part's triangles for a mesh wrapping a part of a shared content-pipeline buffer. Use `meshSlice`/`instancedSlice` (see Added); raylib's `mesh`/`instanced` are unchanged.
### Removed
- **Breaking (experimental): Adaptive:** the restart machinery (`AdaptiveContext.RestartRequested`, `AdaptiveHeadless.Restart()`) — dispose of the runner and create a new one.
### Fixed
- **Input mapping (MonoGame):** the subscription mapper snapshots only the input devices the `InputMap`'s triggers reference — previously every input event (including the per-frame mouse-move event) polled the keyboard, the mouse, and four gamepads, even when the map binds keys only. Behavior is unchanged; the unmapped devices are simply not fetched.
- **Input mapping:** `Started` in the subscription mapper's `buildActions` (both backends) is now a per-ACTION transition, matching core `ActionState.update`: it fires only when the action was NOT already held. Previously each binding press fired `Started` — pressing Left while A already holds the same action re-fired it — while `Released` only fired at full release, so an add-on-Started/subtract-on-Released consumer went +N/−1 and stuck (Defli3D's keyboard pan locked when mixing WASD with arrow synonyms). The `IInputMapper` service's poll loop applies the same transition rule now.
- **Mibo.Adaptive:** the NuGet package now ships its own readme — including the credit note for its AdaptiveSlop origin — instead of the repo root readme.
- **Raylib 3D:** alpha-blended billboards — particles and other transparent quads — no longer write depth, so a transparent billboard no longer hides the geometry or particles behind it.
- **Raylib 2D:** full-circle ring outlines no longer show a radial line where the ring closes. Partial arcs keep their end caps.
- **Raylib 2D:** filled triangles, triangle fans and triangle strips now render in any winding order. Clockwise point lists drew nothing on raylib while MonoGame rendered them; both backends now agree.
- **MonoGame 2D:** ring outlines draw as two clean rings — the outline no longer fills in as a band, and full circles no longer show a radial seam where the ring closes. Partial arcs keep their end caps.
- **MonoGame 2D:** sprites and shapes now keep their draw order when sampler-state commands are interleaved — text no longer renders behind shapes on top of it.
- **MonoGame 2D:** flushing the shape batch no longer copies its vertices into a new array — scenes that flush often (HUDs that interleave text and shapes) stop producing garbage on every flush.
- **MonoGame 3D:** cube, plane and cone primitives now face outward under the default cull mode — the cube no longer shows its interior and the plane no longer vanishes from one side.
- **2D:** triangle fans now auto-close the rim on every backend — the last rim vertex connects back to the first, so a full convex rim fills its polygon. raylib previously left the wedge between the last and first rim vertex unfilled while MonoGame closed it.
- **MonoGame 3D:** translucent materials, alpha-blended billboards and alpha-blended line draws now fade their tint with alpha — a material at `Opacity 0.3` shows 30% of its color over the background. They previously added the tint at full strength while only fading the background, so translucent tints now match the raylib backend.
- **MonoGame (DirectX 12):** lines now render on the DX12 backend. Thin lines, line strips and 3D lines drew as filled shapes or vanished there — the DX12 runtime interprets line topologies as triangles. On that backend 2D lines now draw as thin quads and 3D lines as camera-facing quads, close to the native lines the other backends draw.
- **Templates:** the starter agent files link to the MVU guides at their new locations. The docs reorganization moved Elmish, programs, commands, subscriptions, system, scaling, headless, services, composable systems and background work under the MVU section, and the old flat links in the shipped starters were dead.