CopperlineOS timeline engine.
copperd executes small, deterministic “Copper programs” that drive frame-accurate UI/media timelines (e.g., moving layers, triggering events, waiting on fences). In Phase-0 it runs on Linux as a user-space daemon and talks JSON over Unix domain sockets. Later phases add a binary format and FPGA offload.
TL;DR: Think “modern Copper list” for 2025—tiny programs that say when and how to update visual/audio state, with rock-solid timing.
Modern stacks are great at throughput, less great at deterministic, low-latency control. The original Amiga solved this with the Copper and Blitter. copperd brings that idea back as a small service you can script from any language.
- Deterministic: frame/time based execution with hard waits.
- Simple: a dozen ops (WAIT/MOVE/ADD/IRQ/JUMP/FENCE/LOOP…).
- Composable: talks to the compositor (
compositord) and others via message ports. - Scriptable: drive it from shell, Rust, C, Lua, “ARexx-Next”, etc.
- Phase-0 JSON protocol: stable-ish (v0)
- Platform: Linux (Wayland/X11 optional, KMS recommended)
- Language: Rust (stable)
- License: MIT OR Apache-2.0
flowchart LR
app["Apps & Scripts (Rust/C/Lua/ARexx-Next)"];
port["copperd port"];
subgraph Copperd
exe["Executor"];
clk["Clock"];
store["Program Store"];
end
comp["compositord"];
app --> port;
exe --> clk;
exe --> store;
clk --> exe;
exe --> app;
exe --> comp;
comp --> clk;
Text-only fallback (if Mermaid fails)
Apps/Scripts -> copperd port
Executor <-> Clock, Executor -> Program Store
Executor -> Apps (IRQ/events)
Executor -> compositord (reg writes)
compositord -> Clock (vsync ticks)
copperdmaintains programs (loaded by clients), a clock (vsync-paced or high-res timer), and an executor.- It emits events (IRQs) and writes registers exposed by
compositord(e.g.,layer[1].x). - Optional: waits on fences (e.g., Vulkan timeline semaphores) before advancing.
- Program: a list of ops, optionally labeled, executed on a timeline.
- Clock:
vsync(preferred) or microsecond timers. - Registers: named destinations
layer[n].x/y/alpha/z/visibleowned by the compositor. - Events (IRQ): tagged notifications you can subscribe to for telemetry or scripting.
Socket (default): /run/copperline/copperd.sock
Configurable via COPPERD_SOCKET.
{"cmd":"ping"}→{"ok":true,"name":"copperd","version":"0.1.0"}{"cmd":"load","program":<json>}→{"ok":true,"id":42}{"cmd":"start","id":42}→{"ok":true}{"cmd":"stop","id":42}→{"ok":true}{"cmd":"unload","id":42}→{"ok":true}{"cmd":"status","id":42}→{"ok":true,"state":"running","pc":7}{"cmd":"list"}→{"ok":true,"programs":[{"id":42,"state":"running"}]}{"cmd":"subscribe","events":["irq","state"]}→ stream of events on same socket
{"event":"irq","tag":"tick","time_us":12345678,"prog":42}{"event":"state","id":42,"state":"stopped"}
{
"version": 1,
"labels": { "loop": 5 },
"program": [
{ "op": "BIND_LAYER", "id": 1, "surface": "/tmp/sprite.rgba" },
{ "op": "MOVE", "reg": "layer[1].x", "value": 100 },
{ "op": "MOVE", "reg": "layer[1].y", "value": 360 },
{ "op": "LOOP", "count": -1, "label": "loop" },
{ "label": "loop" },
{ "op": "WAIT", "vsync": true },
{ "op": "ADD", "reg": "layer[1].x", "delta": 4 },
{ "op": "IRQ", "tag": "tick" },
{ "op": "JUMP", "label": "loop" }
]
}| Op | Fields | Description |
|---|---|---|
WAIT |
{"vsync":true} or {"us":N} |
Wait for next vsync or N microseconds. |
MOVE |
{"reg":"layer[ID].x","value":INT} |
Set a register value. |
ADD |
{"reg":"layer[ID].x","delta":INT} |
Add delta to a register. |
IRQ |
{"tag":"name"} |
Emit a tagged event. |
JUMP |
{"label":"L"} |
Jump to label. |
LOOP |
{"count":N,"label":"L"} |
Decrement and jump while count>0 (-1 = infinite). |
FENCE |
{"timeline":"vk","value":INT} |
Wait for external fence/timeline value. |
BIND_LAYER* |
{"id":ID,"surface":FD_or_Path} |
Bind a compositor layer to an image/DMABUF. |
* Convenience: expands to compositor messages in Phase-0 (may move to compositord API later).
# Prereqs: Rust stable, libudev, access to /run
git clone https://github.com/CopperlineOS/copperd
cd copperd
cargo build --release
# Run (requires compositord running for vsync/register writes)
RUST_LOG=info ./target/release/copperdOptional env:
COPPERD_SOCKET=/run/copperline/copperd.sockCOPPERD_CLOCK=vsync|monotonic(default:vsyncif available)
Use portctl (from CopperlineOS/tools) or socat:
# Create a minimal program file
cat > /tmp/demo.json <<'JSON'
{ "version":1, "program":[
{"op":"MOVE","reg":"layer[1].x","value":100},
{"op":"MOVE","reg":"layer[1].y","value":360},
{"op":"LOOP","count":-1,"label":"loop"},
{"label":"loop"},
{"op":"WAIT","vsync":true},
{"op":"ADD","reg":"layer[1].x","delta":4},
{"op":"IRQ","tag":"tick"},
{"op":"JUMP","label":"loop"}
]}
JSON
# Load & start
portctl /run/copperline/copperd.sock "$(jq -c '{cmd:"load",program:.}' /tmp/demo.json)"
portctl /run/copperline/copperd.sock '{"cmd":"start","id":1}'Subscribe to events:
portctl /run/copperline/copperd.sock '{"cmd":"subscribe","events":["irq"]}'
# -> {"event":"irq","tag":"tick","time_us":...,"prog":1}Pair this with
compositord’screate_layer/bind_imageto see a sprite slide across your Vulkan scene.
# Toolchain
rustup default stable
rustup component add rustfmt clippy
# Build & test
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo testMinimum Rust: 1.78+ (aim to keep compatibility with latest stable).
- Crates:
copperd-core(VM & ops),copperd-ipc(protocol),copperd-bin(daemon). - Logging:
RUST_LOG=debug(structured logs). - Timing: vsync comes from
compositordevent feed; falls back to high-res monotonic. - Validation: programs are validated on
load(unknown op, bad register, label miss). - Determinism:
WAIT vsyncadvances exactly one frame; microsecond waits useCLOCK_MONOTONICand are clamped to prevent drift.
- v0.1 (Phase-0): JSON protocol, vsync clock, IRQ/events, MOVE/ADD/JUMP/LOOP/WAIT/FENCE, basic perf counters.
- v0.2: Binary program format + zero-copy ring; named timelines; per-program priorities.
- v0.3: Security caps (per-reg write permissions), rate limiting, sandboxing.
- v0.4: FPGA backend for timeline execution; hardware register writes.
See project-wide RFCs in CopperlineOS/rfcs when available.
We welcome issues and PRs!
- Read
CONTRIBUTING.md(coding style, commit messages, review process). - Check good first issue / help wanted labels.
- For protocol changes, open an RFC and link it from your PR.
Code of Conduct: see CODE_OF_CONDUCT.md.
Please report vulnerabilities privately to security@copperline.os (placeholder) or via GitHub’s security advisories. See SECURITY.md.
Dual-licensed under Apache-2.0 OR MIT. You may choose either license.
compositord: Vulkan/KMS compositor with timeline registersblitterd: 2D copy/fill/convert serviceports: message-port protocol & client libsarexx-next: scripting & shell (examples include the sprite demo)
- Copper: tiny timed program controlling display state.
- DMABUF: Linux buffer-sharing primitive used for zero-copy between processes.
- Vsync: display vertical sync; one tick per frame.
- IRQ: event emitted by a program for observers (not a hardware interrupt).