بنقرة واحدة
fs-skia-elmish
Work on Elmish adapter contracts and generated product Elmish wiring.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Work on Elmish adapter contracts and generated product Elmish wiring.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
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.
استنادا إلى تصنيف SOC المهني
| 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.