# Get Started

From an empty Rust project to a Glint component rendering on screen.

Glint is a set of `.slint` sources. The crate’s only job is to hand your build script the directory they live in, so that `@glint/...` imports resolve the same way `@lucide` does. Four dependencies, one build script, and the components are yours.

This guide assumes a Rust toolchain and an empty project:

```bash
cargo new my-app
cd my-app
```

## Add the dependencies

Slint is a runtime dependency; the three that produce code — the Slint compiler, Glint, and Glint’s icon peer dependency — are build dependencies.

```toml
[dependencies]
slint = "1.17"

[build-dependencies]
slint-build = "1.17"
# Glint is unreleased: nothing is on crates.io, so depend on the repository.
glint-ui = { git = "https://github.com/thelipe7/glint-ui" }
lucide-slint = "1.30"
```

`lucide-slint` is a peer dependency rather than a bundled one: Glint’s public API references its icon types, so your build has to know where they are. A checkout works just as well as the git URL — `glint-ui = { path = "../glint-ui" }` — and is what to use while the repository is still private.

## Register the libraries in `build.rs`

The Slint compiler resolves `@glint/...` and `@lucide` through library paths. Register both, then compile your interface:

```rust
use std::{collections::HashMap, path::PathBuf};

fn main() {
    let libraries = HashMap::from([
        ("glint".to_string(), glint_ui::lib()),
        ("lucide".to_string(), PathBuf::from(lucide_slint::lib())),
    ]);

    let config = slint_build::CompilerConfiguration::new().with_library_paths(libraries);

    slint_build::compile_with_config("ui/app-window.slint", config)
        .expect("failed to compile the Slint sources");
}
```

The name on the left of each pair is the alias an import writes. Register `glint` under another name and `@glint/components/button.slint` stops resolving.

## Write the interface

Create `ui/app-window.slint`. Import the components you want and `Tokens`, the semantic layer every Glint component reads — a window that paints itself `Tokens.color-background` follows the theme along with everything in it.

The preview below is this exact file, running. Switch the theme or the palette in the header and it follows, because nothing in it names a color.

```slint
import { Button } from "@glint/components/button.slint";
import { Input } from "@glint/components/input.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component AppWindow inherits Window {
    title: "My app";
    min-width: 420px;
    min-height: 220px;
    background: Tokens.color-background;

    in-out property <string> username;
    in property <bool> signing-in: false;
    callback sign-in();

    VerticalLayout {
        padding: 24px;
        spacing: 16px;
        alignment: center;

        Text {
            text: "Sign in";
            color: Tokens.color-foreground;
            font-size: Tokens.typography-h2-size;
            font-weight: Tokens.typography-weight-semibold;
        }

        Input {
            placeholder: "Your username";
            text <=> root.username;
        }

        Button {
            text: "Sign in";
            loading: root.signing-in;
            clicked => { root.sign-in(); }
        }
    }
}
```

Properties and callbacks declared on `AppWindow` are the seam between the interface and your program, and the direction is in the declaration: `in-out property <string> username` is state both sides touch, `in property <bool> signing-in` is state Rust sets and the interface only reads, and `callback sign-in()` is an event Rust handles. Glint’s components carry none of your application’s state — a `Button` fires `clicked`, and what that means is yours.

Import from the barrel instead if you prefer one line:

```slint
import { Button, Input, Tokens } from "@glint/glint.slint";
```

Both resolve to the same sources. Per-component imports compile less, which is worth having in a project with many small `.slint` files.

## Run it

`slint::include_modules!()` brings in what the build script generated: one Rust type per exported component, with a getter and setter per property and an `on_<callback>` for each callback.

```rust
slint::include_modules!();

fn main() -> Result<(), slint::PlatformError> {
    let ui = AppWindow::new()?;

    let handle = ui.as_weak();
    ui.on_sign_in(move || {
        let ui = handle.unwrap();
        println!("signing in as {}", ui.get_username());
    });

    ui.run()
}
```

```bash
cargo run
```

The window that opens is the preview above, in your own app.

## Where to go next

- [Theming](/docs/theming) — theme modes, the built-in palettes, and how to build one of your own.
- [Components](/docs/components) — one page per component, each with a live preview and a generated API reference.

Glint ships a handful of default strings — `Continue`, `Cancel`, `Close`, `Select…`, `Search…` — through `@tr(...)`, so they follow your application’s translations when you set them up. Each one is also a property, so passing already-translated text works without a catalog.
