- TargetFrameworks net48;net40. net48 keeps x64 + ViGEm + System.IO.Ports
package; net40 adds Microsoft.Bcl.Async + System.ValueTuple and uses the
in-box SerialPort.
- Compat/TaskCompat bridges Task.Run/Delay/WhenAny/WhenAll (TaskEx on
net40) and SemaphoreSlim.WaitAsync (net40 blocks briefly - trivial at
9600 baud).
- IReadOnlyList/IReadOnlyDictionary -> IList/IDictionary throughout
(net40 predates the IReadOnly* interfaces and the Bcl backport cannot
make arrays implement them).
- HashCode.Combine replaced with a manual combine (Bcl.HashCode has no
net40 build); Marshal.SizeOf<T> -> typeof form; ViGEmJoystickSink
gated #if !NET40. HidFeederJoystickSink stays on both flavors - it
will drive RioGamepadXP.sys on XP via the same contract.
Both TFMs build; 275 tests green on net48.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The interactive replacement for the legacy Sheet -> GIMP/Script-Fu pipeline:
WallpaperMakerForm (tray -> "Wallpaper maker") renders the profile wallpaper
live via SkiaOverlayRenderer, outlines all 119 template cells, and lets any
cell -- including the heading/banner cells the button editor cannot reach --
be clicked and retitled with debounced re-render. Clicks on stacked cells
cycle through the regions at that pixel (OverlayHitTester, unit-tested);
stacking is legitimate chroma-split display encoding. Imports a legacy .data
sheet row (with a game picker for multi-row sheets), exports the PNG, and can
apply the desktop wallpaper immediately to the same per-profile path the
runtime uses. Prompts for and remembers AppConfig.OverlayTemplatePath on
first use. PLAN.md: record this + the completed Phase 6 deploy package.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>