Home / Docs / Platform entry points
Your App class is shared. Each platform adds one small file
that constructs it and hands it to a runner. That is the entire platform surface of a typical
application — six files, none longer than a screen.
WindowsApp.Run and its siblings create the window or surface,
bring up the graphics backend, call
DeviceServices.Initialize with that platform's service
implementations, and finish by invoking BaseApp.Init —
which is what eventually calls your Create. Your code never
constructs a device service and never touches a swap chain.
| Namespace | Runner | Backend |
|---|---|---|
Season.Platforms.Windows | WindowsApp.Run(BaseApp) | Direct3D 12 |
Season.Platforms.Linux | LinuxApp.Run(BaseApp) | Vulkan, on SDL |
Season.Platforms.Android | AndroidApp.Run(BaseApp) | Vulkan |
Season.Platforms.iOS | iOSApp.Run(BaseApp) | Metal |
Season.Platforms.MacCatalyst | MacCatalystApp.Run(BaseApp) | Metal |
Season.Platforms.Web | WebApp.Run(...), awaitable | WebGPU |
Windows — Platforms/Windows/App.xaml.cs
using Season.Platforms.Windows;
public partial class App : Microsoft.UI.Xaml.Application
{
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
WindowsApp.Run(new Hello.App());
}
}
Linux — Platforms/Linux/Linux.cs
using Season.Platforms.Linux;
internal class Program
{
static void Main(string[] args) => LinuxApp.Run(new App());
}
Android — Platforms/Android/MainActivity.cs
using Season.Platforms.Android;
[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true,
ScreenOrientation = ScreenOrientation.FullSensor)]
internal class MainActivity : BaseActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
if (!AndroidApp.IsInitialized)
AndroidApp.Run(new App());
base.OnCreate(savedInstanceState);
}
}
Deriving from BaseActivity is what wires the Android lifecycle
and touch events into the engine. The
AndroidApp.IsInitialized guard matters because Android
recreates activities: a configuration change must not start a second engine.
iOS and Mac Catalyst — Platforms/iOS/Program.cs
using Season.Platforms.iOS;
internal class Program
{
static void Main(string[] args) => iOSApp.Run(new App());
}
Web — from a Blazor WebAssembly page, after the canvas exists
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender || _started) return;
_started = true;
await WebApp.Run(new App(), JSRuntime, HttpClient, CanvasId, "");
}
WebApp.Run(BaseApp app, IJSRuntime jsRuntime, HttpClient
httpClient, string canvasId = "season-canvas", string? assetBasePath = null). The
IJSRuntime is how the engine reaches the WebGPU device,
which lives in JavaScript; the HttpClient is how asset
loading works, because a browser has no synchronous file system. Pass an
assetBasePath if your assets are not served from the
application root.
Occasionally you need to. DeviceServices.Core.Platform returns
a Platform value —
Windows, Linux,
MacCatalyst, Android,
iOS or Web — and the
reference application uses it to keep features off the platforms that cannot host them.
if (DeviceServices.Core.Platform is Platform.Web)
{
// No window capture, no local model inference.
}
// Services that are not implemented everywhere are null, not stubs.
if (DeviceServices.Recorder != null)
await DeviceServices.Recorder.Start();
The null check is the convention, not a defensive habit: a service with no implementation on a platform is left null deliberately so that the gap is visible at the call site rather than failing silently at runtime. The full list is in cross-platform support.