LiveView Muscle Memory in a 60 FPS Terminal Renderer

repoelixirotptuiterminal-uiliveviewflexboxagent-interfaces

Courgette’s mount/render/handle_event lifecycle is a strong reference for stateful, keyboard-first operator UIs in Joel’s terminal-heavy system tooling.

Courgette is a clean idea: take the Phoenix LiveView mental model (mount, render, handle_event) and run it straight in the terminal on Elixir + OTP. It’s still marked work-in-progress, but the shape is already compelling because the component model is familiar and the target is different.

The clever bit is the rendering stack. It goes from element tree → layout → paint buffer → diff → ANSI, with double buffering and frame batching around ~60 FPS. Layout is Flexbox via a port of taffy, and input support includes full keyboard, mouse, focus, paste, and resize events. So this isn’t just “draw text” — it’s a serious terminal UI runtime.

Useful for Joel’s world even without adopting Elixir. The patterns map to how we think about stateful control surfaces in joelclaw: event-driven updates, minimal redraw, and deterministic tests for behavior. The headless component test helpers and explicit focus management are the pieces worth stealing first, especially for terminal-facing ops surfaces tied to system events.

Key Ideas

  • Courgette applies Phoenix LiveView-style lifecycle callbacks (mount, render, handle_event) to terminal apps instead of browser apps.
  • Stateful components are process-backed with GenServer, while stateless function components stay lightweight and composable.
  • Layout uses a terminal-adapted taffy engine, bringing real Flexbox semantics (flex_grow, justify_content, align_items, etc.) to TUIs.
  • Rendering is incremental and double-buffered, emitting minimal ANSI escape sequences instead of repainting the full screen every tick.
  • Input support is unusually complete for early-stage TUI frameworks, including Kitty keyboard protocol, mouse events, bracketed paste, focus tracking, and resize handling.
  • Semantic theme tokens (primary, danger, muted) are built in, which nudges apps toward consistent UI systems instead of hard-coded color soup.
  • Headless test helpers make full lifecycle tests deterministic, which matters for agent/operator interfaces where regressions hide in event handling and focus logic.