Skip to content

CopperlineOS/copperd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

copperd

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.


Why it exists

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.

Status

  • Phase-0 JSON protocol: stable-ish (v0)
  • Platform: Linux (Wayland/X11 optional, KMS recommended)
  • Language: Rust (stable)
  • License: MIT OR Apache-2.0

Architecture (Phase-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;
Loading
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)
  • copperd maintains 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.

Concepts

  • 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/visible owned by the compositor.
  • Events (IRQ): tagged notifications you can subscribe to for telemetry or scripting.

Protocol (Phase-0 JSON, v0)

Socket (default): /run/copperline/copperd.sock
Configurable via COPPERD_SOCKET.

Client → copperd

  • {"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

Events (server → client)

  • {"event":"irq","tag":"tick","time_us":12345678,"prog":42}
  • {"event":"state","id":42,"state":"stopped"}

Program format (JSON, v0)

{
  "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" }
  ]
}

Supported ops

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).


Quick start

1) Build & run

# 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/copperd

Optional env:

  • COPPERD_SOCKET=/run/copperline/copperd.sock
  • COPPERD_CLOCK=vsync|monotonic (default: vsync if available)

2) Send a program

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’s create_layer/bind_image to see a sprite slide across your Vulkan scene.


Building from source

# Toolchain
rustup default stable
rustup component add rustfmt clippy

# Build & test
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test

Minimum Rust: 1.78+ (aim to keep compatibility with latest stable).


Development guide

  • Crates: copperd-core (VM & ops), copperd-ipc (protocol), copperd-bin (daemon).
  • Logging: RUST_LOG=debug (structured logs).
  • Timing: vsync comes from compositord event feed; falls back to high-res monotonic.
  • Validation: programs are validated on load (unknown op, bad register, label miss).
  • Determinism: WAIT vsync advances exactly one frame; microsecond waits use CLOCK_MONOTONIC and are clamped to prevent drift.

Roadmap

  • 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.


Contributing

We welcome issues and PRs!

  1. Read CONTRIBUTING.md (coding style, commit messages, review process).
  2. Check good first issue / help wanted labels.
  3. For protocol changes, open an RFC and link it from your PR.

Code of Conduct: see CODE_OF_CONDUCT.md.


Security

Please report vulnerabilities privately to security@copperline.os (placeholder) or via GitHub’s security advisories. See SECURITY.md.


License

Dual-licensed under Apache-2.0 OR MIT. You may choose either license.


See also

  • compositord: Vulkan/KMS compositor with timeline registers
  • blitterd: 2D copy/fill/convert service
  • ports: message-port protocol & client libs
  • arexx-next: scripting & shell (examples include the sprite demo)

Glossary

  • 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).

About

timeline engine

Resources

License

Unknown and 2 other licenses found

Licenses found

Unknown
LICENSE
Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published