Skip to content
zoir-devPublic

About

A Wayland compositor and desktop shell in Rust. The compositor owns the motion: springs, not durations. Battery is an architectural constraint.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

63 Commits

Folders and files

Repository files navigation

ZaytunOS

A Wayland compositor and desktop shell in Rust, built on Smithay.

Early. It runs, it draws, and a lot is missing — see Where it is.


What makes it different

The compositor owns the motion. Nothing animates itself. A window's arrival, a panel opening, a drag settling — all of it is sampled in the compositor, from one timeline. An application that wedges cannot stutter the desktop around it. macOS gets this property through Core Animation's render server; Wayland hands it to us for free, because the compositor already holds the buffers.

Physics, not durations. There are no easing curves. Every motion is a damped harmonic oscillator, solved analytically — position and velocity at any t in closed form, no integration. That is what makes a motion interruptible: a panel caught halfway closed carries its velocity into the reversal instead of restarting from standstill.

The vocabulary is three rhythms and three characters, and nothing else:

Preset::new(rhythm::HALF, character::SMOOTH)

A literal number handed to an animation is a bug. The numbers live in lib/motion/src/tokens.rs and nowhere else.

Battery is an architectural constraint, not a feature. The event loop sleeps. A still desktop costs zero wakeups. Every spring pins to its target when it settles and drops out of the frame loop — and "settles" means can no longer be seen, in pixels, not in a unit interval. Getting that wrong once drew 13,304 identical frames in 0.4 seconds.

The shell lives inside the compositor. The bar and its calendar are not Wayland clients. No per-frame IPC, no buffer uploads, no protocol — the shell asks the motion engine for physics by calling it. The cost is isolation, paid deliberately: shell drawing runs inside catch_unwind, so a panic drops a frame rather than the session.

Drawing is signed distance fields. A rounded rectangle is a formula, exact at any radius. A shadow is the closed form of a Gaussian convolved with that rectangle — four samples, and the cost does not depend on the blur radius. The same shadow on the CPU was 56% of a frame.


Where it is

Working:

  • Wayland compositor: xdg-shell, wlr-layer-shell, both winit (nested) and udev/DRM (bare metal) backends
  • Window motion: placement, 1:1 drag, physics on release, arrival
  • A frame clock that predicts presentation time from real vblanks
  • GPU drawing layer: SDF shapes and shadows, a glyph atlas, offscreen backing stores
  • A control library: button, switch, slider, popover, calendar
  • A bar with a calendar popover
  • Wallpaper as a client

Not there yet:

  • Dock
  • A live clock (the bar's is a placeholder)
  • Calendar interaction (the hit testing exists; the pointer is not wired)
  • Icons
  • Window decorations, tiling, workspaces
  • Multi-monitor (the architecture is per-screen; the container is not)
  • XWayland

Running it

./dev-run.sh              # nested in your current session, with a terminal
./dev-run.sh foot         # or another client
./vm-run.sh               # on DRM, in a VM

Development switches:

ZAYTUN_SLOWMO=10 every motion, ten times slower — the only way to judge a spring
ZAYTUN_SAMPLE=now sample motion at now instead of the predicted vblank (A/B for micro-judder)
ZAYTUN_PROBE=/tmp/bar.ppm read a shell surface back off the GPU and write it out
ZAYTUN_DEV=1 freeze all motion at its end state — deterministic frames for pixel diffs

RUST_LOG=comp=debug gives per-frame timing.


Layout

comp/           the compositor: scene, input, backends, frame clock
  src/shell.rs  the bar and its popover — inside this process
lib/motion/     springs, and the token vocabulary
lib/canvas/     GPU drawing: SDF shapes, shadows, glyph atlas
lib/ui/         controls: button, switch, slider, popover, calendar
lib/tokens/     spacing, radii, type ramp, shadow steps
lib/color/      the palette, by role
shell/wall/     wallpaper client

The v1 branch holds the first traversal — a working compositor with both backends and a pixel-diff stand. This one is the deliberate second pass.


Design notes

The reasoning — the Motion Law, the token codex, the compositor architecture — lives in a sibling directory (zaytun-db) and is written in Uzbek.

The English record is in the code. Comments here carry why, not what, and the commit messages are long on purpose: git log is the first document. If you want to know why the shadow is not a blur, why the shell is not a client, or why sampling at now is a bug, it is written down at the place it matters.


Contributing

Issues and PRs welcome. Two things worth knowing before you write code:

  1. No bare numbers in design or motion. A spacing, a radius, a response time — it belongs in lib/tokens or lib/motion/tokens.rs, named.
  2. Model and presentation are separate. Input, layout and hit testing read where a thing is. Animations only change how it is drawn. A click during an animation must land where the user aimed.

Both rules are load-bearing, and breaking either produces bugs that look like something else entirely.


Licence

GPL-3.0-or-later.

About

A Wayland compositor and desktop shell in Rust. The compositor owns the motion: springs, not durations. Battery is an architectural constraint.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages