diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4e9205e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,69 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# 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: + +```rust +#[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` 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.