ワンクリックで
fs-skia-scene
Work on dependency-light scene primitives and generated product scene usage.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Work on dependency-light scene primitives and generated product scene usage.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
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-scene |
| description | Work on dependency-light scene primitives and generated product scene usage. |
Owns src/Scene/, Scene package tests, template/fragments/scene/, and generated product code that builds pure scene descriptions.
The supported API lives in src/Scene/Scene.fsi. Surface changes require readiness/surface-baselines/FS.Skia.UI.Scene.txt and package-surface evidence.
Run ./fake.sh build -t CapabilityCheck, ./fake.sh build -t PackageSurfaceCheck, and ./fake.sh build -t PackLocal when this capability changes.
Run dotnet test tests/Scene.Tests/Scene.Tests.fsproj and ./fake.sh build -t GeneratedProductCheck.
Update the active feature readiness package-surface and capability-catalog
reports for contract or catalog changes. Stable public surface baselines live
under readiness/surface-baselines/.
Scene must not reference Elmish, Silk.NET, SkiaSharp, Yoga.Net, or YamlDotNet. Keep host, input, layout, and widget concerns outside this package; use fs-skia-ui-widgets for control, chart, and graph authoring.
Scene is included in every app, governed, headless scene, and sample-pack product as the base capability.
Open the package namespace and build a small pure scene description:
open FS.Skia.UI.Scene
let scene =
Scene.group
[ Scene.filledRectangle { X = 0.0; Y = 0.0; Width = 320.0; Height = 240.0 } (Colors.rgb 16uy 16uy 24uy)
Scene.circle { X = 160.0; Y = 120.0 } 48.0 (Colors.rgb 220uy 60uy 60uy)
Scene.textAt { X = 12.0; Y = 24.0 } "HUD" Colors.white ]
let kinds = Scene.describe scene
let evidence = Scene.renderReadbackEvidence { Width = 320; Height = 240 } scene
printfn "%A %s" kinds evidence.DeterministicHash
The interactive host renderer and the image-evidence (screenshot) renderer are the
same shared painter (SceneRenderer.paintNode inside FS.Skia.UI.SkiaViewer,
feature 063). Its match over SceneNode is exhaustive — there is no wildcard
fallback — so every modeled primitive (Line, Path, Arc, Points, Vertices,
Ellipse/FilledEllipse, Image, RegionNode, Chart, and real-glyph
Text/TextRun) renders to actual pixels through both paths, and a new SceneNode
case is a compile error until both paths handle it. There is no longer an
evidence-mode placeholder rectangle that any primitive collapses onto.
Because of that, treat the two kinds of check as distinct:
Scene.describe and node-count assertions are structural — they prove a node of
a given kind is present in the description, not that it painted visible pixels.Do not let a structural check stand in for visual proof: a scene that describe
reports as a Line is only visibly rendered when the image shows pixels along that
line. (Before feature 063 a Line-only scene drew a single placeholder block, so a
node-count "scene is visible" check passed on an effectively invisible image — that
false-positive is gone now that there is no placeholder.)
X/Y/Width/Height. F# resolves a
record literal { X = …; Y = … } to the most-recently-declared record type
carrying those labels, so if your own game model declares a record with the same
labels (a common { X: float; Y: float } position type), a bare literal can
silently infer to the wrong type — or fail with a confusing inference error.
Remedy: annotate the literal (({ X = 0.0; Y = 0.0 }: Position)), give your
own positional record distinct labels, or qualify the field. Plan your record
label names against the Scene labels before you start designing the model — see
docs/scaffold-map.md for the durable-vs-replaceable map this feeds into.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.