-
Notifications
You must be signed in to change notification settings - Fork 0
CrossPlatform Roadmap
Companion pages: Technical Index · Architecture Overview · Performance Development Plan · Cross-Platform Implementation Plan · Resources & Bibliography
Important
Snapshot 2026-06-12. Avalonia shell is the canonical UI; WinForms is deprecated and kept
only as a --winforms fallback. The 2026-06-11 snapshot is stale — the GPU-compute,
audio-reactive, Toy-mode, and slideshow-recording branches all landed on main since then and
introduced new Windows-only surface that this snapshot folds in. The full execution path
lives in CrossPlatform-ImplementationPlan.md; this file
is the high-level checklist and gap analysis.
Branch baseline: main (HEAD b8c7312, post-Palette Builder reorg).
Active tracking branch: feature/cross-platform-full (created 2026-06-12 from main).
Goal: ship a runnable FracturingFog binary on win-x64, linux-x64, linux-arm64, osx-arm64, osx-x64.
Non-goal (this doc): mobile, Wasm browser host, touch UI, GPU compute parity on Apple Silicon Metal.
This file is a forward-looking checklist; it does not retell Phase 2 history (see
PHASE2_AVALONIA_MIGRATION.md). It picks up after Phase 2.4 (Silk + Skia backends already
merged, CI matrix green for the platform-neutral assemblies) and lists what still blocks an
end-user launching the full app on a non-Windows host.
-
Abstractions,UI.Avalonia,Rendering.Silk,Rendering.Skiabuild + publish under win-x64 / linux-x64 / osx-arm64 in CI (.github/workflows/cross-platform-build.yml). -
Rendering.Silk.Smokerenders one frame on win/linux/macOS (Linux uses xvfb; macOS uses invisible-window FBO; Windows is direct). - Silk context adapters present: WGL (Win32), GLX (X11), EGL (Wayland), CGL/NSOpenGL (macOS).
- ILGPU
AcceleratorProbeexposes CPU fallback when no CUDA/OpenCL device exists. -
RendererFactory.NonWin32Backendslot lets the bootstrap pick Silk or Skia on non-HWND surfaces. -
Hosting/PngSlideshowFrameRecorder.cs(post-roadmap addition) records slideshow frames via SkiaSharp — proves the Skia encode path is hot in main and reusable for the wider image-save migration. -
PaletteBuilder.Libpalette extraction path is SkiaSharp end-to-end (BitmapSampler,PaletteExtractionService,HostPaletteExtractionService). -
FfmpegEncoder(Imaging/FfmpegEncoder.cs) is already a process-based ffmpeg shell-out with PATH lookup, so the "Phase X.2" video-export-portability work is largely a matter of renamingffmpeg.exelookups and providing RID-keyed binaries.
| # | Blocker | File / artefact | Impact | Status vs prior snapshot |
|---|---|---|---|---|
| B1 | WinExe TFM = net10.0-windows + UseWindowsForms=true
|
FracturingFogCLD.csproj |
Whole exe refuses to build off Windows. | Unchanged. |
| B2 | Legacy MainForm + Views/*.cs still compiled into the WinExe |
MainForm.cs, Views/**, Slideshow.cs, VideoZoom.cs, AudioReactive.cs, SlideshowConfig.cs, ImageCapture.cs
|
WinForms types drag the -windows TFM along with them. |
Unchanged. WinForms shell now has more siblings under root (slideshow/audioreactive root files) — all caught by the same exclude glob in the new App project. |
| B3 | PaletteBuilder.Lib net10.0-windows + PDFsharp-gdi (PDF exporter only) |
PaletteBuilder/PaletteBuilder.Lib.csproj, PaletteBuilder/Services/PdfPaletteExporter.cs
|
Decode + sampling now SkiaSharp; only PdfPaletteExporter still drags GDI through PDFsharp-gdi. Drop or swap to QuestPDF → Lib lands on net10.0. |
Unchanged. SkiaSharp swap landed; PDF swap is the last mile. |
| B4 | WinForms ImagePaletteDialog keeps a System.Drawing.Bitmap for PictureBox display |
Views/ImagePaletteDialog.cs |
Bridges to SKBitmap at the sampler boundary (deprecation-tail dialog). Goes away when WinForms shell is removed; not on the cross-platform critical path. |
Unchanged. |
| B5 | Vortice DX11/12 hard-referenced in WinExe |
FracturingFogCLD.csproj <PackageReference> block |
Brings runtime.win-x64.* natives; ref'd by DX renderer classes that live in the WinExe today. |
Unchanged. |
| B6 | MP4 export via Media Foundation P/Invoke | Imaging/MP4Writer.cs |
mfplat.dll / mfreadwrite.dll are Win-only. |
Partially mitigated: Imaging/FfmpegEncoder.cs already provides a process-based encoder. Need to flip the bootstrap to prefer it on non-Win and add Linux/macOS ffmpeg binaries. |
| B7 |
NativeMouseForwarder HWND subclass (comctl32, user32) |
Hosting/NativeMouseForwarder.cs |
Already guarded by OSPlatform.Windows, but file still lives in the host. |
Unchanged. |
| B8 | Console attach P/Invoke in batch + server entry points |
ServerHost/ServerEntry.cs, Batch/BatchEntry.cs
|
kernel32!AttachConsole/AllocConsole. Cosmetic on non-Windows but currently unguarded. |
Unchanged. |
| B9 |
RuntimeInformation.IsOSPlatform checks scattered ad-hoc |
Hosting/HostHelpContentProvider.cs, MainForm.cs, etc. |
Inconsistent fallbacks; some still throw on non-Win. | Unchanged. |
| B10 |
BenchmarkDotNet pulls kernel32 P/Invokes via Benchmarks/MandelbrotBench.cs
|
Benchmarks/MandelbrotBench.cs |
Dev-only; safe to gate but currently in main project. | Unchanged. |
| B11 |
Tools/ffmpeg.exe copied to output |
FracturingFogCLD.csproj <Tools/ffmpeg.exe>
|
Windows binary in output dir; need RID-keyed copy. | Unchanged. |
| B12 | ILGPU CUDA path assumes NVIDIA driver |
Calculators/*GpuCalculator*.cs, Calculators/UserBulbSandboxGpuCompiler.cs, Rendering/MandelbrotGpuKernel.cs
|
Already falls back to CPU device, but needs verification on Apple Silicon (no OpenCL on macOS 14+, CUDA absent). | Expanded: GPU-compute branch added UserBulbGpuCalculator, UserBulbSandboxGpuCompiler + spike, and Rendering/MandelbrotGpuKernel.cs. All ILGPU; same CUDA/OpenCL/CPU fallback applies. |
| B13 |
NEW. Audio engine uses NAudio Win-only APIs (WaveOutEvent, NAudio.CoreAudioApi WASAPI loopback) |
Audio/AudioEngine.cs, Audio/FractalSynth.cs, Audio/BeatAnalyzer.cs
|
Audio-reactive slideshow path (landed d8f77d2) requires WASAPI loopback for system audio and WaveOutEvent for synth playback. Loopback capture has no cross-platform equivalent without per-OS adapters (PulseAudio/ALSA parec, macOS BlackHole/loopback driver). |
New blocker — was not flagged in 2026-06-11 snapshot because the feature shipped after. |
| B14 | NEW. Avalonia shell has Win-only HWND P/Invoke for Toy-mode drag and inspect-click |
UI.Avalonia/Views/MainWindow.axaml.cs:777-781 (ReleaseCapture, SendMessage), Hosting/AvaloniaShellBootstrap.cs:65 (ClientToScreen) |
Toy-mode (8768f5e) borrowed the WinForms HWND drag trick. Calls will throw DllNotFoundException on Linux/macOS. Avalonia has BeginMoveDrag(PointerPressedEventArgs) — use that instead. |
New blocker — landed after 2026-06-11 snapshot. |
| B15 |
NEW. Engine-side image save/export still uses System.Drawing GDI+ |
Imaging/ImageExport.cs, Imaging/PngSequenceWriter.cs, Imaging/PosterRenderer.cs, Rendering/FractalOverlayCompositor.cs, Models/ColorThemeCsExporter.cs and friends |
These are engine code (not WinForms), referenced by both shells AND headless paths (Batch, Server). System.Drawing.Common 10.x throws on non-Win unless explicit opt-in. Migration target is SkiaSharp (already shipping via Avalonia + Rendering.Skia). PngSlideshowFrameRecorder.cs is a working precedent. |
New blocker — was understated in 2026-06-11 snapshot ("phase X.0 splits this out" line for ImageCapture only). The surface is bigger; calling it out as its own phase. |
| B16 |
NEW. FfmpegInstaller.cs auto-downloads the Windows ffmpeg zip from gyan.dev |
Imaging/FfmpegInstaller.cs |
The "install ffmpeg for me" path the FfmpegSetupDialog uses is Windows-only. Linux/macOS users get directed to apt/brew. Not a blocker — but the dialog and CLI surface need OS-aware copy. |
New cleanup item. |
| B17 |
NEW. Hosting/FfmpegSetupDialog.cs is a WinForms dialog inside the cross-platform Hosting/ folder |
Hosting/FfmpegSetupDialog.cs |
The Hosting/ folder is otherwise UI-framework-neutral; this dialog drags WinForms into the host fragment. Belongs in the Win-only sub-project or rewritten as an Avalonia dialog. | New cleanup item. |
The phases below are the long-pole ordering. Each phase has an exit criterion; the
implementation plan (CrossPlatform-ImplementationPlan.md) breaks them into individual
slices with file lists and commit boundaries.
Goal: introduce a separate cross-platform exe target without breaking the existing Windows WinExe.
- Add
FracturingFog.App(net10.0,WinExeon Win /Exeon other RIDs) as the new cross-platform entry point. References:Abstractions,UI.Avalonia,Rendering.Silk,Rendering.Skia,Server,Client,CalculatorGen,ColorGen. No WinForms, no Vortice, noSystem.Drawing.Common, noPaletteBuilder.Lib(until X.1 finishes). - Move
Hosting/AvaloniaShellBootstrap.cs,Hosting/AvaloniaDialogs.cs,Hosting/HostColorThemeService.cs,Hosting/HostHelpContentProvider.cs,Hosting/ColorThemeDefAdapter.cs,Hosting/HostPaletteExtractionService.cs,Hosting/PngSlideshowFrameRecorder.csintoFracturingFog.App(or into a newFracturingFog.Hostingnet10.0lib both shells reference). LeaveHosting/NativeMouseForwarder.csandHosting/FfmpegSetupDialog.csin a Windows-only fragment. - Pull
Rendering/FractalRenderHost.cs+.Video.cs+ the 13+ calculator types (incl. the newUserBulbGpuCalculator, sandbox compilers,MandelbrotGpuKernel.cs) into a newFracturingFog.Enginenet10.0project. Calculators have no UI deps; the move just severs them fromnet10.0-windows. - Pull
Imaging/(minusMP4Writer.csandFfmpegSetupDialog) intoFracturingFog.Engine. The SkiaSharp swap (Phase X.A) happens inside this project once it lives here. - Pull
Audio/into a newFracturingFog.Audionet10.0project with anIAudioCaptureBackendabstraction (Phase X.B fills in the OS-specific implementations). - Keep
Rendering/DirectXRenderer.cs,DirectX12Renderer.cs,RenderFactory.csin a separateFracturingFog.Rendering.D3Dnet10.0-windowsproject (deferred since Phase 2.1; do it now). KeepImaging/MP4Writer.cshere too. -
FracturingFog.Appreferences DX + MP4Writer only via a Windows-conditionalProjectReference:<ProjectReference Include="..\Rendering.D3D\FracturingFog.Rendering.D3D.csproj" Condition="'$([MSBuild]::IsOSPlatform(`Windows`))' == 'true'" />
- Existing
FracturingFogCLD.csprojstays as the Windows-legacy WinExe (keepsMainForm-
Vortice+PaletteBuilder.Lib) so nothing regresses for current users. Mark itObsoletein the sln description.
-
- sln gains
FracturingFog.App,FracturingFog.Engine,FracturingFog.Audio,FracturingFog.Rendering.D3D, optionalFracturingFog.Hosting.
Exit criteria: dotnet build FracturingFog.App.csproj -r linux-x64 --self-contained false
succeeds in CI without referencing any *-windows TFM project. Existing
FracturingFogCLD.csproj still builds + runs on Windows unchanged.
Goal: strip System.Drawing from the engine + headless paths so the cross-platform host
can save PNG/TIFF/BMP, write PNG sequences, render posters, and composite watermark/grid
overlays.
-
Imaging/ImageExport.cs→ SkiaSharp.Bitmap.LockBitsBGRA copy becomesSKBitmap.InstallPixelsover the sameuint[]. PNG/TIFF/BMP write viaSKImage.Encode. Watermark composition viaSKCanvas.DrawText+ outlineSKPath.Color fontColorsignature swaps toSKColoror a UI-neutral RGB struct. -
Imaging/PngSequenceWriter.cs→ SkiaSharp.Bitmap→SKBitmapsnapshot per frame;Encodeto disk. Stays threaded with the same semaphore gate. Even-dimension crop logic is unchanged. -
Imaging/PosterRenderer.cs→ SkiaSharp. The renderer pullsIColorMap+ calculator output; only the save tail usesBitmaptoday. Swap the tail. Custom watermark composition →SKCanvas. -
Rendering/FractalOverlayCompositor.cs→ SkiaSharp. Used for grid + halo overlays on exported frames. Pixel-loop falls back to SkiaSharp draw calls or a managed BGRA blit. -
Models/ColorThemeCsExporter.csand theModels/ColorSchemes/**files: these useSystem.Drawing.Colorpurely as a struct (ARGB packing). Either swap toSystem.Drawing.Primitives(which IS cross-platform — only GDI+ types throw) or introduce a smallRgba32struct inAbstractions/. Decide once; prefer the latter so the engine has zeroSystem.Drawing.*references. - Audit
ImageFormatenum usage in callers — collapse to a string ext +SKEncodedImageFormatpair at the save site. - Remove
<PackageReference Include="System.Drawing.Common">from any project that ends up in theFracturingFog.Appreference closure.
Exit criteria: FracturingFog.Engine and FracturingFog.App build with NoWarn= empty
under -r linux-x64 --self-contained false, and the headless --batch PNG-sequence + PNG
single-image paths round-trip a render on a Linux CI runner.
Goal: make the audio-reactive slideshow degrade gracefully on non-Windows without ripping the feature out, and support file/synth paths on every RID.
- Introduce
IAudioCaptureBackendinAbstractions/Audio/with the minimum surface theBeatAnalyzerneeds:Start(AudioFormat),Stop(),DataAvailableevent yieldingfloat[]PCM, plus aCapabilitiesenum (SystemLoopback | Microphone | FilePlayback | SynthPlayback). - Split the current
AudioEngineinto a backend-neutral analyzer driver + per-backend source pump. Existing NAudio code becomesWindowsNAudioBackendinside a Win-only fragment. - On Linux/macOS, ship a
NoopAudioBackendthat supports onlyFilePlayback(decoded viaNAudio.CoreMP3/WAV — that path is cross-platform when the WASAPI bits aren't touched) andSynthPlayback(synth analyzer-only, no speaker output). System loopback is marked unsupported; the audio-source picker grays it out with a one-line banner. - Stretch goal:
OpenAlAudioBackend(Silk.NET.OpenAL) for mic + speaker on Linux/macOS. Park behind a follow-up; not a launch blocker. - Audio-reactive sweep settings remain editable; the running sweep simply receives a flat (silent) beat stream on hosts that can't capture.
Exit criteria: opening the audio-reactive slideshow on Linux shows the picker without crashing; choosing "File" plays a local MP3 and drives the beat analyzer; choosing "System loopback" displays "Not supported on this OS" instead of throwing.
Goal: strip Windows-only deps from the palette extraction path so the cross-platform host
can keep IPaletteExtractionService.
Status (2026-06): SkiaSharp swap landed on feature/palette-builder-image-pipeline. The
remaining work is the PDF exporter and the TFM flip.
-
Imaging/PaletteExtraction/BitmapSampler.cs—System.Drawing.*replaced withSkiaSharp(SKBitmap,SKCodec,SKImageInfo,SKEncodedOrigin). Pixel layout forced toSKColorType.Bgra8888. EXIF orientation viaSKCodec.EncodedOrigin. -
PaletteBuilder/Services/PaletteExtractionService.cs—_sources: List<SKBitmap>, decode viaSKCodec.GetPixels. NoSystem.Drawingimports remain. -
Hosting/HostPaletteExtractionService.cs— same SkiaSharp swap; cache-key now covers full filter set + ROI. - File pickers extended:
.webp,.heic,.heif. - Remove
PDFsharp-gdi+System.Drawing.CommonfromPaletteBuilder.Lib.csproj. Currently both survive only to feedPaletteBuilder/Services/PdfPaletteExporter.cs. Options:-
Swap to
QuestPDF(recommended) — cross-platform, MIT-friendly with optional commercial license. RewritePdfPaletteExporteragainstQuestPDF.Fluent. Honour the existingPdfExportOptions(page size, columns, cover page, CVD rows, etc.). - Drop PDF export from the cross-platform host and keep it in the Windows WinExe wrapper.
-
Swap to
- Once
PDFsharp-gdiis gone, flipPaletteBuilder/PaletteBuilder.Lib.csprojTFM fromnet10.0-windows→net10.0. VerifyPaletteBuilder/PaletteBuilder.csproj(WinExe wrapper) andFracturingFogCLD.csproj(Windows host) still resolve the Lib via TFM downcompat. - Optional split:
PaletteBuilder.Engine(extractors + BitmapSampler + stop builder) carved out from the UI shell soFracturingFog.Appreferences only the engine. - Once the engine is portable, retire the
GdiToSkiabridge inViews/ImagePaletteDialog.cs(deletes with the WinForms shell — same gate as the broader WinForms deprecation tail).
Exit criteria: From Image… palette flow round-trips an input PNG → ColorStopDef list on
Linux + macOS in a manual smoke. PaletteBuilder.Lib TFM is net10.0 and dotnet build
succeeds on linux-x64.
Goal: MP4 writer either works on every RID or fails gracefully.
- Introduce
IVideoWriterinAbstractions/Imaging/. - Keep current
MP4Writer(Media Foundation P/Invoke) asWin32MP4Writerin the Windows fragment. -
Imaging/FfmpegEncoder.csalready exists and shells out to ffmpeg viaSystem.Diagnostics.Process. Wrap it in anIVideoWriteradapter —FfmpegVideoWriter— and make it the default on Linux/macOS (and the Windows default if ffmpeg is present).- Detect bundled
Tools/<rid>/ffmpeg(orffmpeg.exeon Win) first, else fall through toPATH. Rename the existingFindFfmpeg()to look for bothffmpegandffmpeg.exe. - On Linux: ship
Tools/linux-x64/ffmpeg+Tools/linux-arm64/ffmpeg; RID-keyed<None Include>blocks. - On macOS: rely on PATH (
brew install ffmpeg) or bundle a notarized binary.
- Detect bundled
-
FfmpegInstaller.csbecomes OS-aware: Windows downloads the gyan.dev zip as today; Linux/macOS surface a "Install via your package manager" instruction with copy-paste commands (apt install ffmpeg/brew install ffmpeg). - Bootstrap picks
Win32MP4Writeron Windows when MF resolves, elseFfmpegVideoWriter. Video tab disables itself with a one-line banner when no writer resolves. -
Hosting/FfmpegSetupDialog.csrewritten as an Avalonia dialog (or split: Win-only WinForms version stays in the legacy WinExe; Avalonia version added toUI.Avalonia/).
Exit criteria: a 100-frame slideshow export succeeds on Linux via bundled (or PATH) ffmpeg.
- Audit every
[DllImport]outsideRendering.D3DandRendering.Silk/Platform. Wrap the call site inif (OperatingSystem.IsWindows()) …and provide a no-op or alternative on non-Win.-
ServerHost/ServerEntry.csAttachConsole/AllocConsole→ no-op on Linux (stdout/stderr already inherited). -
Batch/BatchEntry.csditto. -
Benchmarks/MandelbrotBench.cs— gate or move under#if WINDOWS. -
Hosting/NativeMouseForwarder.csalready gated; move file into the Windows-only host fragment so non-Win builds don't even compile it. -
NEW:
UI.Avalonia/Views/MainWindow.axaml.csToy-mode HWND drag — replaceReleaseCapture+WM_NCLBUTTONDOWNwith Avalonia'sBeginMoveDrag(PointerPressedEventArgs). No[DllImport]left after the rewrite. (Catches the crash on Linux/macOS Toy-mode drag.) -
NEW:
Hosting/AvaloniaShellBootstrap.csClientToScreen— gate behindOperatingSystem.IsWindows(); on non-Win, use Avalonia'sControl.PointToScreenfor the inspect-click coordinate.
-
- Sweep
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)and switch toOperatingSystem.IsWindows()(compile-time analyzable, plays nice with trimming). - Add
[SupportedOSPlatform("windows")]attributes to genuinely-Windows-only types so the analyzer (CA1416) catches drift.
Exit criteria: dotnet build on Linux emits zero CA1416 warnings from
FracturingFog.App, Engine, Hosting, UI.Avalonia, Audio.
-
AvaloniaShellBootstrapstatic ctor: on non-Windows, registerNonWin32Backend = Silkby default with Skia as the documented fallback (--renderer skiaCLI flag). On Windows, keep DX as the default and let--renderer silk/--renderer skiaoverride for parity testing. - Verify
IGpuSurface.Kindcovers Win32Hwnd, X11Window, WaylandSurface, CAMetalLayer/NSView, with bootstrap diagnostics that name the missing adapter when init fails. - Settle the macOS adapter: the current
SilkCglContextAdapterrequests a 3.2 core profile token (macOS caps; 4.1 in practice). Confirm the Silk fragment shader still compiles (#version 330 coreworks under that token). - Wayland: the EGL adapter is in but the Linux CI leg still runs the smoke under xvfb
(X11/GLX). Add a parallel
linux-waylandsmoke that runs the EGL path underweston --backend=headless.
Exit criteria: Avalonia shell paints a fractal on:
- Win10/11 x64 (DX)
- Win10/11 x64 with
--renderer silk(WGL) - Ubuntu 22.04 x64 + X11 (GLX)
- Ubuntu 22.04 x64 + Wayland (EGL)
- macOS 14 arm64 (CGL)
- Fedora 39 x64 with
--renderer skia(no GL driver case)
- On Apple Silicon, ILGPU has neither CUDA nor OpenCL. Confirm
UserBulbGpuCalculator, the newUserBulbSandboxGpuCompiler, andRendering/MandelbrotGpuKernel.csall fall through to the managed CPU device cleanly; add a smoke test asserting the chosen device kind on each RID. - Document that AVX2/AVX-512 lanes are x64-only at runtime; on osx-arm64 / linux-arm64 the
scalar path runs. The calculator gating (
Avx2.IsSupported && Fma.IsSupported) already handles this — publish the expectation in user-facing docs (Help → Hardware tab). - Out of scope for this roadmap: ARM64 NEON SIMD lane in
CalculatorGen. File asCalculatorGen-Roadmap.mdfollow-up.
- Define publish profiles (
Properties/PublishProfiles/*.pubxml) for:win-x64,linux-x64,linux-arm64,osx-arm64,osx-x64. All--self-contained true,PublishSingleFile=true,IncludeNativeLibrariesForSelfExtract=true. - Linux: produce both a tarball and a
.AppImage(useappimagetool). Optional Flatpak manifest as a follow-up. - macOS: produce
.appbundle viadotnet publish+ customInfo.plist. Code-signing- notarization needs an Apple Developer cert — defer until binary verified.
- Windows: keep the existing MSIX/zip flow (no change required since the legacy WinExe still ships).
- CI: extend
cross-platform-build.ymlto publish + upload artifacts on tag pushes.
- Update
FEATURES.mdwith platform matrix table. - Add a
Help → Hardwaretab section listing detected backend (DX / Silk / Skia), SIMD width, ILGPU device list, audio backend — most of this exists, verify labels match new selection logic. -
README.md: install instructions per OS. -
Docs/User/CrossPlatform-UserGuide.md(new): known limitations per OS — Wayland + NVIDIA proprietary driver caveats, macOS notarization status, Linux video export ffmpeg requirement, audio-reactive loopback gap.
| Risk | Likelihood | Mitigation |
|---|---|---|
| Vortice DX leaks into Engine via implicit ref | Med | Audit Engine.csproj's transitive deps; add CI assertion that Engine.dll has no runtime.win-* natives in its publish folder. |
System.Drawing.Common 8+ throws on non-Win unless explicit opt-in |
High | Phase X.A removes it entirely from the engine surface; do not opt in via runtimeconfig. |
| SkiaSharp watermark text differs visually from GDI+ output on existing posters | Med | A/B render a fixed test poster pre- and post-swap; allow ±2 px metric drift but no missing glyphs. Pin SkiaSharp font fallback to Inter (already bundled via Avalonia). |
| NAudio cross-platform claim doesn't survive WASAPI loopback removal | High | Audit which NAudio assemblies actually load on Linux at runtime; design the IAudioCaptureBackend so the WASAPI path is gated behind OperatingSystem.IsWindows() and never reached on other RIDs. |
| Avalonia 11.3.x XAML compiler regression on macOS arm64 | Low | Pin Avalonia version; CI runs dotnet publish per RID and exercises one window-open smoke per OS. |
| Silk.NET GL ctx flakes on hybrid GPU laptops (Linux) | Med | Bootstrap falls back to Skia CPU renderer with a banner; document --renderer skia escape hatch. |
| ILGPU CPU device perf cliff vs CUDA path | Low | Calculator already exposes scalar/AVX2/AVX-512 lanes; CPU device path is for parity, not perf parity. |
| ffmpeg licensing on bundled Linux binary | Med | Ship system-ffmpeg lookup first; only bundle if licensing audit clears. |
| Avalonia BeginMoveDrag on Linux/Wayland tied to seat focus loss bugs (compositor-specific) | Low | Acceptable degradation: if BeginMoveDrag throws, swallow and log; Toy-mode loses drag on broken compositors but doesn't crash. |
A user on a fresh Ubuntu 22.04, Fedora 39, macOS 14 arm64, and Windows 11 x64 install can:
- Download a single self-contained archive for their OS.
- Launch
FracturingFog(nodotnet runtimeinstall required). - See an interactive Mandelbrot render within 5 seconds.
- Pan/zoom, switch fractal type, switch colour theme, export PNG.
- Export an MP4 zoom video (Win + Linux must; macOS allowed to defer if ffmpeg notarisation slips).
- Open the audio-reactive slideshow dialog without crashing. System-loopback option is greyed out on Linux/macOS with a banner; file-playback and synth options work everywhere.
Anything beyond that (deep-zoom perturbation parity, GPU path on Apple Silicon, perfect HiDPI on every Linux compositor, OpenAL system-audio capture) is follow-up, not launch.