Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

The window, status bar, and menus

Copperline opens a single window: the emulated display presented at a TV-like 4:3 aspect ratio, above a status bar with the machine’s controls. The window scales continuously when resized.

The display defaults to buffered, synchronised presentation (strict FIFO vsync) on all desktop platforms. Video Settings -> VSync changes this immediately; it is also in the configuration screen’s A/V & Emu -> Display category and saved as [display] vsync. PAL output is roughly 50 Hz, so motion can still have an uneven cadence on a fixed 60 Hz or 120 Hz display, where some Amiga frames stay on screen for an extra refresh. VSync prevents tearing, but it does not make those refresh rates match or change the emulated machine’s speed.

On native Wayland, redraws also follow compositor frame callbacks. This allows the compositor to throttle a hidden window and schedule visible updates, including when VSync is off.

For display diagnostics, launch with RUST_LOG=info to log the selected presentation mode, supported modes, GPU, graphics backend, and window system. The window-system field distinguishes native Wayland from an X11 window running through XWayland. Add COPPERLINE_PRESENT_PROFILE=1 to log each presentation attempt: its emulated frame number, interval since the previous attempt, time acquiring/uploading the surface, time recording draw commands, and time submitting/presenting. submitted=false means no frame was submitted; -1 marks a stage that was not reached. These are host CPU timings, not GPU execution or physical display timestamps. They complement the performance overlay, whose FPS measures emulated frames.

On Windows, if the default graphics backend selects a CPU software renderer, Copperline tries OpenGL and uses it when its adapter is not reported as a CPU renderer. This avoids a slow software DirectX path on systems with accelerated OpenGL, including some virtual machines. If OpenGL cannot initialise or also selects a CPU renderer, Copperline rebuilds the renderer using the original backend. If that also fails to initialise, it reports the startup error. Setting WGPU_BACKEND or WGPU_ADAPTER_NAME disables this automatic fallback so explicit selections still apply. The startup log records any switch.

Keyboard shortcuts

The app shortcut modifier is Cmd on macOS and Alt on Linux/Windows.

macOSLinux/WindowsAction
Cmd+QAlt+QQuit (also the menu’s last row; a calibrated gamepad’s optional Quit hotkey, held, quits too)
Cmd+EAlt+EOpen / close the menu (also the status bar’s hamburger button); releases a captured mouse
Cmd+SAlt+SSave a screenshot (copperline-screenshot-<YYYYMMDDHHmmSS>.png in the screenshots folder; the on-screen confirmation overlay is not part of the saved image)
Cmd+RAlt+RStart / stop a video-with-audio recording (below)
Cmd+Shift+RAlt+Shift+RStart / stop an input recording (below)
Cmd+Shift+VAlt+Shift+VPaste as keystrokes: type the host clipboard’s text on the emulated keyboard (also Input Settings -> Paste as Keystrokes)
Cmd+Shift+GAlt+Shift+GSave the last few seconds of the display as an animated GIF (copperline-clip-<YYYYMMDDHHmmSS>.gif in the recordings folder; see Saving a GIF clip)
Cmd+Shift+SAlt+Shift+SSave a state (copperline-state-<YYYYMMDDHHmmSS>.clstate in the states folder)
Cmd+Shift+LAlt+Shift+LOpen the Load State browser
Cmd+1..Cmd+9, Cmd+0Alt+1..Alt+9, Alt+0Quick-save to numbered slot 1-10
Cmd+Shift+1..Cmd+Shift+0Alt+Shift+1..Alt+Shift+0Quick-load from that slot
Cmd+DAlt+DSwap the first drive with a queued playlist to its next disk
Cmd+GAlt+GCapture / release the host mouse (clicking the display also captures)
Cmd+BAlt+BToggle the Debug layout
Cmd+Shift+BAlt+Shift+BPress the freezer cartridge’s button: enter the HRTMon monitor ([cartridge] model, see Configuration)
Cmd+KAlt+KToggle the Console in Debug layout
Cmd+JAlt+JToggle joystick input mode: gamepad / keyboard (also the status-bar icon)
Cmd+MAlt+MTurn the monitor bezel off, or back on to the chosen front (Video Settings -> Monitor Bezel picks it; [display] bezel sets the start-up value)
Cmd+Shift+AAlt+Shift+ACycle the audio output: Default, each host device, then Disabled (also Audio Settings -> Audio Output)
Cmd+AAlt+ACycle Paula’s audio filter: auto, on, off (also Audio Settings -> Audio Filter)
Cmd+Shift++ / Cmd+Shift+-Alt+Shift++ / Alt+Shift+-Raise / lower the parallel-port sampler input gain (only when a sampler is attached; also Parallel Port -> Sampler Gain)
Cmd+Shift+> / Cmd+Shift+<Alt+Shift+> / Alt+Shift+<Raise / lower the host mouse sensitivity (also the launcher’s Input tab)
Cmd+FAlt+FToggle fullscreen on / off
Cmd+Shift+FAlt+Shift+FShow / hide the status bar
Cmd+PAlt+PToggle the performance overlay ([display] perf_overlay sets the start-up value)
Cmd+WAlt+WToggle Warp Speed (turbo) on / off; one press also ends every warp a control client, a GDB client, the guest, or a boot phase engaged
Cmd+Shift+WAlt+Shift+WCycle the Warp Speed limit: 2x, 4x, 8x, 16x, Max
Cmd+ZAlt+ZRewind the machine one step (needs [emulation] rewind or Emulation Settings -> Rewind)
EscEscClose an open menu or overlay panel (in Debug controls, return to Play); otherwise passed through to the Amiga
Ctrl+Amiga+AmigaCtrl+Amiga+AmigaKeyboard reset (warm reboot)

Host modifiers that are passed through to the emulated keyboard map onto the Amiga keyboard: Alt becomes Amiga Alt, Cmd/Super becomes the left/right Amiga keys, and left Ctrl becomes Amiga Ctrl, so Ctrl+Amiga+Amiga is typed naturally. The Amiga keyboard has no right Ctrl, so host right Ctrl also acts as the right Amiga key -- handy on PC/laptop keyboards that lack a right Super/Win key. Host F11 types the Amiga Help key, and the ISO key between left Shift and Z types the Amiga key in the same position.

All other keys reach the emulated machine through a bit-timed model of the keyboard’s microcontroller. It clocks each transition into CIA-A’s serial register over the emulated KCLK/KDAT lines, with the real handshake, power-up stream, and recovery protocol, so software that drives the keyboard hardware directly works too. Ctrl+Amiga+Amiga runs the authentic reset protocol (reset warning, then KCLK held low), so the reboot lands a fraction of a second after the chord, as on real hardware.

During a netplay session only a few of these shortcuts apply; see Netplay controls.

Keyboard and controller navigation

Everything the mouse can reach in the launcher, the menu, the status bar and the overlay panels can be reached with the arrow keys or a controller.

The arrows move the focus, which lights the control it is on. Return (or the pad’s fire button) works it; Esc (or the pad’s second button) steps back out -- out of an open setting, then the page, then the surface. Left and right move along the row, up and down to the row above or below; at the edge of a surface the focus stays where it is. Controls that cannot be pressed are skipped.

ControlReturn / fire
Buttons, tabs, the close gadgetPresses it
Tick boxes and cover artTicks it
Text boxesOpens it for typing
< value > settingsOpens it; left and right change the value, Return closes it
Volume sliderOpens it; left and right move it

Lists -- the games, the favourites, the host’s disks -- are walked with up and down, which move the list’s own selection and scroll it. Right steps to the tick beside a row and then out of the list; left leaves it.

Stepping down off the foot of a surface reaches the status bar, and up returns. Left out of a settings page returns to the category button that opened it, and right opens that button’s page. Walking off the bottom of the menu closes it and leaves the focus on the menu button.

Clicking anything hides the focus and moves it to where the pointer pressed, so going back to the keyboard resumes from there. While the focus is shown the pointer highlights nothing; moving the mouse hides the focus again.

A controller drives all of this with its d-pad, fire and second button. Its Menu button is the way in from a running machine, and the way out too: the menu’s last row is Quit, and the Menu button held quits -- unless the pad’s calibration bound a separate Quit control, which then owns the hold instead.

The inspectors of the Debug workspace -- the debugger, Frame Analyzer and Console -- are not walked this way. There Esc leaves a text field first and then returns to Play, and the pad’s second button closes the inspector in front.

Status bar

The status bar is a 44-pixel strip below the display. Cmd+Shift+F / Alt+Shift+F or Video Settings -> Status Bar hides it entirely. From left to right it holds:

On-screen keyboard

The keyboard button in the status bar, or Input Settings -> On-Screen Keyboard, draws an Amiga keyboard in a strip between the display and the status bar. The window grows to make room for it: the picture keeps its size, the canvas gets taller, and hiding the keyboard gives the height back. A window you have resized yourself keeps its size, and the display reflows into it as usual.

It is an A600 -- the one Amiga keyboard with no numeric keypad, so the whole machine fits the window’s width at a usable cap size. Clicking a cap sends that key’s rawkey to the emulated keyboard MCU over the same authentic serial protocol a host keystroke uses, and is recorded the same way, so on-screen keys are captured by --record-input and replay from the resulting --script file. The two keyboards are independent holders of the same key: pressing a cap the host keyboard is already holding down changes nothing for the machine, and the key comes up only when the last of the two lets go.

The keyboard reaches the keys a host keyboard may lack -- Help, both Amiga keys, and the #/~ key beside Return -- and lets you drive a session entirely with the mouse.

Performance overlay

Cmd+P (macOS) / Alt+P (Linux/Windows), Video Settings -> Performance, or [display] perf_overlay = true shows a live emulation-performance readout in the top-right corner of the display, one line per data point at the menu’s font size (it follows Menu Size), refreshed twice a second:

LineMeaning
50.0 fpsEmulated video frames retired per host second: 50 (PAL) or 60 (NTSC) when the machine holds real time, lower when the host cannot keep up, far higher under Warp Speed
x1.00Speed factor: emulated seconds advanced per host second (the effective multiplier under Warp Speed)
emu 3.2 msHost milliseconds of emulation work per emulated frame, pacing sleeps excluded
host 16%Share of host wall time spent emulating. In real-time mode this is the share of the frame budget (20.0 ms PAL, 16.7 ms NTSC) used per frame
audio 148 msLive audio output lead -- the cushion that absorbs host scheduling hiccups (steady state is about 150 ms)
xrun 0Audio underrun frames per second: the audible symptom of the host falling behind
slip 0Times the pacer reset its host-time target after exceeding the catch-up limit (for example, after a host stall), since the last guest reset

Copperline never skips frames to keep pace: when the host cannot sustain real time the machine slows down (fps and the speed factor fall below nominal while host sits near 100%). After a long stall, the pacer resets its host-time target and increments slip; guest execution continues from the same point. Under Warp Speed the presentation shows one frame per burst, but every emulated frame is still computed.

Like the transient message overlay, the readout is painted into the presentation only: screenshots, frame dumps, and recordings never include it. While a video recording is running the block steps below the REC badge. COPPERLINE_PERF_OVERLAY=1|0 overrides the config for a single run, and --perf-overlay shows it from the command line; the launcher’s Perf overlay row (A/V & Emu, Display) makes it stick. The same counters are exported through the control protocol’s status reply for headless runs (see Control protocol (CCP)).

Guest debug overlay

Guest programs (such as those using the vscode-amiga-debug template) can draw debug shapes and text on the screen with the uaelib trap helpers (debug_rect, debug_filled_rect, and debug_text; see Direct executable launching (--run)). They stay until debug_clear removes them. Their coordinates are in a virtual 768x576 space mapped across the active display area, so they follow the autocrop and scaling settings. The debug overlay is drawn beneath the host UI (status bar, OSD, performance overlay) and affects only live window presentation; screenshots, frame dumps, and video recordings exclude it. Disabling [emulation] uaelib removes the uaelib trap entirely.

Drag and drop

Disk images can be dropped anywhere on the emulator window:

During a netplay session only the host can drop disks, and only floppy images; they go to the first connected drive.

The chooser opens after the drop rather than offering per-drive drop targets because the windowing layer reports file drops without a cursor position. Drops are not delivered at all under native Wayland (X11 and XWayland work).

The pop-up menu with a category open

The menu, with a category open beside it.

The hamburger button at the right of the status bar opens the menu, as does Cmd+E / Alt+E. It grows upward from the status bar and dims the picture behind it, so the menu stays readable over a busy picture. The dimming is a window effect: it never appears in a screenshot, a frame dump, or a recording.

The top level holds the tools, then a category per area of the machine, then Load Kickstart ROM..., Keyboard Shortcuts..., About..., and Quit at the foot. A category is marked > and opens a list of its own beside it; a setting with more than two values opens a further list of those values with the one in force ticked, and a setting that is simply on or off is ticked in place. Categories with nothing to offer are not shown at all: the serial port unless it is in MIDI mode, the parallel port unless a sampler is on it, and the PCMCIA slot on machines without one.

Point at a category and it opens; point at one of its rows and that row is where the keyboard is. The cursor keys walk the same path -- up and down within a list, right into a category, left back out -- and Return picks the row under the cursor. Esc steps back one level, and closes the menu from the top.

Picking a row that opens something else -- a window, a panel, a file dialog -- closes the menu behind it. Changing a setting leaves the menu up with the new value marked, so a run of changes costs one open rather than one each. Opening the menu also releases a captured mouse.

Menu Size under Video Settings draws the whole menu at 1x or 2x. The start-up size is [display] menu_scale, --menu-scale, or Menu size on the launcher’s A/V & Emu page (Display category).

The Debug workspace puts the Amiga display beside the debugger, Frame Analyzer, and Console in the main window. Switch inspectors with the tabs at the top, close one with the close box on its own tab, and resize the display using the divider. The title bar’s Play / Debug switch changes layout: Play restores the display layout and keeps the inspectors open, with their selections, captures, and command history. Switching layouts preserves the current run/pause state.

Click the display to send keyboard and mouse input to the Amiga; Cmd+G / Alt+G returns input to the debugger. In the inspector controls, Esc leaves a text field first, then returns to Play. When the Amiga owns input, Esc belongs to the guest. Overlay panels remain modal: their keys and clicks stay in the UI.

Tools

Emulation Settings

Audio Settings

Video Settings

Input Settings

Warp Settings

Serial Port and Parallel Port

Shown only when something is on the port: the serial port in MIDI mode, or a sampler on the parallel port.

PCMCIA Card

Offered only on an A600 or A1200, whose Gayle carries the credit-card slot. The list opens with what is in the slot, which cannot be picked: the card image’s file name, in the colour a value carries (cut short with a ~ if it is wider than the list), or a greyed None.

See the [pcmcia] section of Configuration for boot-time cards, SRAM cards, real card readers, and the fast-RAM rule.

Recording

Save State

Application controls

The keyboard shortcuts window

The Keyboard Shortcuts window.

Machine configuration screen

Starting Copperline with no machine specified -- no ./copperline.toml, no --config, no ROM or override, and not a headless run -- opens the configuration screen instead of booting. It is also available any time from the menu’s Machine Configuration... item, seeded with the running machine’s settings.

The machine configuration screen

The configuration screen: the machine selector across the top, category tabs down the left, settings on the right, and the action bar along the bottom. Here an A1200 is selected on the Memory tab; Zorro III RAM is greyed with the reason “needs 32-bit CPU” (the A1200’s 68EC020 has a 24-bit bus).

The layout is:

The Boot Priority sub-page of the Storage tab

The Boot Priority sub-page: an A1200 whose IDE master boots at priority 0, its slave with the Bootable box cleared (showing the -128 that stores), and one SCSI unit of a fitted A2091 carrying a disk of its own. A greyed Info: label heads a note on the valid priority range.

Saved files use the same schema as a hand-written copperline.toml (see Configuration reference), so the screen and the config file are interchangeable: configure a machine and save it, or load an existing config to tweak it. Run builds the machine in place, so the configuration screen and a direct --config launch produce an identical machine.

Create Image

Storage -> Create Image... makes new, empty disk images: Floppy Disk writes an ADF, Hard Disk writes an HDF. These pages write a file and nothing else; none of their settings belongs to the machine, so none of it is saved to a configuration file.

Save... opens a file dialog, then writes the image. The status line reports progress and the finished size; the write runs in the background, so the window stays responsive while a large image is written.

A hard disk image is saved as .hdf or .img, which hold the same bytes. The page does not write CHD, and refuses a name ending in .chd; make a CHD from the finished image with chdman createhd.

Floppy Disk

OptionEffect
DensityDD (880K) or HD (1.76M). Sets the image size: 901,120 or 1,802,240 bytes. Copperline’s floppy drives are double-density only and cannot use an HD image in either container, so the page shows a warning while HD is selected. Make HD images for another emulator, or for a real Amiga with a high-density drive.
ContainerStandard ADF writes the sectors in order. Extended ADF wraps them in the UAE-1ADF container, which stores one record per track.
FilesystemUnformatted leaves the image blank for the Amiga to format. OFS and FFS write a boot block, root block and bitmap.
DOSTypeThe DOS type’s options: International case folding, Dir cache, Long names. See DOSType below.
Volume nameThe name the volume mounts under.
BootableWrites the boot code that loads dos.library, so the disk boots rather than only mounting.

Hard Disk

OptionEffect
SizeA whole number up to 9999, in the unit beside it. Click MB/GB to change the unit. The image is rounded up to the next whole cylinder.
GeometryAuto derives cylinders/surfaces/sectors from the size. Custom sets them by hand, and adds a Configure button that opens the geometry editor.
PartitioningRDB writes a Rigid Disk Block and one partition filling the drive. None writes no partition table.
FilesystemAs for a floppy. With RDB the type is recorded in the partition entry; with None the volume starts at block 0.
DOSTypeAs for a floppy.
Device nameThe device the partition mounts as, e.g. DH0. RDB only.
Volume nameThe name the volume mounts under.
BootableSets the partition’s bootable flag. RDB only.
Boot priorityThe partition’s de_BootPri, -128 to 127. Kickstart enters DF0: at 5, so 6 boots the hard disk ahead of a floppy. Applies while Bootable is ticked.
Read onlyMarks the finished file read-only on this computer.
Sparse imageOn by default: the file is created at full length with only its structure written, and the host fills the rest in as it is used. Clear it to write the whole file now, which takes as long as writing that many bytes.

An image larger than 2048 GB can be made only with Partitioning: None and Filesystem: Unformatted: every block number an RDB or an AmigaDOS volume uses is a 32-bit field.

With Sparse image cleared, the volume the file is being written to is checked for room first, and the write is refused if there is not enough.

The Hard Disk page of the Create Image sub-page

The Hard Disk page, set up for a 64 MB bootable FFS volume in an RDB with custom geometry.

Geometry editor

Reached from Configure on the Hard Disk page once Geometry is set to Custom. The geometry set here decides the image’s size; the Size box seeds it.

OptionEffect
Cylinders, Surfaces, Sectors per trackThe drive’s stated geometry. Surfaces x sectors is one cylinder; the RDB states the partition in cylinders, so these set the granularity a partition can start and end on.
Reserved blocksBlocks at the front of the partition the filesystem never allocates. Two -- the length of the boot block -- unless there is a reason to say otherwise.
Drive, Type, RevisionWhat the drive answers when asked what it is. HDToolBox shows the first two as its Drive and Type columns. Each box holds as many characters as its RDB field: 8, 16 and 4.

Apply returns to the Hard Disk page. Auto puts every figure back to what the size implies, and the identity back to Amiga / the size / Copperline’s version.

The geometry editor of the Create Image sub-page

The geometry editor, with the drive identity below the figures and a note of the size they come to.

DOSType

The Filesystem row picks OFS or FFS; the DOSType row picks the options that filesystem carries. Between them they name one of the eight AmigaDOS types:

TickedType
--DOS0 (OFS), DOS1 (FFS)
InternationalDOS2, DOS3
International + Dir cacheDOS4, DOS5
International + Long namesDOS6, DOS7

Dir cache and Long names are two values of one field, so ticking one greys the other. Both are international, so International shows ticked and greyed alongside either.

Dir cache needs Kickstart 3.0, International needs 2.0, and Long names needs a filesystem no Kickstart provides.

Saving native screenshots

Choose Recording → Save Native Screenshot (1:1) to save the active playfield at its original pixel size, without the TV border, aspect correction, filtering, phosphor persistence or tint. Black pixels inside the playfield are kept. RTG screens save at the board’s native resolution. Interlaced chipset screens save the current field, without blending or weaving another field into it.

Starting Copperline with --native-screenshots also makes the camera button and Cmd+S / Alt+S use this capture. You can switch just the button and shortcut in Video Settings → Native Screenshot Button; set [recording] native_screenshot_button = true to start with it enabled. To keep a change made in the menu, choose Machine Configuration → Save default. See native headless captures for resolution and crop details.

Screenshots save to the screenshots folder.

Recording video

Cmd+R on macOS or Alt+R on Linux/Windows (or the menu’s “Record Video”) starts capturing the emulated display and sound to copperline-video-<YYYYMMDDHHmmSS>.avi in the recordings folder; pressing it again stops and finalizes the file. A red REC badge sits in the display’s top-right corner while a recording runs. Like the screenshot overlay, the badge, status bar, and menus are never part of the captured video.

The file is an AVI with lossless ZMBV video (the DOSBox capture codec: zlib-compressed keyframes plus frame deltas, which keeps typical Amiga output to a few MB per minute) and uncompressed 16-bit stereo PCM audio at 44.1 kHz. It plays directly in VLC, mpv, and anything else built on ffmpeg; for other players, transcode with ffmpeg -i copperline-video-<ts>.avi out.mp4.

Frames and audio are captured on the emulated timeline, not the host clock: the recording stays in sync even when the host stutters, and a capture made under Warp Speed plays back at normal speed. The audio track is tapped before the status bar’s volume slider, so recordings keep full level regardless of the live output volume. Pausing (or powering off) suspends the capture; recording resumes when emulation continues.

Saving a GIF clip

The window keeps a rolling ring of the last ten emulated seconds (by default) of the picture it presents, so a moment worth sharing can be saved after it happened: Cmd+Shift+G on macOS or Alt+Shift+G on Linux/Windows (or the menu’s “Save Clip as GIF”) writes the ring as copperline-clip-<YYYYMMDDHHmmSS>.gif in the recordings folder and confirms the file name on screen when it is done. The clip is written on a background thread, so emulation never pauses; asking for another clip while one is still being written only shows a notice.

The GIF shows exactly what a screenshot would: the presentation’s crop, TV aperture, H/V centre and pixel aspect, with the status bar, menus and the on-screen message left out. Frames are thinned to 25 per second on PAL and 30 on NTSC ([recording] clip_fps sets another rate) and each carries its own palette, so the usual Amiga picture is stored losslessly; a frame with more than 256 colours (a HAM picture, for example) is reduced to 256 with NeuQuant when the file is written. Frame delays follow the emulated timeline, so a clip made under Warp Speed plays at normal speed, and a stretch where Warp presented no frames plays as one held frame rather than a burst. A clip has no sound; use Record Video for that.

[recording] clip_seconds sets the ring’s length (up to 120 seconds; 0 switches the ring off, and the menu item and shortcut then only say so) -- see Configuration. The ring holds pictures in their palette-indexed form and stores a picture once however long it stays on screen, so a ten-second ring costs well under 100 MB of host memory in practice; it is bounded at 256 MB regardless. Loading a save state, resetting or running a different machine starts the ring over. The headless --gif-after flag writes the same kind of clip from a scheduled emulated time (see Capturing GIF clips).

Recording input

Cmd+Shift+R on macOS or Alt+Shift+R on Linux/Windows (or the menu’s “Record Input”) starts logging every input event that reaches the emulated machine -- key presses with their hold times (typed on the host keyboard or clicked on the on-screen one, which reaches the machine by the same path), mouse buttons and motion, joystick / CD32-pad controls, analogue pot positions, and floppy inserts, on whichever port carries each device -- each stamped with its emulated time. Pressing it again stops the recording and writes copperline-input-<YYYYMMDDHHmmSS>.clscript in the recordings folder: a plain text file of scripted-input directives that copperline --script FILE replays exactly, because the core is deterministic and the events re-fire at the same emulated timestamps.

This is the direct way to turn “I can reproduce it by hand” into a regression: play the sequence once while recording, then keep the script (optionally together with a save state to skip the lead-in) as a deterministic, shareable reproduction. The format and the headless --record-input variant are described in Input scripts and recording.

Save states

Cmd+Shift+S on macOS or Alt+Shift+S on Linux/Windows (or the menu’s “Save State”) writes a snapshot of the whole emulated machine to copperline-state-<YYYYMMDDHHmmSS>.clstate in the states folder: CPU, chip/slow/fast RAM, ROM, the full chipset and CIA state, floppy images (including unsaved in-memory changes), expansion boards, and CD/NVRAM state. Cmd+Shift+L / Alt+Shift+L (or “Load State...”) opens the browser below to restore one; the machine continues from exactly the saved point, byte-for-byte -- the core is deterministic, so a resumed run is indistinguishable from one that was never interrupted. Your audio output settings (the volume slider, mono/stereo, stereo separation, and the filter override) are not part of the machine: loading a state or rewinding keeps whatever they are set to now.

Every state also carries a small card about itself, written ahead of the machine so it can be read without loading anything: a thumbnail of the display at the moment of the save (240 pixels wide, the same picture a screenshot would take), the emulated time and the wall-clock time of the save, a one-line machine summary, and the names of the media in the drives (floppies, hard-drive images, CD). The browser shows it, and copperline-ctl state-info FILE.clstate prints it as JSON (with --thumbnail FILE.png to write the picture out; see the control protocol reference). States written before this card existed load exactly as before and show in the browser without a picture.

States are taken at emulated-frame boundaries and are versioned per subsystem: the file is a set of tagged chunks (CPU, memory, Paula, Agnus, floppy, expansion boards, ...) that name their fields, so a state keeps loading across releases that add or drop state fields, and a release that changes what a subsystem’s state means upgrades that chunk on load. A file a build cannot read is refused with a message naming the chunk and versions rather than producing a corrupt machine. A build still needs support for every expansion board present in the snapshot. States written by Copperline 0.19 and earlier used a flat layout with a single version and must be recreated.

Saving over an existing file replaces it only after the new snapshot has been completely written and flushed. A failed save leaves the previous file intact.

A state is self-contained: it carries its own RAM, ROM, and chipset, so loading one always restores the machine it was taken on -- even if you launched Copperline with a different config. When the loaded machine differs from the running one -- a different model, chipset, video standard, RAM size, or even a different Kickstart of the same machine (the ROM is fingerprinted) -- the load reconfigures to match the state and tells you so (the load message names the restored machine, e.g. “reconfigured to A1200 / 68EC020 / AGA / PAL”); your current config is not silently mixed in. Two caveats:

Load State browser

The Load State browser listing quick-save slots and named states with thumbnails

The Load State browser: the ten slots, then the folder’s states newest first. One state was taken on a different machine and is flagged; one file is not a state at all and says so.

Load State... (or Cmd+Shift+L / Alt+Shift+L) lists the states folder: the ten quick-save slots first, empty ones included, then every other .clstate in the folder, newest first. Each row shows the state’s thumbnail, when it was saved, how far into the emulated run it was taken, the machine it was taken on, and what was in the drives. A state taken on a different machine than the one running -- another model, chipset, memory size, or Kickstart -- is shown in amber with the difference named; it still loads (a state carries its own machine, and the load reconfigures to match it, as described above), the flag just says that it will. A file the build cannot read is listed with the reason, so a stray or damaged file can still be found and deleted from here.

Clicking a row loads it and closes the browser. With the keyboard, up and down move the selection (Page Up/Down and Home/End move faster), Return loads the selected state, and Delete asks before removing its file -- the question comes up with Cancel under the focus, so a second Return keeps the file and Delete again (or left, then Return) removes it. Down off the foot of the list reaches the button row, where left and right pick Load, Delete, or Browse...; Esc closes the browser (or withdraws the question first). A controller walks the same list with its d-pad, fire, and second button, as everywhere else. Browse... opens the file dialog for a state kept outside the folder.

A deleted slot shows as empty again; a deleted named state leaves the list. Loading reports “Loaded Slot 3” or the file’s name on the OSD, and a state that fails to load puts the browser back up with the reason on its status line.

Quick-save slots

Naming a file is the wrong interaction for the “before this jump” save you take twenty times an hour, so there are ten numbered slots as well. Cmd/Alt+<digit> saves to that slot and Cmd/Alt+Shift+<digit> loads it, with 0 as the tenth. The menu’s Quick Save and Quick Load lists reach the same ten, each row naming when that slot was written or showing it as empty.

A quick save overwrites its slot without asking -- that is the point of it -- and loading a slot that has never been written reports “Slot N is empty” rather than failing. Slots are ordinary .clstate files, identical in format to a named save, kept in the states folder below, and the Load State browser lists them first, each with its thumbnail, so a slot can be told from another by what it shows rather than by its number. And because they are per user and not per machine, a slot may hold a state from a different Amiga than the one running. That is safe: as above, the state carries its own machine and the load reconfigures to match it and says so, and the browser flags such a slot before it is picked.

The headless flags --save-state-after SECS PATH and --load-state PATH script the same feature for debugging workflows: snapshot a long-running program just before the scene under investigation once, then iterate from the state in seconds instead of re-emulating minutes. The file format and what exactly is (and is not) captured are specified in the internals chapter.

Where files go

Everything Copperline produces is kept per user rather than per working directory, so it is reachable however Copperline was launched. The host-data directory is:

HostLocation
Linux/BSD~/Documents/Copperline/
macOS~/Documents/Copperline/
Windows%USERPROFILE%\Documents\Copperline\

with a folder inside it for each kind of file: screenshots/, states/ (named saves and the quick-save slots), recordings/ (video captures, GIF clips and recorded input scripts), nvram/ (battery-backed clock RAM and CD32 game saves), traces/ (debugger traces and waveform captures), and configs/ (configurations saved from the configuration screen). Each folder is created on first use, and each can be moved with the [paths] section of the configuration or the configuration screen’s A/V & Emu -> Paths page -- see Configuration reference. Headless flags that take an explicit path (--screenshot-after and friends) write exactly where they are told and ignore all of this.

A battmem.nvram or cd32-nvram.bin left in the working directory by an earlier Copperline keeps being used from there -- they hold real game saves, so nothing is moved or abandoned behind your back.

For a self-contained installation, create an empty file named portable.txt beside the Copperline executable (or beside the downloaded .AppImage) and restart Copperline. That folder then becomes the host-data directory, and all of the folders above -- plus gamepad calibration, keyboard mappings, the default WHDLoad library and other per-user host data -- live inside it, so the whole installation moves as one folder. Delete portable.txt to return to the platform location above; Copperline does not move existing files in either direction.

Controller ports

An Amiga has two game ports, and either accepts any controller. Copperline models that: each port carries a device -- mouse, joystick, cd32 pad, analogue paddles, lightpen, or none, and port 1 additionally gamepad-mouse -- set with [input] port1/port2 in the config (or --port1/--port2, or the launcher’s Input tab). The default is the stock wiring, a mouse in port 1 and a joystick in port 2 (a CD32 pad on the CD32 profile). The runtime menu’s Port 1 Device / Port 2 Device items hot-plug a different device live, exactly like swapping the physical plug: the old device’s lines release, and the port’s quadrature counters hold.

The host mouse drives the (lowest-numbered) port with a mouse plugged in and feeds its JOYxDAT counters. Click the display (or press Cmd+G on macOS or Alt+G on Linux/Windows) to capture the host mouse; the same shortcut releases it. The click that takes the capture is a window action and is not passed to the Amiga, so the first click that reaches the guest is the first one aimed at it -- otherwise a single click on a gadget arrives as two, close enough together to read as a double click.

While an overlay panel is open, host cursor motion is not fed to the emulated mouse. In the Debug workspace the inspectors own the keyboard and mouse until you click the display: that click hands input to the Amiga (capturing the mouse when a port has one), and Cmd/Alt+G or a click outside the display hands it back. Entering the Debug workspace while the mouse is captured borrows the cursor, and returning to Play hands the capture back, so a visit to the debugger does not leave the machine uncaptured -- which matters most in fullscreen, where there is no desktop to reach for. An explicit Cmd/Alt+G release settles it the other way: the capture stays off.

Uncaptured, host cursor motion over the display still drives the emulated mouse, and [input] mouse_sensitivity scales it the same way it scales captured motion. At the default setting the factor is 1.0 and the pointer tracks the host cursor one-for-one.

[input] mouse_capture (--mouse-capture, the launcher’s Input tab) changes when the grab is taken: auto grabs whenever the window has the focus and on entering fullscreen, so no host cursor is ever loose over the display, and manual grabs only on the shortcut, leaving display clicks to go straight to the Amiga. See Mouse capture.

Enable Middle to release on the launcher’s Input tab, or set [input] middle_click_release = true, to release capture with the middle mouse button. It defaults to off, so middle click reaches the guest. When enabled, the click that releases capture is consumed.

A USB gamepad drives the emulated digital joystick on whichever port one is plugged into: directions through JOYxDAT, fire through /FIRx, and a second button through POTxY/POTGOR. A cd32 device speaks the CD32 serial button protocol instead, including the red/blue/green/yellow and transport buttons, on either port. An analogue device presents pot resistances on the POTxX/POTxY pins; no live host device maps to it yet -- drive it with --pot-after scripting or the control protocol’s input.analogue.

A lightpen device (alias lightgun) follows the host pointer over the display: wherever the pointer is, the pen’s photodetector is held against that pixel, and Agnus latches the beam position as it sweeps past (readable through VPOSR/VHPOSR while the guest sets BPLCON0 LPEN). A left click over the display presses the pen’s tip switch -- a light gun’s trigger -- which the pen puts on the port’s third-button line (POTxX), since pin 6 is the pulse line itself. Leave the mouse uncaptured: a captured pointer has no position to follow. The pen only reaches Agnus from the port the board wires to its LP input, port 1 on the A1000 and port 2 on every later Amiga; a pen in the other port is logged at start-up. See Port devices for the headless and control-protocol forms.

Ports 3 and 4 are the sockets of the parallel-port multitap, also called the four-player joystick adapter. Set I/O Ports -> Parallel Port -> Device to Multitap (4 joysticks) in the launcher, or use --parallel multitap (the joystick-adapter name also works). Games such as Super Skidmarks, Kick Off 2 and Dyna Blaster read these sockets as two extra joysticks.

For four local USB/Bluetooth controllers, select Joystick for both native ports and use gamepad input mode:

copperline --parallel multitap --port1 joystick --port2 joystick --joystick gamepad

Controllers fill the configured joystick ports in port order. Each has its own state and calibration; unplugging one releases its controls without moving the other controllers between players. The next controller connected fills the vacant slot. The first controller also operates Copperline’s menu. To calibrate another controller, connect it alone while running calibration.

The cursor-key and numeric-keypad mappings fill remaining player slots. Two physical controllers plus the two keyboard mappings can therefore drive all four players. Keyboard input mode reserves the first joystick port for cursor keys, with up to three physical controllers filling the rest. With no pads, cursor keys and numpad retain their usual two-player assignment. Bindings remain editable through Input Mapping....

Scripted --joy-after ... 3/4 and the control protocol’s input.joy address the adapter sockets directly. The libretro core also exposes both sockets, and Netplay can give each socket to a player on another computer.

A gamepad-mouse device is a mouse a gamepad moves as well as the host’s own; the machine still sees one mouse. The d-pad moves the pointer, gathering speed while a direction is held, and the left stick moves it proportionally where the pad has one. Fire is the left button, the second button the right, and mouse_sensitivity scales both hands alike. It is offered on port 1 only. While it is chosen the pad drives no joystick port -- whichever port it would have driven falls to the keyboard until the device is changed back.

Copperline can also emulate the joystick from the host keyboard. There are two explicit input modes, and the active one is always shown by the gamepad / keyboard icon in the status bar (next to the volume control), so a “my keys aren’t working” surprise can be spotted and fixed at a glance:

With joysticks (or pads) in both ports, two connected gamepads drive one each in gamepad mode. With one gamepad, cursor keys drive the other port; with none, the numeric keypad substitutes for the gamepad so two players can share one keyboard. Keyboard mode keeps cursor keys on the first joystick port even when multiple gamepads are connected.

With mice in both ports, the host mouse drives the lower-numbered one and the cursor-key mapping drives the second as an emulated mouse (in keyboard mode; in gamepad mode the second mouse is undriven and the keyboard passes through). The same applies whenever the keyboard-routed port carries a mouse: the mapping’s keys become the pointer.

Click the status-bar icon to flip between them; the menu’s Joystick Input item and Cmd+J on macOS / Alt+J on Linux and Windows do the same. Set the starting mode with [input] joystick in the config (or --joystick MODE, or the launcher’s Input tab).

The primary keyboard mapping is FS-UAE-compatible: cursor keys for directions, and Right Ctrl, Right Alt or Left Ctrl for fire, with Left Alt as the second button (the left-hand fire keys pair naturally with the right-hand arrows, and compact keyboards often lack the right-side modifiers). For CD32 pad buttons, C is red/fire, X is blue, D is green, S is yellow, Return is play/pause, Z is rewind, and A is forward. On a mouse port the same keys drive the pointer: cursor keys move it, the fire keys are the left button, X or Left Alt the right, and D the middle. The second (numpad) mapping is 8/2/4/6 for directions, 0 for fire, . for the second button, and numpad Enter for play. While a mapping owns its keys, they are not sent to the Amiga keyboard.

Those are the defaults; every binding is editable from the menu’s Input Mapping... item (see Input mapping). A held fire button can also be turned into a pulse train with the Autofire item or [input] autofire_hz.

Gamepad calibration

Most pads work with no setup at all: a controller found in the bundled SDL_GameControllerDB (or identified by the platform driver) uses a fixed standard layout. The d-pad and left stick drive the directions; the south face button (A / Cross) is fire / CD32 red, east (B / Circle) is blue, west (X / Square) is green, north (Y / Triangle) is yellow, Start is play/pause, and the left and right shoulders or triggers are reverse and forward. Select/Back and the guide button -- which no emulated control uses -- open the pop-up menu, and Select held quits (both below). Personal SDL mapping strings in the standard SDL_GAMECONTROLLERCONFIG environment variable are honoured too.

Calibration is the per-pad override, and the only path for controllers the database does not cover: push each control when prompted. This records raw axis/button codes and directions, which makes any pad work regardless of database coverage -- including pads with broken database entries -- and handles inverted or odd axis layouts automatically. A saved calibration always wins over the database for its pad.

The gamepad calibration window

The calibration window mid-flow. Skip covers pads without the CD32 extras.

Run it either from the menu (“Calibrate Gamepad...”) -- which ends with a live test of the finished bindings and a Save button that makes them live immediately -- or from the terminal with copperline --calibrate-gamepad. The steps are the four directions, fire (CD32 red), button 2 (CD32 blue), the CD32 green/yellow/play/reverse/forward buttons, an Open menu button, a Quit Copperline hotkey, and finally the four directions again as alternates. Push a control to bind it. To skip a step the pad has no control for, press Skip or hold any control for 0.7 seconds (in the terminal flow, wait five seconds); every step after fire can be skipped, but the four directions and fire cannot.

The alternates are for a pad with both a stick and a d-pad: bind the stick to the first four steps and the d-pad to the alternates (or the other way round) and either steers, as on the standard layout. Each alternate simply ORs with its primary, so a pad with one set of directions skips them and loses nothing. When a direction pair is bound to the two ends of one stick axis, the stick’s deflection is known too, and a gamepad-mouse device on that pad moves the pointer at a speed that follows the stick rather than at the d-pad’s fixed pace.

The Quit hotkey is a host-side control: it never reaches the emulated machine, so any spare pad button (Select, Start, a shoulder button) can carry it without affecting the game. To guard against accidental presses it must be held for about a second and a half -- an on-screen countdown shows the hold in progress, and releasing early cancels it. It works whenever the pad is connected -- even while the keyboard or another device drives the joystick ports, and while the machine is paused or powered off. On the default database layout Select/Back carries it: a tap opens the menu and keeping it held quits, with the countdown drawn over the menu; let go early and the menu simply stays open, where Quit is the last row. A calibrated pad’s Menu button works the same way unless a separate Quit control was bound, which then takes the hold to itself. Skip both steps to leave quitting to the menu row and the keyboard shortcut.

The Menu button is the other host-side control: a press opens the pop-up menu, or closes whatever is up instead -- the menu, an overlay panel, or the Debug workspace’s front inspector. From the menu the pad walks whatever is up, as described under Keyboard and controller navigation above. While the menu or a panel is open the pad stops driving the emulated port, just as the keyboard does. On the default database layout Select/Back and the guide button carry it; a calibration can put it anywhere (or skip it). Held, it doubles as the Quit hotkey, as above.

Once every step is captured, pushing a control tests its binding and holding one hands the panel’s Save and Cancel buttons to the pad, so a calibration can be finished without the mouse.

Calibrations are saved per controller UUID in ~/Documents/Copperline/gamepads.toml (%USERPROFILE%\Documents\Copperline\ on Windows, or beside the executable in portable mode). A calibration recorded by a Copperline version that predates the bundled controller database can resolve a stick direction reversed on a database-covered pad; the log suggests recalibrating when it loads such a file, and recalibrating once fixes it.

Input mapping

The keyboard also stands in for a controller, on two independent mappings so one keyboard can drive a two-player setup (see Controller ports). The menu’s Input Mapping... item edits both.

The input mapping window

Editing the first keyboard mapping, with the Fire row armed for capture.

Pick the mapping with the Controller 1 / Controller 2 tabs, then Set on a row and press the key to bind (Escape cancels that row without closing the panel). Clear unbinds a control entirely, Defaults restores the built-in layouts, and Save writes the map and applies it to the running machine. Closing the panel without saving discards the edits.

A control may hold several keys, and they OR together: fire ships bound to Right Ctrl, Right Alt, Left Ctrl and C, so compact keyboards without the right-hand modifiers still work, and releasing one alias while another is held keeps the button down. Binding a key removes it from wherever it was before -- including from the other mapping -- so the two controllers can never end up fighting over one key.

Saved maps live next to the gamepad calibrations, in ~/Documents/Copperline/keymap.toml (same per-platform locations as above). Deleting the file restores the defaults.