A Gleam TUI framework. TEA+Erlang
  • Gleam 99.4%
  • Nix 0.6%
Find a file
bgw c1719f2a28
fix: add word splitting in text wrap
infinite loop occured when a single word would exceed the width of the
viewport

now split word when a single word would exceed the width of the viewport
2026-04-19 12:12:45 +01:00
examples chore(deps): update gleam_stdlib and gleeunit 2026-04-19 11:40:05 +01:00
src fix: add word splitting in text wrap 2026-04-19 12:12:45 +01:00
test feat: add zipper module pending input handling rewrite 2026-04-15 21:03:46 +01:00
.gitignore docs(examples): move all examples into a single project 2025-07-23 03:35:44 +01:00
CHANGELOG.md feat(style): add bright terminal colors 2026-04-18 16:47:01 +01:00
flake.lock flake.lock: Update 2026-03-26 23:42:48 +00:00
flake.nix refactor: remove all ffi/nif code 2025-04-03 22:38:27 +01:00
gleam.toml v1.3.0 2025-08-13 21:59:49 +01:00
LICENSE docs: add MIT license 2025-04-18 00:55:03 +01:00
manifest.toml chore(deps): update gleam_stdlib and gleeunit 2026-04-19 11:40:05 +01:00
README.md docs(README): remove unnecessary pub exports 2025-07-31 16:48:45 +01:00

Shore

Package Version Hex Docs

Shore is a TUI (terminal user interface) framework following The Elm Architecture for Gleam.

It is purely focused on the erlang runtime.

Shore requires erlang/otp 28 at minimum.

Further documentation can be found at https://hexdocs.pm/shore.

Example

Check out the examples directory for more information and showcase of features such as commands, layout and styling

gleam add shore@1
import gleam/erlang/process
import gleam/int
import gleam/option.{Some}
import shore
import shore/key
import shore/layout
import shore/style
import shore/ui

// MAIN

pub fn main() {
  let exit = process.new_subject()
  let assert Ok(_actor) =
    shore.spec(
      init:,
      update:,
      view:,
      exit:,
      keybinds: shore.default_keybinds(),
      redraw: shore.on_timer(16),
    )
    |> shore.start
  exit |> process.receive_forever
}

// MODEL

type Model {
  Model(counter: Int)
}

fn init() -> #(Model, List(fn() -> Msg)) {
  let model = Model(counter: 0)
  let cmds = []
  #(model, cmds)
}

// UPDATE

type Msg {
  Increment
  Decrement
}

fn update(model: Model, msg: Msg) -> #(Model, List(fn() -> Msg)) {
  case msg {
    Increment -> #(Model(counter: model.counter + 1), [])
    Decrement -> #(Model(counter: model.counter - 1), [])
  }
}

// VIEW

fn view(model: Model) -> shore.Node(Msg) {
  ui.box(
    [
      ui.text(
        "keybinds

i: increments
d: decrements
ctrl+x: exits
      ",
      ),
      ui.text(int.to_string(model.counter)),
      ui.br(),
      ui.row([
        ui.button("increment", key.Char("i"), Increment),
        ui.button("decrement", key.Char("d"), Decrement),
      ]),
    ],
    Some("counter"),
  )
  |> ui.align(style.Center, _)
  |> layout.center(style.Px(50), style.Px(12))
}

Terminal Support

The following terminal emulators have been tested and are generally supported. It is expected any modern terminal emulator should work.

Shore makes use of the terminal CSI 2026 Synchronized Output to aid smoothing the redrawing experience and also alt buffers.

  • alacritty
  • ghostty
  • wezterm
  • kitty
  • iterm2
  • warp
  • konsole
  • gnome-console
  • st
  • windows terminal

Terminal Known Issues

  • Terminal.App (layout issues?)
  • tmux with alacritty (flickering under certain conditions, debug help wanted!)