con un clic
fs-skia-elmish
Work on Elmish adapter contracts and generated product Elmish wiring.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Work on Elmish adapter contracts and generated product Elmish wiring.
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Consumer-facing guide to hosting an interactive FS.Skia.UI app — the keyboard/pointer input surface, the preview-vs-tree render distinction, and the windowed-fullscreen blur caveat.
Build Skia-rendered FS.Skia.UI Controls, rich text, chart controls, graph controls, DataGrid, custom wrappers, and generated product examples.
Generated product guidance for Skia-rendered FS.Skia.UI Controls, rich text, chart controls, graph controls, DataGrid, and custom wrappers.
Wire a generated FS.Skia.UI product to the desktop viewer host.
Understand and work with the internal keyed VDOM diff over the lowered Control<'msg> IR (feature 067) — its key-first-then-positional matching, the NodePatch/ChildOp operation set, the totality/determinism/identity-at-rest/round-trip invariants, and the module's disposition (internal, property-tested, wired onto the live render path via RetainedRender in feature 091 and current through feature 103 — layout/bounds cache, injected-delta animation clock, visual-state cross-fade). Use when reading the diff invariants, extending the property tests, or working on the wired retained render path.
Maintainer-facing guide to the FS.Skia.UI.Controls.Elmish interactive-host seam — how runInteractiveApp drives the retained render structure each frame (RetainedRender.step over the keyed diff), advances per-identity animation clocks from an injected Tick delta, stamps runtime visual state pre-reconcile, routes keys focus-first through routeFocusedKey, and resolves pointer hits to a stable identity via retainedHitTest. Use when reading or extending the live controls host loop, the per-frame retained-state/clock/visual-state wiring, or the key/pointer routing seam.
| name | fs-skia-elmish |
| description | Work on Elmish adapter contracts and generated product Elmish wiring. |
Owns src/Elmish/, Elmish adapter tests, template/fragments/elmish/, and generated product Elmish entry points.
The supported API lives in src/Elmish/Elmish.fsi. Surface changes require readiness/surface-baselines/FS.Skia.UI.Elmish.txt.
Run ./fake.sh build -t CapabilityCheck, ./fake.sh build -t DependencyReport, and ./fake.sh build -t PackLocal.
Run dotnet test tests/Elmish.Tests/Elmish.Tests.fsproj and ./fake.sh build -t GeneratedProductCheck.
Record transition and effect evidence under the active feature readiness
package-surface reports when adapter behavior changes. Stable public surface
baselines live under readiness/surface-baselines/.
Keep Model, Msg, Effect, init, and update pure. Native viewer I/O belongs to SkiaViewer interpreter code.
Products that select Elmish receive Scene and SkiaViewer prerequisites plus this skill.
Open the package namespace and initialize the adapter over a pure user model:
open FS.Skia.UI.Scene
open FS.Skia.UI.SkiaViewer
open FS.Skia.UI.Elmish
let options = { Title = "elmish"; InitialSize = { Width = 320; Height = 240 } }
let render (count: int) = Text((10.0, 20.0), sprintf "count=%d" count, Colors.white)
let model, _effects = ElmishAdapter.init options 0 (render 0)
let next, _ = ElmishAdapter.update render (UserMsg 1) model
printfn "user model = %d" next.UserModel
Every arcade demo (Asteroids, Breakout, …) re-derives the same deterministic
update-side primitives. Capture them as canonical MVU conventions here rather
than re-implementing them per game. Each is a pure function of the model, so it
lives inside update, never in the interpreter.
Shipped helper: deterministic seeded RNG (FS.Skia.UI.SkillSupport.Random).
As of feature 062 (FR-010), the thrice-re-implemented seeded RNG is shipped real
API — use it instead of ambient System.Random so your update stays pure and
replayable. Thread the opaque RngState through your Model:
open FS.Skia.UI.SkillSupport
// in init: seed once (same seed ⇒ identical replayable stream on any platform)
let model0 = { model with Rng = Random.seedRng 42UL }
// in update: thread the state — no ambient System.Random, no wall-clock
let spawnColumn, rng' = Random.nextBelow boardColumns model.Rng
{ model with Rng = rng' (* … place the entity at spawnColumn … *) }
seedRng/nextRng/nextBelow are pure state -> (value, nextState); carrying
RngState in the model keeps the whole simulation deterministic and replayable
(a prerequisite for deterministic-replay evidence).
The three loop primitives below remain documented conventions, not shipped
FS.Skia.UI API (feature 062 D10/D11 defer them with rationale — not yet at the
3-demo recurrence bar); each documented convention is the spec if a later feature
ships it.
step driver). Decouple simulation
from frame cadence: accumulate real elapsed time and advance the simulation in
fixed 1/120 s steps, capping the steps consumed per tick so a long stall
(debugger pause, GC) can never spiral into hundreds of catch-up steps. Pure in
update; the only input is the elapsed time carried on the tick Msg.
let private dt = 1.0 / 120.0 // fixed simulation step
let private maxStepsPerTick = 5 // cap catch-up after a stall
let stepFixed (advance: Model -> Model) (elapsed: float) (m: Model) : Model =
let acc = m.Accumulator + elapsed
let steps = min maxStepsPerTick (int (acc / dt))
let m' = List.fold (fun s _ -> advance s) m [ 1 .. steps ]
{ m' with Accumulator = acc - float steps * dt }
|Dy| floor. Map the ball's contact offset
from the paddle centre to a horizontal velocity, but clamp |Dy| to a minimum
so the ball can never settle into a purely-horizontal loop:
dy = sign dy * max minDy (abs dy) after the rebound.When a problem outlasts reasonable in-repo attempts, extensive external research is
mandatory — consult official online docs first (the F#/.NET docs and the driven
library's own documentation/API reference), then community sources (forums, Reddit, Q&A
sites, issue trackers and changelogs). Record the findings and resolving links in the
feature's specs/<feature>/feedback/ folder and, for durable lessons, in this skill's
Sources line. Offline, the mandate degrades to recording "research blocked — "
rather than hard-failing the phase.
ViewerModel/ViewerMsg this adapter wraps.SceneNode the render function produces.