Files
ruin/CLAUDE.md
2026-03-22 13:31:29 -04:00

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

# Build the entire workspace
cargo build

# Run a specific example (all live in lib/ruin_app/example/)
cargo run --example 00_bootstrap_and_counter -p ruin_app
cargo run --example 01_async_data_and_effects -p ruin_app
cargo run --example 03_fine_grained_list -p ruin_app

# Run tests
cargo test

# Run tests for a specific crate
cargo test -p ruin_reactivity

Architecture

RUIN is a layered, single-threaded reactive UI framework targeting Linux/Wayland. The layers build on each other strictly from bottom to top:

Layer Stack

ruin-runtime (lib/runtime/) — Linux x86_64 async runtime. io_uring-backed I/O, single-threaded event loop with JavaScript-style microtask/macrotask scheduling. Entry points are #[ruin_runtime::async_main] and #[ruin_runtime::main] macros. Provides fs::*, net::*, time::*, channel::* (mpsc, oneshot).

ruin_reactivity (lib/reactivity/) — Fine-grained reactive graph. Key primitives: Cell (root signal), Thunk/Memo (derived values), Effect (side-effects), Event (subscriptions). The reactor is single-threaded and schedules deferred jobs via the runtime's microtask queue. No async inside the reactive graph — async work feeds results in via state updates at the edges.

ruin_ui (lib/ui/) — Platform/renderer-agnostic UI substrate. Intentionally uses explicit Rust construction (no proc-macros at this layer). Key modules: layout.rs (flexbox-style layout engine), text.rs (cosmic-text integration), scene.rs (display list/scene graph), interaction.rs (pointer/keyboard routing), platform.rs (platform abstraction traits), tree.rs (element tree and styling).

ruin_ui_platform_wayland (lib/ui_platform_wayland/) — Wayland backend. Entry point: start_wayland_ui(). Handles window creation, input events, clipboard via wayland-client + wgpu renderer.

ruin_ui_renderer_wgpu (lib/ui_renderer_wgpu/) — GPU rendering via wgpu. Text rasterization with cosmic-text.

ruin_app (lib/ruin_app/) — High-level app/runtime glue. This is the crate most application code targets. Exports App, Window, Mountable, and the proc-macros #[component], view!, #[context_provider]. Intentionally low-level — it is the expansion target for proc-macros, not the final ergonomic API.

ruin_app_proc_macros (lib/ruin_app_proc_macros/) — Procedural macros: #[component] wraps component functions, view! is the DSL for UI tree construction, #[context_provider] injects context values.

Application Model

A typical app entry point:

#[ruin_runtime::async_main]
async fn main() -> ruin_app::Result<()> {
    App::new()
        .window(Window::new().title("My App").app_id("dev.ruin.myapp").size(960.0, 640.0))
        .mount(view! { MyRootComponent() {} })
        .run()
        .await
}

Components use #[component] and return impl IntoView. Reactive state uses use_signal, use_memo, use_effect. Layout uses view! with primitives like column, row, block, text, button.

The aspirational_examples/ Directory

These files (00_ through 07_) define the desired future API — a cleaner ruin::prelude::* surface with shorter syntax like use_signal instead of use_signal(|| ...). They are not wired into the build. The corresponding ported implementations live in lib/ruin_app/example/ and represent the current actual API. When porting an aspirational example, the goal is to make the example/ version match the aspirational design as closely as the current framework allows.

Key Design Constraints

  • The reactive graph is strictly single-threaded — never share reactive values across threads.
  • Signal<T> must be .clone()d before being moved into closures (it's Rc-based, not Arc).
  • All float layout values are f32 (e.g., gap = 8.0, not gap = 8).
  • ruin_app is the integration target; avoid bypassing it to call ruin_ui or ruin_reactivity directly in application code unless writing low-level infrastructure.