FS.GG.UI.Elmish
0.27.0
Prefix Reserved
dotnet add package FS.GG.UI.Elmish --version 0.27.0
NuGet\Install-Package FS.GG.UI.Elmish -Version 0.27.0
<PackageReference Include="FS.GG.UI.Elmish" Version="0.27.0" />
<PackageVersion Include="FS.GG.UI.Elmish" Version="0.27.0" />
<PackageReference Include="FS.GG.UI.Elmish" />
paket add FS.GG.UI.Elmish --version 0.27.0
#r "nuget: FS.GG.UI.Elmish, 0.27.0"
#:package FS.GG.UI.Elmish@0.27.0
#addin nuget:?package=FS.GG.UI.Elmish&version=0.27.0
#tool nuget:?package=FS.GG.UI.Elmish&version=0.27.0
FS.GG.UI.Elmish
Elmish adapter contracts for FS.GG.UI V3 products.
FS.GG.UI.Elmish is one of the FS.GG.UI distribution packages — an F# / Elmish UI and 2D
scene-graph framework for .NET 10 desktop, rendered through Vulkan + SkiaSharp.
Which adapter?
FS.GG.UI.Elmishis the pure scene adapter (ElmishAdapter): yourrenderprojects the model to aSceneNode, andinit/updatestay pure, returning the next model plus effect values interpreted at the host boundary (it bridges viewer messages and effects into Elmish envelopes overViewer.runInteractiveViewer). For a product built on the semantic control set — buttons, text boxes, grids — use the sibling packageFS.GG.UI.Controls.Elmish(runInteractiveApp), which every FS.GG.UI sample uses. Both are supported; pick by whether your view produces aSceneNodeor aControl<'msg>tree.
Install
dotnet add package FS.GG.UI.Elmish
Or scaffold a full governed project that wires the FS.GG.UI packages together:
dotnet new install FS.GG.UI.Template
dotnet new fs-gg-ui -o MyApp
Usage
The adapter wraps your own Elmish model/msg together with the viewer. It is a viewer
bridge, not your MVU runtime: a ViewerMsg advances the viewer and rebuilds the scene from
the current user model, while a UserMsg is a pass-through — it forwards your message as a
DispatchUser effect and leaves the model and scene unchanged. You supply a render function
that projects your model to a SceneNode; the adapter re-renders it on a ViewerMsg, and your
product composes its own update around the adapter (interpret DispatchUser by running your
update, then reflect the next user model back so the following ViewerMsg re-renders it).
open FS.GG.UI.Scene
open FS.GG.UI.SkiaViewer
open FS.GG.UI.Elmish
// Your own Elmish model/msg — and your own pure update (the adapter never folds this).
type Model = { Count: int }
type Msg = Increment
let update (msg: Msg) (model: Model) : Model =
match msg with
| Increment -> { model with Count = model.Count + 1 }
// Project the user model into a scene
let render (model: Model) : SceneNode =
Text((20.0, 40.0), $"Count: {model.Count}", Colors.black)
let options = { Title = "Counter"; InitialSize = { Width = 640; Height = 480 } }
// Initialise the combined adapter model + initial effects
let initial, startupEffects =
ElmishAdapter.init options { Count = 0 } (render { Count = 0 })
// Pass a user message through the adapter. `UserMsg` is a pass-through: it yields a
// `DispatchUser` effect and leaves `passthrough.UserModel`/scene unchanged (the scene is
// rebuilt via `render` only on a `ViewerMsg`).
let passthrough, effects =
ElmishAdapter.update render (UserMsg Increment) initial
// Compose YOUR update around the adapter: interpret the `DispatchUser` effect by folding
// your own `update`, then reflect the next user model back so the following `ViewerMsg`
// re-renders the scene from it.
let folded =
match effects with
| [ DispatchUser m ] ->
let userModel' = update m passthrough.UserModel
{ passthrough with UserModel = userModel'; Scene = render userModel' }
| _ -> passthrough
API at a glance
ElmishAdapter.init— builds the combinedElmishAdapterModel<'model>fromViewerOptions, your initial user model, and an initialSceneNode, returning the model and its startup effects.ElmishAdapter.update— advances the adapter on anElmishAdapterMsg<'msg>: aViewerMsgsteps the viewer and refreshes the scene viarender, while aUserMsgis forwarded verbatim as aDispatchUsereffect — your user model is not folded here, so compose your ownupdatearound the adapter. Yields the next model plus effects.ElmishAdapterModel<'model>— the bridged state record holding yourUserModel, the currentScene(aSceneNode), and theViewerModel.ElmishAdapterMsg<'msg>— message envelope:UserMsgcarries your own messages,ViewerMsgcarries viewer messages.ElmishAdapterEffect<'msg>— effect envelope:DispatchUserfor your messages andDispatchViewerforViewerEffects.TransitionHost.beginTransition— allocates a newer typed generation for an expensive target and returns pure presentation/focus directives for a React host.TransitionHost.update— accepts generation-bound delayed responses, exact post-commit acknowledgements, visibility edges, and controlled/global input observations. Stale work is rejected into the typed ledger.TransitionHost.isPending— identifies the interval in which old-DOM global dispatch and pointer capture must be suppressed while controlled input remains synchronous.
For React hosts, interpret every RequestPresentation in a fresh startTransition, including work
that resumes after await. Dispatch Presented presentation.Token from a layout effect only after
that exact DOM revision commits. Do not transition controlled text or file setters: send their
TransitionHostInput values synchronously. Forward document.visibilityState edges so hidden work
is retained and one resume request converges to the newest generation. The complete host recipe and
typed example live in template/fragments/elmish/README.md.
Versioning
All FS.GG.UI.* libraries share one version and move together. In a generated project a
single <FsGgUiVersion> in Directory.Packages.props pins every package — upgrading is one
edit; see docs/UPGRADING.md. Pre-release versions use a -preview.N suffix.
Links
- Repository & issues: https://github.com/FS-Skia-UI/FS-Skia-UI
- License: MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Fable.Elmish (>= 5.0.2)
- FS.GG.Audio.Core (>= 0.5.0)
- FS.GG.UI.Scene (>= 0.27.0)
- FS.GG.UI.SkiaViewer (>= 0.27.0)
- FSharp.Core (>= 10.1.302)
- HarfBuzzSharp.NativeAssets.Linux (>= 14.2.1)
- HarfBuzzSharp.NativeAssets.Win32 (>= 14.2.1)
- Silk.NET.GLFW (>= 2.23.0)
- Silk.NET.Input (>= 2.23.0)
- Silk.NET.OpenGL (>= 2.23.0)
- Silk.NET.Windowing (>= 2.23.0)
- Silk.NET.Windowing.Extensions (>= 2.23.0)
- Silk.NET.Windowing.Glfw (>= 2.23.0)
- SkiaSharp (>= 4.150.0)
- SkiaSharp.HarfBuzz (>= 4.150.0)
- SkiaSharp.NativeAssets.Linux (>= 4.150.0)
- SkiaSharp.NativeAssets.Win32 (>= 4.150.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on FS.GG.UI.Elmish:
| Package | Downloads |
|---|---|
|
FS.GG.UI
Optional BOM / metapackage for the FS.GG.UI framework. Reference this single package at one version to pin the entire coherent FS.GG.UI.* set to that version; any attempt to mix a member at a different version fails loudly at restore/build. Ships no assembly — dependencies only. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.27.0 | 0 | 8/22/2026 |
| 0.26.0 | 619 | 8/3/2026 |
| 0.21.1 | 1,181 | 7/26/2026 |
| 0.21.0 | 170 | 7/26/2026 |
| 0.20.0 | 176 | 7/26/2026 |
| 0.19.0 | 312 | 7/23/2026 |
| 0.18.6 | 165 | 7/23/2026 |
| 0.18.5 | 165 | 7/22/2026 |
| 0.18.4 | 144 | 7/22/2026 |
| 0.18.0 | 248 | 7/22/2026 |
| 0.15.0 | 335 | 7/20/2026 |
| 0.14.0 | 175 | 7/19/2026 |
| 0.13.0 | 206 | 7/18/2026 |
| 0.12.0 | 328 | 7/17/2026 |
| 0.11.0 | 379 | 7/16/2026 |
| 0.10.0 | 436 | 7/14/2026 |
| 0.9.2 | 483 | 7/13/2026 |
| 0.9.0 | 581 | 7/11/2026 |
| 0.8.0 | 233 | 7/11/2026 |
| 0.7.0 | 183 | 7/11/2026 |