# star A **native Lightspeed** LiveView app on [Mist](https://hexdocs.pm/mist) (port **8080**). Server-owned state, typed events, verified routes, and the Lightspeed wire protocol — no Datastar. ## What you get | Piece | Role | |-------|------| | `star/live.gleam` | `stateful.LifecycleComponent` — model, msgs, routes, render | | `star/ws.gleam` | Live session host — protocol Event → handle → Diff patch | | `star.gleam` | Mist HTTP + `/live` WebSocket + `endpoint` | | `/assets/lightspeed.js` | Minimal browser runtime (`data-ls-click` → Event frames) | ### UI (all server-driven) - Counter (`inc` / `dec` / `reset`) - Toggle panel - Greeting form - Notes (save / delete) ## Run ```sh # enter the flake dev shell, then run nix develop gleam run # or one-shot from the repo root nix run ``` Open **http://localhost:8080/** ## Routes | Path | What | |------|------| | `GET /` | LiveView shell (`data-ls-*` + initial HTML) | | `WS /live` | Lightspeed protocol (`hello` / `event` / `diff` / `ack`) | | `GET /health` | Controller route (`ok`) | | `GET /assets/app.css` | Styles | | `GET /assets/lightspeed.js` | Client runtime | ## Idioms used ```gleam // verified route + live controller endpoint.new(contract.allow_all("owner-1"), "/live") |> endpoint.get_live(index, "star_view", fn(_conn) { initial_body() }) // stateful component (mount / handle / render / routes) stateful.LifecycleComponent( mount: mount, update: update_assigns, handle: handle, render: render, routes: routes(), ) // typed event decoding stateful.route("greet", fn(e) { event.decode_form(e, "greet", fn(data) { ... }) }) ``` Client hooks are LiveView-style attributes: ```html ``` ## Development ```sh gleam test ```