# Getting started ## Requirements - Rust (edition 2024 toolchain). - Linux with a Wayland compositor. The GPU renderer needs Vulkan-capable drivers; the software renderer needs nothing beyond a compositor. guiduck is not on crates.io yet; depend on it by path or git: ```toml [dependencies] guiduck = { path = "../guiduck/crates/guiduck" } ``` ## Your first app A guiduck application is two files: a **component file** describing the interface, and Rust supplying the logic. Component files live in a `components/` directory under your crate root (the *component search path* — configurable, see below), one component per file, with the file named after the component: `Hello` lives in `components/Hello.gdc`. ```lisp (component Hello (state count i32 :init 0) (handler bump) (container :direction column :padding 16 :gap 12 :background "#ffffff" (text :font-size 18 :text "Clicked {count} times") (button :label "Click me" :width 120 :height 36 :on-click bump))) ``` Reading it top to bottom: the component declares one piece of **state** (`count`, an `i32` starting at 0) and one **handler** name (`bump`). Then comes the widget tree — a column container holding a label and a button. `"Clicked {count} times"` is a **binding**: it reads `count`, so it re-renders whenever `count` changes. `:on-click bump` wires the button's click to the handler. Notice what is *not* there. Nothing says how to lay the column out when the window resizes, nothing repaints the label, and nothing describes a frame. You declare the relationship — this text is that state — and the framework keeps it true. On the Rust side: ```rust use guiduck::core::WidgetTree; guiduck::include_component!(Hello); struct Logic; impl HelloLogic for Logic { fn bump(&mut self, cx: HelloCx) { cx.count.set(cx.count.get_untracked() + 1); } } fn main() { let mut tree = WidgetTree::new(); Hello::mount(&mut tree, None, HelloProps::default(), Logic); guiduck::run("hello", tree).unwrap(); } ``` `include_component!(Hello)` finds `Hello.gdc` on the search path, compiles it at build time, and expands to generated types: - `HelloProps` — one field per declared prop (here: none). - `HelloCx` — what handlers receive: each state as a writable signal, each prop as a read-only signal, each output as an emitter. - `trait HelloLogic` — one method per declared handler. Forgetting or misspelling a handler is a **compile error** at your `impl`. - `struct Hello` with `mount(...)` — builds the widget subtree, installs the bindings, wires the events. `guiduck::run(title, tree)` opens a window and runs the event loop. Closing the window exits. This exact app ships as an example: ```sh cargo run -p guiduck --example hello ``` ## Edit it while it runs Leave it running and change `components/Hello.gdc` — the padding, the label, the whole tree — and save. The window follows, and `count` keeps its value. That is not a separate mode you turned on. `mount` takes the structure from the file when this is a development build and the file is where the build found it, and from the compiled component otherwise, so a shipped binary never looks for it. Your handlers stay compiled Rust either way: what reloads is the *shape*, not the logic, which is why a reload cannot break a type. The two paths are held identical by a differential test suite that replays real input through both, so which one you are running is not something you should be able to tell. If you ever can, that is a bug in guiduck, and `guiduck::testing` is the same oracle so you can say so precisely. ## Choosing a renderer The GPU renderer (vello on wgpu) is the default. Set an environment variable to use the software renderer (tiny-skia) instead — same scene, near-identical pixels: ```sh GUIDUCK_BACKEND=software cargo run -p guiduck --example hello ``` `GUIDUCK_TRACE_FRAMES=1` logs a line per rendered frame to stderr; you will see that an idle guiduck app renders *nothing*. ## The component search path Component names resolve by probing each directory of the search path for `Name.gdc`, first hit wins. The default is a single `components/` directory under the crate root. Override it in Cargo.toml: ```toml [package.metadata.guiduck] component-path = ["components", "src/widgets"] ``` The same path serves `include_component!` and references between components (a capitalized name inside a `.gdc` file — see [the component language](components.md)). Editing any referenced file triggers a rebuild of the components that use it. ## Fonts `WidgetTree::new()` uses your system fonts. For hermetic rendering (tests, reproducible goldens) or bundled fonts, construct the tree with an explicit text context: ```rust use guiduck::core::text::TextContext; let tree = WidgetTree::with_text_context( TextContext::with_extra_fonts([my_font_bytes]), ); ``` ## Where to go next - [The component language](components.md) — everything a `.gdc` file can say. - [Widgets](widgets.md) — the builtin widget vocabulary. - [Writing a widget in Rust](writing-widgets.md) — implementing the `Widget` trait: layout, paint, input, theming, accessibility. - [Widget manifests](widget-manifests.md) — naming your own Rust widgets from a `.gdc` with a `.gdw` file. - [Theming](theming.md) — moving colors and fonts out of components. - [The Rust side](rust-api.md) — generated code in detail, signals, hot reload, and skipping `.gdc` entirely.