server2 a8cd23546d docs: README, AGENTS.md, test tools in tools/
- README: features, layout, requirements, install, IPC, runtime files, limits
- AGENTS.md: the user's ground rules (branch + approval, never touch real
  players' sound), architecture, measured performance rules, type-check
  and test loop, desktop test driver and its pitfalls, open threads
- tools/: amane-remote.sh and fake_mpris.py, so the test loop doesn't
  depend on the Hermes skill
- .gitignore: the Cargo files amane generates
2026-10-06 15:41:48 +02:00
2026-10-06 03:28:55 +02:00
2026-10-06 03:28:55 +02:00

Magic Island: an Amane media widget

A Dynamic-Island-style media widget for Amane (Rust Wayland shell library), running on Hyprland. It sits as a small pill at the top centre of the screen and opens into a now-playing card.

  • Pill: cover thumbnail, title, 7 live bars from the shown player's own sound (lows left, highs right, growing up and down from the middle), or a pause sign.
  • Card: a still CD of the cover ringed by 40 cava "candles", title and artist, a seekable time bar, previous / play-pause / next.
  • Player switcher ("VIA …" chip): every MPRIS player; picking one pins it, otherwise the island follows whichever plays.
  • Output switcher: moves only the shown player's audio to another device.
  • Per-player volume (scroll the volume chip, click to mute), set on that player's own PulseAudio/PipeWire streams, so it also works for browsers that ignore MPRIS volume.
  • Real 10-band equalizer per player (31 Hz to 16 kHz, ±12 dB): a PipeWire filter-chain per player, with 8 presets (Flat, Bass, Treble, Vocal, Pop, Rock, Jazz, Classic). Curves are saved per player.
  • Background: a diagonal gradient from the cover's own colours, darkened so white text stays readable.
  • Opening animation: the pill fades out, the empty shape grows, then the card fades in. Closing runs backwards. Moving the pointer off the open card closes it.

Layout

src/main.rs        app setup: Fira Code font, the `island` IPC handler, palette from the cover
src/island.rs      the view: pill, card, ring, equalizer, dropdowns, animation, IPC commands
src/sound.rs       per-player volume, mute, output and equalizer (pactl, pw-cli, pipewire)
src/spectrum.rs    the shown player's sound as 24 levels (pw-record | cava)
src/art.rs         cover download (curl) and the palette file
src/parse.rs       pure text parsing with unit tests, no amane dependency
island-eq          saved equalizer curves (a snapshot of ~/.config/amane/island-eq)
tools/             remote test driver and fake MPRIS players, see AGENTS.md
src.before-test/   the original hello-world config, kept as a backup

Requirements

On the desktop that runs the shell:

  • the amane CLI and Rust toolchain (amane compile builds src/)
  • PipeWire with pipewire-pulse: pactl, pw-record, pw-cli, pipewire (filter-chain module)
  • cava, curl
  • the Fira Code font

Install and run

The shell lives in ~/.config/amane/. Copy (or clone) this repo's src/ there, then build and start:

amane compile
~/.cache/amane/project/target/debug/amane-shell

The installed CLI on the current desktop is older than the Amane docs: it doesn't save ~/.cache/amane/amane-shell, so amane run has nothing to start. Run the binary above directly.

Control it

amane ipc call island toggle           # also: open, close
amane ipc call island next             # show the next player
amane ipc call island menu output      # open a dropdown: output | player | close
amane ipc call island preset Rock      # apply an equalizer preset to the shown player
amane ipc call island output <sink>    # move the shown player to a sink (pactl sink name)
amane ipc call island status           # player=<identity> expanded=<bool> menu=<bool>

Example Hyprland keybind:

bind = SUPER, M, exec, amane ipc call island toggle

Runtime files

  • ~/.config/amane/island-eq: one line per player identity, <player>\t<preset or Custom>\t<10 gains in dB>.
  • $XDG_RUNTIME_DIR/magic-island/: downloaded covers, palette-cover, cava.conf, eq-<key>.conf. On tmpfs, gone at logout.
  • Equalizer nodes are named magic_island_eq.<key>. The key is the player's MPRIS bus name without org.mpris.MediaPlayer2., non-alphanumerics as _ (e.g. chromium_instance123).

Known limits

  • The time bar moves in 1 s steps (the MPRIS poll rate).
  • Every slider step starts one pactl or pw-cli process.
  • An equalizer keeps running, and keeps that player routed through its last curve, if the shell stops while the player is open.
  • The candle ring around the CD is still mirrored left against right; the pill's bars are not.
  • Dropdowns have no keyboard navigation.
S
Description
Config for amane
Readme 5.2 MiB
Languages
Rust 94.5%
WGSL 2.3%
Python 2.1%
Shell 1.1%