Skip to main content

Build a reactive app

A Lux app is one file: structure, style, logic, and state in a single syntax. No HTML, no CSS files, no component framework to install.

1. Create a project

lux new counter
cd counter

2. Write the app

app Counter:
    count = signal(0)

    view:
        column gap=16 padding=24:
            text "Count: {count}" size=24
            row gap=8:
                button "+" on:click -> count.update(n -> n + 1)
                button "-" on:click -> count.update(n -> n - 1)
            text "{energy.total()} J" color=gray size=12

The pieces:

  • signal(0) creates a reactive value. Reading it inside the view registers a dependency; writing it invalidates exactly the nodes that read it.
  • view: is a declarative tree — elements by name, styled by properties, composed by indentation. It compiles to a virtual DOM with O(n) keyed diffing.
  • on:click -> … wires an event to an update. No addEventListener, no this.
  • {energy.total()} — the app can read its own meter.

3. Develop with hot reload

lux dev        # JIT dev server on port 3000

lux dev compiles through Cranelift into executable memory and hot-swaps on file change.

4. Ship it

lux build --wasm --release

A complete application — reactive runtime, VDOM, CSS engine, and the standard library modules it uses — compiles to a WebAssembly binary around 398 KB. The browser instantiates it directly: no parsing, no JIT warmup, no bundler.

Derived state and effects follow the same model when you need them:

total = memo(items.map(i -> i.price) |> sum())

effect:
    print("total changed: {total}")

Try the counter in the playground, or read the reactive-state section of the spec.