# Five-Minute Tutorial

No MoonBit knowledge needed — programming experience in any language is enough. This tutorial builds a desktop app from scratch: a window, a button, and a counter that refreshes automatically on every click.

## 1. Install the toolchain (once)

**MoonBit toolchain**:

```sh
# Linux / macOS
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
# Windows (PowerShell)
irm https://cli.moonbitlang.com/install/powershell.ps1 | iex
```

<details>
<summary>Linux (Ubuntu 24.04) environment setup</summary>

You need build-essential (gcc / g++ / make), CMake, pkg-config, plus the development packages for GTK3 / Pango / FontConfig / X11 / WebKit2GTK:

```sh
sudo apt install build-essential cmake pkg-config \
  libgtk-3-dev libpango1.0-dev libfontconfig1-dev libx11-dev libwebkit2gtk-4.1-dev
```

If a runtime error complains about missing GTK libraries, this apt list is most likely incomplete.

</details>

<details>
<summary>Windows (10/11, x64) environment setup</summary>

You need Python 3, MoonBit, CMake, and the MSVC C++ toolchain (including ATL); when moon compiles native code on Windows it looks for `cl` on PATH, so run from the "x64 Native Tools Command Prompt for VS 2022", or call `vcvars64.bat` first:

```powershell
irm https://cli.moonbitlang.com/install/powershell.ps1 | iex            # MoonBit
winget install Kitware.CMake
winget install Microsoft.VisualStudio.2022.BuildTools -e --override "--quiet --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
# add ATL:
Start-Process -FilePath 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\setup.exe' -ArgumentList 'modify','--installPath','"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"','--add','Microsoft.VisualStudio.Component.VC.ATL','--quiet','--norestart' -Verb RunAs -Wait
```

</details>

## 2. Create the project

```sh
moon new my_app
cd my_app
moon add NoahLiu/moonbit-libyue
```

The project generated by `moon new` needs three manual adjustments:

- **`moon.mod`: change `preferred_target = "wasm"` to `"native"`** — this library goes through native FFI and supports only the native backend.

- **Rename the entry file: `my_app.mbt` -> `main.mbt`** — the current moon only recognizes a file named `main.mbt` as the program entry; the template's default file name yields `Missing main function`.

- **Replace the whole `moon.pkg` with** (note this is moon's DSL format, not JSON):

  ```
  import {
    "NoahLiu/moonbit-libyue/yue",
  }

  options(
    "is-main": true,
  )
  ```

  `import` lets your code reach the component library via `@yue.*`; `is-main` declares this package as an executable entry.

## 3. The first window

Replace `main.mbt` entirely with:

```moonbit
fn main {
  if !@yue.initialize() {
    return
  }
  let clicks = @yue.Signal::new(0)
  let _ = @yue.mount_window(
    [
      @yue.label("Hello, MoonBit + libyue!", style=[("margin", 20.0)]),
      @yue.button("Click me", on_click=fn() { clicks.update(fn(n) { n + 1 }) }),
      @yue.bind(clicks, fn(n) { "Clicked \{n} times" }),
      @yue.button("Quit", on_click=fn() { @yue.quit() }),
    ],
    title="Tutorial example",
    size=Some((360.0, 220.0)),
    center=true,
    on_close=fn(_w) { @yue.quit() },
  )
  @yue.run()
}
```

```sh
moon run .
```

A window appears: a label and a button; click the button and the "Clicked N times" line in the middle increments itself — this is **signal reactivity**: when state changes, bound spots refresh automatically, with no "update the text on click" glue code. `mount_window` takes an array of nodes that **declaratively** describes the UI; the `label`/`button` styles can be swapped for the component library's themed widgets at any time (see "Next steps").

## 4. MoonBit syntax in five rows (only what the code above uses)

| Syntax | Meaning |
|---|---|
| `fn main { ... }` | program entry |
| `if !cond { return }` | early return; `!` is logical not |
| `let clicks = ...` | immutable binding (mutable is `let mut`; not needed in this example) |
| `fn(n) { n + 1 }` | anonymous function (lambda), passed as a callback |
| `on_click=fn() { ... }` | named argument: parameters with defaults are passed by name |
| `"Clicked \{n} times"` | string interpolation; `\{expression}` embeds any value |
| `Some((360.0, 220.0))` | the "has a value" form of an optional; `None` is the absence |

**Learning MoonBit systematically**: the official [Chinese tutorial](https://docs.moonbitlang.com/zh-cn/latest/tutorial/index.html) / [English tutorial](https://docs.moonbitlang.com/en/latest/tutorial/index.html); if you prefer interactive learning-by-playing, the official [Tour of MoonBit](https://tour.moonbitlang.com) walks lesson by lesson in the browser.

## 5. Next steps

With the first app running, pick a path by goal:

**Want it to look good** — reskin in one line, light/dark follows the system automatically:

```moonbit
@yue.theme_apply({ ..@yue.default_theme(), primary: "#1E4FA3" })
```

Customization items like the primary color, corners, and dark mode are in the "Theme" section of [components-ui.md](components-ui.md); swapping `label`/`button` for the component library's themed widgets (`label_t`/`button_t`) is in the same document.

**Want something to copy** — the demo board is the material library:

```sh
git clone https://github.com/lb091188/moonbit-libyue && cd moonbit-libyue
moon run examples/showcase    # 15 pages: basic / form / navigation / data display / feedback / events & layout / native widgets / system integration...
```

Pick a page from the left menu and write along on the right; each page's source is its own file (`examples/showcase/pages_*.mbt`) — copy and adapt. To start smaller: `moon run examples/hello` (original widgets) and `moon run examples/hello-themed` (themed).

**Want to learn systematically** — three documents, three facets:

- [declarative.md](declarative.md): describing UI with the node tree (`Node`/`mount`) and binding state with `Store`/`Signal` — the click counter in section 3 of this tutorial is its minimal form
- [layout.md](layout.md): the full set of style keys (flex/padding/margin...); both `set_style` and the style parameter of `X::make` speak this key set
- [components.md](components.md): parameters and methods for every widget, in both setter and `X::make` styles

**Running into problems** — [adaptation.md](adaptation.md) records field-tested pitfalls and root causes per platform; for the tray design see [tray.md](tray.md).

## 6. A note for library contributors

This library started from a simple idea (the full story in [aboutlibyue.md](aboutlibyue.md)): writing native desktop apps in MoonBit. It now covers most of the widgets in libyue's C++ documentation, but much remains worth doing:

- **Platform compatibility**: the mainline verification so far is Ubuntu (XFCE/GNOME/KDE) and Windows; macOS has CI builds only, no real machine — any issue you hit on a mac is valuable input.
- **Widgets and capabilities**: entries in the libyue documentation not yet wrapped, and per-platform adaptation pitfalls — all welcome, starting from an issue.
- **Docs and examples**: the tutorial, the component docs, and every page of the demo board welcome improvements.

No barrier to joining: open an issue describing the problem or idea, or send a PR directly. Before starting, remember only three rules — `moon check && moon test` with zero errors and zero warnings before committing, write field-tested pitfalls together with their fixes into [adaptation.md](adaptation.md), and commit one cohesive change per batch. The full process (FFI conventions for adding widgets, native-layer releases) is in the repo-root [AGENTS.md](../AGENTS.md).
