Avalonia Desktop app¶
Cross-platform desktop app written with Avalonia UI. Shares almost all code (including UI) with the Avalonia Browser app.








Technologies:
- UI:
AvaloniaUI controls. - Rendering:
Highbyte.DotNet6502.Impl.Avalonia. - Input:
Highbyte.DotNet6502.Impl.Avalonia+Highbyte.DotNet6502.Impl.SilkNet.SDL(joystick). - Audio:
Highbyte.DotNet6502.Impl.NAudio, playback viaOpenAL. Two C64 audio providers available: a sample-based one (good but not perfect accuracy — the default) and a command-stream synthesizer one (low CPU but inaccurate). See C64 audio.
Installation¶
See Desktop apps installation for package manager and manual download instructions.
Features¶
System-specific features (ROMs, display, input, audio, SwiftLink, and the C64 menu) are documented on the per-system pages — shared with the Avalonia Browser app, with desktop-specific differences called out inline:
- C64 in the Avalonia apps
- VIC-20 in the Avalonia apps
- Apple II Plus in the Avalonia apps
- Oric Atmos in the Avalonia apps
- Generic computer in the Avalonia apps
Native virtual keyboard¶
The desktop app uses its existing emulator keyboard input for physical keyboards and OS accessibility keyboards. Focus the emulator display, then type or click keys on your OS on-screen keyboard. The Keyboard button and text-entry panel are hidden in the desktop app; they are offered by the browser app on touch-first devices to open the phone or tablet keyboard.
Lua scripting¶
The Avalonia Desktop app supports Lua scripting via MoonSharp. See Tools / Scripting for the full guide.
When the script directory setting is empty, scripts are loaded from ~/Documents/Highbyte/DotNet6502/scripts (or the Windows Documents equivalent).
Snapshots¶
The snapshot save/load UI defaults to ~/Documents/Highbyte/DotNet6502/snapshots (or the Windows Documents equivalent) unless a snapshot directory override is configured in the desktop settings.
VS Code debug adapter¶
The app exposes a TCP-based debug adapter for source-level debugging from VS Code. See Tools / VSCode debugger / Debugging.
Remote control¶
The app can expose a TCP remote control endpoint that lets external processes drive the running emulator. See Tools / Remote control.
UI¶
Menu¶
Start and stop of selected system.
Configuration options of selected system.
Monitor¶
An Avalonia implementation of the machine code monitor is available by pressing F12.
Stats¶
A toggleable stats window by pressing F11.
CLI arguments¶
The desktop app can be launched from the command line with arguments for automated startup (system selection, program / disk loading, C64 BASIC paste), scripting, logging, the debug adapter, and remote control.
There are two mutually exclusive ways to drive startup from the command line:
- Scripting mode — a Lua script selects the system and controls start, load, and lifecycle.
- Automated startup mode — CLI flags select a system, optionally load a program, and start it.
Parameters are grouped below into General parameters (system-agnostic — interpreted by the shared startup pipeline, valid for any system) and one group per system (interpreted by that system's plugin; currently only C64).
The Depends on column lists each parameter's requirements and any parameters it is mutually exclusive with. Availability differs between the Avalonia Desktop app and the Headless app where noted; an (Avalonia Desktop only) / (Headless only) marker means the flag is ignored by the other app.
Important
--script / --scriptDir are mutually exclusive with all automated-startup parameters
(--system, --systemVariant, --start, --waitForSystemReady, --loadPrg, --loadPrgUrl,
--runLoadedProgram, and the C64-specific parameters such as .d64, .crt, and BASIC paste
startup). In scripting mode the Lua script is
responsible for all emulator setup and lifecycle; combining the two modes is an error.
General parameters (system-agnostic)¶
These are interpreted by the shared startup pipeline and are valid for any system.
Updates¶
Handled before the emulator/UI starts; each prints its result and exits immediately. Update checks require a package-manager install (Homebrew / Scoop) — manual-download and development builds report not managed. For how detection works and the on/off setting, see Staying up to date.
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--version |
Print the app version and exit. | — | --version |
--check-update |
Check for a newer release and print the result. Ignores the UpdateCheckEnabled setting and the CI / DOTNET6502_NO_UPDATE_CHECK suppression. |
— | --check-update |
--update |
Check and, if an update is available on a package-manager install, run the brew/scoop upgrade in the foreground, then exit. |
— | --update |
Host-specific notes: on Avalonia Desktop these flags run before the GUI window opens and, on Windows, attach to the invoking console so their output is visible. On Headless the output goes to stdout. The Remote Client exposes the same flags (see its Global options) but never checks automatically.
Scripting¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--script <path> |
Load and run a Lua script. Can be specified multiple times. | Exclusive with all automated-startup parameters. | --script scripts/demo.lua |
--scriptDir <path> |
Override the effective script directory. When omitted, desktop hosts use the configured directory or ~/Documents/Highbyte/DotNet6502/scripts. |
Exclusive with all automated-startup parameters. | --scriptDir ./scripts |
System selection & lifecycle¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--system <name> |
Select a system (e.g. C64, Generic). |
— | --system C64 |
--systemVariant <name> |
Select a system variant (e.g. C64PAL, C64NTSC). |
Requires --system. |
--systemVariant C64PAL |
--start |
Auto-start the emulator after selection. | Requires --system. |
--start |
--waitForSystemReady |
Wait until the system reports ready (e.g. C64 BASIC prompt) before continuing. | Requires --start. |
--waitForSystemReady |
--loadPrg <path> |
Load a local .prg file into memory. |
Requires --start. Exclusive with --loadPrgUrl and C64 --loadD64 / --loadD64Url / --loadCrt / --loadCrtUrl. |
--loadPrg game.prg |
--loadPrgUrl <url> |
(Avalonia Desktop only.) Fetch a .prg over HTTP(S) and load it into memory. |
Requires --start. Exclusive with --loadPrg and C64 --loadD64 / --loadD64Url / --loadCrt / --loadCrtUrl. |
--loadPrgUrl https://example.com/game.prg |
--runLoadedProgram |
Run the loaded program after loading. | Requires --start and a load source (--loadPrg / --loadPrgUrl, or C64 --loadD64 / --loadD64Url). |
--runLoadedProgram |
--load-snapshot <path> |
Restore a full .d6502snap emulator-state snapshot. Relative paths are resolved from the shared snapshot directory. The snapshot's manifest determines the system, so no --system is needed. The machine is left paused after restore; add --start to resume. |
Exclusive with --system, --systemVariant, --loadPrg / --loadPrgUrl, --runLoadedProgram, and --script. --waitForSystemReady requires --start. |
--load-snapshot state.d6502snap |
--loadPrg / --loadPrgUrl copy the file's bytes to the load address in its 2-byte header — but
how a loaded .prg is interpreted and run is system-specific. The systems documented below may
add behavior on top of this (e.g. based on the load address); see the relevant system's parameter
group. Cartridge images use the C64-specific .crt startup flow instead of PRG loading.
Logging¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--console-log / -c |
(Avalonia Desktop only — Headless always logs to console.) Enable console logging output. | — | --console-log |
--log-level <level> / -l <level> |
Console log level (Trace / Debug / Information / Warning / Error / Critical). |
— | --log-level Debug |
Diagnostics & auto-exit¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--show-storage-paths |
Print effective storage paths and exit without starting the app. Also supported by Headless. | — | --show-storage-paths |
--stats-interval <seconds> |
(Avalonia Desktop only.) Log an instrumentation snapshot every N seconds after startup completes. | Requires --start. |
--stats-interval 5 |
--exit-after <seconds> |
(Avalonia Desktop only.) Quit the app N seconds after startup completes. | Requires --start. |
--exit-after 60 |
Debug adapter¶
For the user guide on attaching VS Code, see Tools / VSCode debugger / Debugging.
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--enableExternalDebug |
Start the VS Code debug adapter (DAP) over TCP. This is the flag that enables the server. | — | --enableExternalDebug |
--debug-port <port> |
TCP port for the debug adapter (default 6502). |
Requires --enableExternalDebug. |
--debug-port 6502 |
--debug-bind-address <ip> |
IP address to bind the debug adapter to (default 127.0.0.1). |
Requires --enableExternalDebug. |
--debug-bind-address 0.0.0.0 |
--debug-wait |
Wait for a debug client to connect before starting. | Requires --enableExternalDebug. |
--debug-wait |
Remote control¶
For protocol and command list, see Tools / Remote control.
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--remote-port <port> |
Start the TCP remote control server on this port. | — | --remote-port 6510 |
--remote-bind-address <ip> |
IP address to bind the remote control server to (default 127.0.0.1). |
Requires --remote-port. |
--remote-bind-address 0.0.0.0 |
--allow-remote-quit |
(Headless only.) Allow the emu.quit remote control command to terminate the app. |
Requires --remote-port. |
--allow-remote-quit |
C64 parameters (system-specific — Avalonia Desktop only)¶
These extend the general automated-startup flow and are interpreted by the C64 Avalonia shell
plugin. They are not parsed by the Headless app today (it has no C64 shell plugin). They build
on the general --system C64, --start, and --waitForSystemReady flags.
Loading a C64 .prg (BASIC vs machine-language)
The general --loadPrg / --loadPrgUrl flags copy the file's bytes to the load address in its
2-byte header. No separate parameter is needed for C64 BASIC programs; the C64 plugin adapts
automatically based on the load address:
- C64 BASIC program (load address
$0801): after the load, the BASIC variable pointers are initialized automatically, and with--runLoadedProgramthe program is started by typingRUN. This path requires--waitForSystemReadyso the load andRUNhappen after the BASIC prompt is up. - Machine-language program (any other load address):
--runLoadedProgramsets the CPU program counter to the load address instead.
So a C64 BASIC .prg is loaded and run with
--system C64 --start --waitForSystemReady --loadPrg prog.prg --runLoadedProgram.
BASIC source paste¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--basicText <text> |
Paste inline C64 BASIC source (plain text) after BASIC is ready. | Requires --system C64, --start, --waitForSystemReady. Exclusive with --basicFile, --basicUrl, and any PRG / .d64 / .crt load. |
--basicText "10 print \"hi\":goto 10" |
--basicFile <path> |
Paste C64 BASIC source read from a local file. | Same as --basicText. |
--basicFile hello.bas |
--basicUrl <url> |
Fetch C64 BASIC source over HTTP(S) and paste it. | Same as --basicText. |
--basicUrl https://example.com/hello.bas |
--runBasic |
Queue run + Return after the BASIC source is pasted. |
Requires --basicText / --basicFile / --basicUrl. |
--runBasic |
Disk image (.d64)¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--loadD64 <path> |
Load a local C64 .d64 disk image. ZIP archives are also accepted; by default the first .d64 entry is used. |
Requires --system C64, --start, --waitForSystemReady, and exactly one of --d64Program / --diskMount. Exclusive with --loadPrg / --loadPrgUrl / --loadD64Url / --loadCrt / --loadCrtUrl. |
--loadD64 game.d64 |
--loadD64Url <url> |
(Avalonia Desktop only.) Fetch a .d64 over HTTP(S). ZIP archives are also accepted; by default the first .d64 entry is used. |
Same as --loadD64. Exclusive with --loadD64, the PRG loads, and the CRT loads. |
--loadD64Url https://example.com/game.d64 |
--loadD64ZipEntry <entry> |
Select an exact .d64 entry inside a ZIP archive. Use forward slashes for directories. |
Requires --loadD64 / --loadD64Url and the source must be a ZIP archive. |
--loadD64ZipEntry side-b/game.d64 |
--d64Program <name\|*> |
Direct-load a PRG from the disk image into memory (no disk mount). * selects the first directory entry. |
Requires --loadD64 / --loadD64Url. Exclusive with --diskMount. |
--d64Program "*" |
--diskMount |
Mount the image in drive 8 and prepare LOAD"*",8,1 + RUN via the keyboard buffer. |
Requires --loadD64 / --loadD64Url. Exclusive with --d64Program. |
--diskMount |
When loading a .d64, the general --runLoadedProgram flag controls whether the disk's run
commands are pasted after the load / mount: LOAD"*",8,1 + RUN for --diskMount, just RUN for
--d64Program.
Cartridge image (.crt)¶
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--loadCrt <path> |
Attach a local C64 .crt cartridge image at startup. ZIP archives containing exactly one .crt are also accepted. |
Requires --system C64, --start. --waitForSystemReady is not required. Exclusive with PRG, BASIC, and .d64 startup loads. |
--loadCrt fc3.crt |
--loadCrtUrl <url> |
(Avalonia Desktop only.) Fetch and attach a .crt over HTTP(S). ZIP archives containing exactly one .crt are also accepted. |
Same as --loadCrt. Exclusive with --loadCrt. |
--loadCrtUrl https://example.com/fc3.crt |
--loadCrtZipEntry <entry> |
Select an exact .crt entry inside a ZIP archive. Use forward slashes for directories. |
Requires --loadCrt / --loadCrtUrl and the source must be a ZIP archive. Allows archives with multiple .crt files when the entry is explicit. |
--loadCrtZipEntry carts/fc3.crt |
Cartridge startup attaches the image after the C64 instance has been started, and the cartridge
attach operation resets / boots the machine into the cartridge. The general --runLoadedProgram
flag does not apply to .crt images.
Runtime config¶
These knobs override the C64 host config before the system starts. They apply for any C64 start
path — plain --start, --loadPrg / --loadPrgUrl, BASIC paste, --loadD64 / --loadD64Url,
or --loadCrt / --loadCrtUrl.
| Parameter | Description | Depends on | Example |
|---|---|---|---|
--keyboardJoystickEnabled |
Force-enable the C64 keyboard-emulated joystick. | Requires --system C64. |
--keyboardJoystickEnabled |
--keyboardJoystickNumber <1\|2> |
C64 joystick port the keyboard emulates (and which gamepad port drives). | Requires --system C64. Implies --keyboardJoystickEnabled. |
--keyboardJoystickNumber 2 |
--audioEnabled <true\|false> |
Override the C64 audio-enable config before start. Omit to keep the existing value. | Requires --system C64. |
--audioEnabled false |
Examples¶
# Run a Lua script (script owns all setup and lifecycle)
./Highbyte.DotNet6502.App.Avalonia.Desktop --script scripts/example_c64_basic_readwrite.lua
# Start C64 and load a local .prg file via CLI (no script)
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --loadPrg game.prg --runLoadedProgram
# Start C64, fetch a .prg over HTTP, and run it
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --waitForSystemReady --loadPrgUrl https://example.com/game.prg --runLoadedProgram
# Start C64, paste BASIC source from a local file and run it
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --waitForSystemReady --basicFile hello.bas --runBasic
# Start C64 PAL, mount a .d64, paste LOAD"*",8,1 + RUN, set keyboard-joystick to port 2
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --systemVariant C64PAL --start --waitForSystemReady --loadD64 "/path/to/SomeGame.d64" --diskMount --runLoadedProgram --keyboardJoystickEnabled --keyboardJoystickNumber 2
# Start C64, direct-load the first PRG from a .d64 image (no disk mount) and RUN it
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --waitForSystemReady --loadD64 "/path/to/SomeGame.d64" --d64Program "*" --runLoadedProgram
# Start C64, fetch a .d64 over HTTP, direct-load the first PRG (no disk mount) and RUN it
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --waitForSystemReady --loadD64Url https://example.com/game.d64 --d64Program "*" --runLoadedProgram
# Start C64 and attach a local .crt cartridge image
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --loadCrt "/path/to/fc3.crt"
# Restore an emulator-state snapshot and resume running it (manifest determines the system)
./Highbyte.DotNet6502.App.Avalonia.Desktop --load-snapshot "/path/to/state.d6502snap" --start
# Restore a snapshot but leave it paused
./Highbyte.DotNet6502.App.Avalonia.Desktop --load-snapshot "/path/to/state.d6502snap"
# Start with debug adapter for VS Code, waiting for client
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --enableExternalDebug --debug-port 6502 --debug-wait
# Start with debug adapter bound to all interfaces (use only on trusted networks)
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --enableExternalDebug --debug-port 6502 --debug-bind-address 0.0.0.0
# Start with remote control server on port 6510 (loopback only)
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --remote-port 6510
# Start with remote control server accessible from the network (trusted networks only)
./Highbyte.DotNet6502.App.Avalonia.Desktop --system C64 --start --remote-port 6510 --remote-bind-address 0.0.0.0
How to run locally for development¶
For development system requirements, see Development.
Prerequisites, compatibility, and troubleshooting¶
See Avalonia Desktop app troubleshooting.
Visual Studio (Windows)¶
Open solution dotnet-6502.slnx. Set project Highbyte.DotNet6502.App.Avalonia.Desktop as startup, and start with F5.
VSCode¶
TODO
See also¶
- Avalonia Desktop app automation — UI automation and accessibility.
- Avalonia Desktop app troubleshooting — platform-specific notes.