Mibo.Raylib 2.0.0-rc-001

This is a prerelease version of Mibo.Raylib.
There is a newer version of this package available.
See the version list below for details.
dotnet add package Mibo.Raylib --version 2.0.0-rc-001
                    
NuGet\Install-Package Mibo.Raylib -Version 2.0.0-rc-001
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Mibo.Raylib" Version="2.0.0-rc-001" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Mibo.Raylib" Version="2.0.0-rc-001" />
                    
Directory.Packages.props
<PackageReference Include="Mibo.Raylib" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Mibo.Raylib --version 2.0.0-rc-001
                    
#r "nuget: Mibo.Raylib, 2.0.0-rc-001"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Mibo.Raylib@2.0.0-rc-001
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Mibo.Raylib&version=2.0.0-rc-001&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Mibo.Raylib&version=2.0.0-rc-001&prerelease
                    
Install as a Cake Tool

Mibo.Raylib

Install the templates:

dotnet new install Mibo.Raylib.Templates
dotnet new mibo-2d -o MyGame
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.Raylib 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.Raylib is a port of my first attempt at this Mibo_monogame micro-framework from MonoGame to raylib-cs, designed to allow F# developers to write games using familiar Elmish 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 via InputMap / 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, AnimatedSprite state machines, and grid-based animation definitions
  • Input Mapper — Listen to raw input and map it to semantic actions

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 developed for the initial Raylib version and the new MonoGame Samples are being stored in its own repository Mibo.Samples is the place to visit.

You'll find examples of

2D::

  • Platformer - A simple platformer featuring lights, normal maps, occluders and particles
    • Sample Mibo.Raylib targeting Desktop OpenGL
    • Sample Mibo.MonoGame targeting Windows Desktop DirectX11
  • Space Battle - A minimalistic hex grid strategy game a'la Wargroove or Advanced Wars
    • Sample Mibo.Raylib targeting Desktop OpenGL
  • Ping Pong - A Small client-server example
    • Mibo.Raylib Client
    • Mibo.MonoGame Client
    • dotnet app acting as a server running Mibo.Core's headless support

3D:

  • Platformer - A simple platformer with 3D models, lights, shadows, particles, and skeletal animation
    • Mibo.Raylib targeting Desktop OpenGL

License

Mibo.Raylib is distributed under the zlib/libpng License.

Built on

Mibo.Raylib is built on top of:

  • raylib — the cross-platform graphics library that powers the rendering, input, and audio layers
  • raylib-cs — the C# bindings that make raylib accessible from .NET

Feedback

Issues and PRs are very welcome. If you're interested in using F# for game development beyond simple 2D games, Mibo.Raylib aims to be a practical, batteries-included framework that scales with your ambition.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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 32 8/19/2026
4.4.0 58 8/18/2026
4.3.0 75 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-001 105 7/2/2026
Loading failed

### Added

- **Core: backend-neutral `Color` type** — a byte RGBA struct (`Mibo.Color`) with `toVector3`/`toVector4` conversions and named constants (`White`, `Black`, `Red`, etc.). Shared light/camera definitions use this instead of a backend-specific `Color`. Each backend provides inlineable `op_Implicit` conversions to/from its native color type.
- **Core: shared 3D light definitions** — `AmbientLight3D`, `DirectionalLight3D`, `PointLight3D`, and `SpotLight3D` (with their builder modules) now live in `Mibo.Core` using `Mibo.Color` + `System.Numerics.Vector3`. Both backends previously carried byte-for-byte identical copies; now there is one implementation.
- **Core: shared `Animation3DState` playback clock** — the pure state machine (`create`, `play`, `blendTo`, `update`, etc.) and `Animation3DClipsInfo` (clip names + keyframe counts) now live in `Mibo.Core`. The clock operates on ints/floats only — no backend types. Each backend builds `Animation3DClipsInfo` at load time from its native clip data and delegates playback to the Core functions.
- **Core: mouse capture** — `IInput.SetMouseCapture(MouseCapture)` lets games request pointer-locked, unlimited-rotation mouse input via a backend-neutral contract. Raylib uses native `DisableCursor`/`EnableCursor`; MonoGame re-centers the mouse inside its own `Poll()` so no external `GameComponent` is needed.

### Changed

- **Core — Breaking:** `AmbientLight3D.Color`, `DirectionalLight3D.Color`, `PointLight3D.Color`, and `SpotLight3D.Color` are now `Mibo.Color` (were `Raylib_cs.Color` / `Microsoft.Xna.Framework.Color`). Use `Mibo.Color.White` etc. when constructing lights, or rely on the implicit conversion from your backend's native color. Light `Direction`/`Position` fields are now `System.Numerics.Vector3` (were native on the MonoGame backend).
- **Core — Breaking:** `Animation3DClips` gains a `ClipsInfo: Animation3DClipsInfo` field. The `Animation3DState` playback functions (`create`/`play`/`blendTo`/`update`/etc.) on both backends now delegate to the Core implementation. The public API is unchanged, but the struct field layout of the backend-specific `Animation3DState` types is internal — construct states via the module functions.
- **Core:** `Animation3DState.update` blend target wrapping now respects `Loop = false` consistently across both backends (previously raylib always wrapped the blend target regardless of the loop flag).
- **MonoGame: device-level config callback** — `MonoGameProgram` wraps a Core `Program` and carries `(Game * GraphicsDeviceManager -> unit)` callbacks (`ofProgram` + `withConfig`) that `MiboGame` runs in its constructor, after the Core `GameConfig` but before `Initialize` / `GraphicsDevice` creation. Use this for `GraphicsProfile`, vsync (`SynchronizeWithVerticalRetrace`), `IsFullScreen`, `Window.AllowUserResizing`, `Content.RootDirectory`, and other properties that need direct device-manager access. `MiboGame` now takes a `MonoGameProgram` instead of a raw `Program`. `MonoGameProgram.withInputMapper` now operates on the wrapper.
- **MonoGame: host & program** — `MiboGame(program)` is the MonoGame game host (subclasses `Microsoft.Xna.Framework.Game`, drives the shared `ElmishLoop`). `MonoGameProgram.withInputMapper` registers the MonoGame-backed input mapper (and calls `withInput`). `MonoGameGameContext` accessors (`getGraphicsDevice`/`getContentManager`/`getGame`) retrieve MonoGame handles from the Core `GameContext` service registry. MonoGame `IAssets` exposes the typed loaders (`Texture`/`Font`/`Sound`/`Model`/`Effect`/`ModelAnimations`/`AnimatedMesh`) and extends the portable `IAssetCache`.
- **Core: `IAssetCache`** — backend-neutral asset cache interface (`Get`/`Create`/`GetOrCreate`/`Clear`/`Dispose`) that portable code depends on; the backend `IAssets` extends it.
- **Docs: migration guide** — `docs/migration-from-monogame.md`, a before/after guide for moving from the original monolithic `Mibo` package to `Mibo.Core` + `Mibo.MonoGame` (program setup, GameContext, input, assets, the renamed 2D/3D rendering stacks, animation, cameras, the content pipeline, and a Raylib-backend appendix).
- **Docs: shader uniform reference** — `docs/shader-uniforms.md` lists the exact uniform names the 3D `beginEffect`/`endEffect` scope uploads (matrices, lights, shadows, material, bones, `time`), the `drawMeshEffect` and `drawImmediate` contracts, and the 2D lit-sprite layout, so a custom shader can declare just what it consumes. Worked HLSL + GLSL examples included.
- **MonoGame 3D: per-group custom shading** — `Draw3D.beginEffect`/`endEffect` shade the draws between them with a user-supplied `Effect` instead of PBR. The effect inherits the scene's camera, lights, shadows, material, bones, and a `time` clock **by declaring the matching uniform names**; uniforms it doesn't declare are skipped. Scopes don't persist across cameras. Lets you render toon/water/vignette alongside the default PBR scene.
- **MonoGame 3D: extensible pipeline** — `ForwardPipelineBase` (abstract; owns the gather + frame orchestration + a virtual `Shade`) with `ForwardPipeline` as the thin PBR subclass. Override `Shade` to plug a different shading strategy; it receives the per-frame scene (lights, bones, shadow output, `time`). Register the same way: `Renderer3D.create (ForwardPipeline()) view`.
- **MonoGame 3D: `drawImmediate` receives a `SceneContext`** — the raw `GraphicsDevice` plus the gathered scene (camera, lights, shadows, `time`). For fully-custom draws (water/refraction, screen-space, multi-pass) that want device control without re-gathering the scene.
- **Raylib 3D: per-group custom shading** — `Draw3D.beginEffect`/`endEffect` shade the draws between them with a user-supplied `Shader` instead of PBR. The shader inherits the scene's camera, lights, shadows, material, bones, and a `time` clock **by declaring the matching uniform names**; uniforms it doesn't declare are skipped. Scopes don't persist across cameras. Lets you render toon/water/vignette alongside the default PBR scene.- **Raylib 3D: extensible pipeline** — `ForwardPipelineBase` (abstract; owns the gather + frame orchestration + a virtual `Shade`) with `ForwardPbrPipeline` as the thin PBR subclass. Override `Shade` to plug a different shading strategy; it receives the per-frame scene (lights, shadow output, `time`). Register the same way: `Renderer3D.create (ForwardPbrPipeline()) view`.
- **Raylib 3D: `drawImmediate` receives a `SceneContext`** — the gathered scene (camera, view/projection matrices, lights, shadows, `time`). For fully-custom draws (water/refraction, screen-space, multi-pass) that want the scene data without re-gathering it. Mirrors the MonoGame `SceneContext` minus the device field (raylib uses global device state).
- **Raylib 3D: `time` uniform** in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaring `time`. `IRenderPipeline3D.Execute` gains a `GameTime` argument.
- **MonoGame 3D: `time` uniform** in the scene-data contract. Shaders opt into animation (ripples, flowing textures) by declaring `time`. `IRenderPipeline3D.Execute` gains a `GameTime` argument (MonoGame backend only).
- **MonoGame 3D: PBR shading** — models, animated models, primitives, and instanced geometry route through a Cook-Torrance PBR effect (ambient + 1 directional + up to 8 point + up to 4 spot lights, emission, opacity, tiling, optional normal maps). Imported models keep their authored look; a `MaterialKey` short-circuit skips re-uploading unchanged materials. Per-draw `normalMatrix`; instanced normals transform by the per-instance world matrix; the instanced shader negates the directional light direction.
- **MonoGame 3D: shadows** — directional, point, and spot lights that set `CastsShadows` render depth into an `R32F` atlas (sampled with 3×3 PCF; OpenGL uses `RasterizerState` polygon-offset + a `shadowTexelSize` uniform since SM3.0 has no `dFdx`/`textureSize`). Per-light frustum culling skips casters outside each light's view (accounting for transform scale). Static models, primitives, instanced geometry, and animated models all cast; animated models render depth-only with matching bone semantics (not frustum-culled — a bare mesh part has no reachable bounds). A per-light shadow index replaces the per-fragment caster scan. Configure via `ShadowAtlasConfig`/`ShadowBiasConfig`; `EnableShadows`/`DisableShadows`/`SetShadowOrigin` are honored. Only the first shadow-casting directional light is registered (the shader samples slot 0).
- **MonoGame 3D: skeletal animation** — `AnimatedModel` plays/blends animation clips loaded at runtime from raw model files (`.glb`/`.gltf`/`.fbx`/…) via AssimpNetter (the content pipeline discards animation data; loading both `ModelAnimations` + `AnimatedMesh` for the same path parses once). `Draw3D.drawAnimatedModel` computes the bone palette and routes through GPU skinning; the caller never handles a `Matrix[]`. Cross-fade blend targets respect `Loop = false`. Load via `IAssets.ModelAnimations`/`AnimatedMesh` (filesystem paths — copy the raw model to your output directory). Adds the `AssimpNetter` dependency.
- **MonoGame 3D: instancing** — `Draw3D.drawInstanced` renders bulk geometry via hardware instancing (dual vertex stream) through the PBR `Instanced` technique.
- **MonoGame 3D: billboards + lines** — `Draw3D.drawBillboard`/`drawBillboardBatch`/`drawLine3D` (billboard UVs normalized `[0,1]`; line staging pooled).
- **MonoGame 3D core** — `Camera3D` (perspective/orthographic, orbit, screen-point-to-ray), `Culling`, `Primitive3D` (unit cube/sphere/cylinder/plane/torus/cone meshes), `Material3D`, the `Draw3D` DSL, and a pluggable `IRenderPipeline3D`. `EndCamera` resets camera state so draws after it don't use stale matrices.
- **MonoGame: 2D rendering stack** — sprites, text, shapes, cameras, custom shaders, render targets, 2D lighting (point/directional/occluders), particles, post-processing, and sprite-sheet animation. Parity with the Raylib `Graphics2D` surface. Includes: mouse back/forward buttons on the `MouseDelta` stream; `Renderer2D.Draw` always closes batches and releases RTs even when a frame throws; per-instance lit-sprite quad buffer; centroid-radiating rounded-rect fill; `AddTriangleFan` `closeLoop` for open fans; `LightContext2D.Dispose` respects caller effect ownership; float-space particle removal; allocation-free occluder upload; multi-pass post-process; `RenderTargetPool` idle-target cap (window-resize leak).
- **Core: backend-neutral input** — `KeyCode`/`MouseButtonCode`/`GamepadButtonCode`/`GestureKind` + `IInput`/`IInputMapper<'Action>` live in `Mibo.Core`, so input bindings are portable across backends.
- **Core: `Cmd.Msg`** — a zero-allocation `Cmd` case for `Cmd.ofMsg` (no delegate wrap).
- **Core: `Program` builder** gains `withServiceRegistration` for backend-specific service registration.
- **Core: `Mibo.Core` project** — backend-agnostic home for `Cmd`/`Sub`/`GameTime`/`Program`/`GameContext`/layout/`HeadlessProgram`/`ElmishLoop`. The Raylib backend now references it; namespaces are unchanged. Includes `Mibo.Core.Tests`.
- **Raylib: `RaylibProgram.withInputMapper`** — the raylib-specific input-mapper builder (decoupled from the shared Core `Program`).
- **Raylib / MonoGame 3D:** `Draw3D.modelWith` and `modelWithPerMesh` draw a model with your own `Material3D` — the whole model, or per sub-mesh — instead of the material baked into the file. One call covers any override shape, so you don't reach for a different API per property. MonoGame also gains `animatedModelWith` / `animatedModelWithPerMesh` for skinned models.
- **Docs:** multi-backend documentation. The site now covers the Core, Raylib, and MonoGame packages: the rendering, shaders, assets, input, and lighting pages show both backends side-by-side where their APIs diverge (the pipeline types, GLSL vs HLSL effects, loose-file vs content-pipeline assets, and viewport coordinate conventions). The original raylib-only docs are preserved as a frozen archive for the prior release.
- **Raylib 3D — Breaking:** `IRenderPipeline3D.Execute` gains a `GameTime` argument (surfaced to shaders as the `time` uniform and passed to `drawImmediate` callbacks). Custom raylib pipelines must add the parameter. Matches the MonoGame backend.
- **Raylib 3D — Breaking (behavioral):** `Draw3D.drawImmediate` callback changed from `unit -> unit` to `SceneContext -> unit`. The callback now receives the frame's gathered scene (camera, view/projection, lights, shadows, `time`) instead of no data.
- **Raylib — Breaking:** `Mibo.Elmish.Camera` is now a `[<Struct>]` (was a reference record). It flows through the view function every frame, so stack-allocating it removes per-frame Gen0 pressure. Code that held it by reference or relied on reference-identity semantics needs review.
- **Raylib:** 3D point/spot shadow lookup is now an O(N) indexed read instead of an O(N·M) per-fragment caster scan (no visual change; faster with many shadow-casting lights). Only the first shadow-casting directional light is registered.
- **Core — Breaking:** `Cmd<'Msg>` has a new `Msg of 'Msg` case. Exhaustive pattern matches must handle it (or use a wildcard). `Cmd.ofMsg` returns `Msg` instead of wrapping in an `Effect`.
- **Core — Breaking:** input uses backend-neutral codes instead of raylib enums — `InputMap.key` takes `KeyCode` (not `Raylib_cs.KeyboardKey`), `InputMap.mouse` takes `MouseButtonCode` (not `int`), and `Trigger.MouseBut`/`GamepadBut` became `MouseButton`/`GamepadButton`. Bindings are now portable.
- **Raylib — Breaking:** `Program.withInputMapper` moved to `RaylibProgram.withInputMapper` (raylib backend only). Call sites change `Program.withInputMapper map` → `RaylibProgram.withInputMapper map`.
- **Core — Breaking (behavioral):** multiple renderers now draw in the order you add them (previously the last-added drew first). Review your setup if you stack renderers.

### Fixed

- **Core:** `Cmd.batch` no longer silently drops a lone `NowAndDeferNextFrame` effect.
- **Core:** `HeadlessRunner.StepUntil` off-by-one fixed (the predicate is now tested after each step; the loop exits immediately when met).
- **Raylib:** `pollMouse` filters `Unknown` button codes; `InputMapper` binds the raylib key once per trigger (was three times).
- **Raylib 3D:** textures and model materials now load with mipmaps and trilinear filtering. Loaded surfaces previously rendered with point filtering, so 3D models looked flat and matte compared to other backends.
- **Docs:** the MonoGame migration guide no longer claims the backend ships without renderers — it now documents the full default pipeline and 2D/3D stacks that are available.

### Removed

- **Raylib:** 11 stale duplicate test files from `Mibo.Raylib.Tests` (leftovers from the `Mibo.Core.Tests` extraction; never compiled).