# \[ANN\] Tachikoma.jl — A terminal UI framework for Julia

**URL:** <https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878>\
**Category:** Package Announcements\
**Tags:** announcement, terminal, tooling\
**Created:** [February 27, 2026, 3:37am UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878 "2026-02-27T03:37:39Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 3:37am UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/1 "2026-02-27T03:37:39Z")

</div>

Tachikoma.jl is a pure-Julia framework for building rich, interactive terminal applications. It uses an Elm-inspired `Model`/`update!`/`view` architecture with a 60fps event loop, double-buffered rendering, 30+ composable widgets, and built-in recording/export.

**GitHub:** [github.com/kahliburke/Tachikoma.jl](https://github.com/kahliburke/Tachikoma.jl)  
**Docs:** [kahliburke.github.io/Tachikoma.jl](https://kahliburke.github.io/Tachikoma.jl/dev/)

![hero demo](https://global.discourse-cdn.com/julialang/original/3X/5/4/543c1129fb6f7ee60f2e41a8134ba190df66c26a.gif)

## Install

```julia
using Pkg
Pkg.add("Tachikoma")

```

Requires Julia 1.12+.

## What’s in the box

**Architecture** — Define a `Model` struct, write `update!` for events, write `view` to render. The framework handles the event loop, frame pacing, and diff-based terminal output.

**30+ widgets** — Text inputs, text areas, code editor with syntax highlighting, data tables with column resize/sort, forms with validation, tree views, charts, sparklines, calendars, modals, dropdowns, markdown viewer, and more.

**Constraint layouts** — `Fixed`, `Fill`, `Percent`, `Min`, `Max`, and `Ratio` constraints with nested horizontal/vertical splits. Draggable resizable pane borders with layout persistence via Preferences.jl.

**Animation** — Tweens with 10 easing functions, physics-based springs with `retarget!`, timeline composition (`sequence`, `stagger`, `parallel`), and organic effects (`pulse`, `breathe`, `shimmer`, `jitter`, `flicker`, `drift`).

**Graphics** — Three rendering backends: Braille dots (2x4 per cell), quadrant blocks (2x2), and pixel rendering via Kitty or sixel protocol (16x32 per cell). Vector drawing API with lines, arcs, circles, and filled shapes.

**11 themes** — Cyberpunk, retro, and classic palettes (Kokaku, Esper, Motoko, Kaneda, Neuromancer, Catppuccin, Solarized, Dracula, Outrun, Zenburn, Iceberg) with hot-swap switching at runtime.

**Async tasks** — `spawn_task!` / `TaskQueue` for background work that delivers results back to the main thread as events, preserving the single-threaded Elm architecture. Cancel tokens, timers, and repeat scheduling.

**Recording & export** — Live recording via `Ctrl+R`, headless `record_app()` / `record_widget()` for CI/docs, native `.tach` format with Zstd compression, export to SVG and GIF.

**Testing** — `TestBackend` for headless widget rendering with `char_at()`, `style_at()`, `row_text()`, `find_text()` inspection APIs.

## Quick example

A Game of Life in ~30 lines:

```julia
using Tachikoma

@kwdef mutable struct Life <: Model
    quit::Bool = false
    grid::Matrix{Bool} = rand(24, 80) .< 0.25
end

Tachikoma.should_quit(m::Life) = m.quit
function Tachikoma.update!(m::Life, e::KeyEvent)
    e.key == :escape && (m.quit = true)
end

function Tachikoma.view(m::Life, f::Frame)
    h, w = size(m.grid)
    g = m.grid
    nc = [sum(g[mod1(i+di,h), mod1(j+dj,w)]
          for di in -1:1, dj in -1:1) - g[i,j]
          for i in 1:h, j in 1:w]
    g .= (nc .== 3) .| (g .& (nc .== 2))
    a, buf = f.area, f.buffer
    for i in 1:min(h, a.height), j in 1:min(w, a.width)
        g[i,j] || continue
        set_char!(buf, a.x+j-1, a.y+i-1, '█',
            tstyle([:primary,:accent,:success,:warning,:error][clamp(nc[i,j],1,5)]))
    end
end

app(Life())

```

## Gallery

| | |
| --- | --- |
| **Dashboard** | **Form with Validation** |
| ![dashboard](https://global.discourse-cdn.com/julialang/original/3X/1/4/14078849e05aa4ced36ddcd17217eae5c3594df7.gif) | ![form](https://global.discourse-cdn.com/julialang/original/3X/a/2/a2a2f3faa5326bccfeaf7f5084a5c5e356cf4765.gif) |
| **Animation Showcase** | **Todo List** |
| ![anim](https://global.discourse-cdn.com/julialang/original/3X/a/0/a01fb8d5499baa0acc88c2eb6b776109207fbd63.gif) | ![todo](https://global.discourse-cdn.com/julialang/original/3X/f/3/f3d26d2ab94b7083db4c27b3ab96ca0b13b4fa6a.gif) |
| **GitHub PR Viewer** | **Animated Backgrounds** |
| ![prs](https://global.discourse-cdn.com/julialang/original/3X/0/5/052facc53005606651a49da72dde2962f51340b8.gif) | ![dotwave](https://global.discourse-cdn.com/julialang/original/3X/6/0/602bb2090f638ce7cc7bc10dddcacedf764c1bf0.gif) |

## Comparisons

Tachikoma is designed full-screen interactive applications with their own event loop, like what you’d build with Textual (Python), Ratatui (Rust), or Bubbletea (Go). If you want to build a dashboard, data explorer, or game that takes over the terminal, that’s what Tachikoma is for.

## Tutorials

The docs include step-by-step tutorials that build complete apps:

- [Getting Started](https://kahliburke.github.io/Tachikoma.jl/dev/getting-started) — A dice game covering model, input, layout, and widgets
- [Dashboard](https://kahliburke.github.io/Tachikoma.jl/dev/tutorials/dashboard) — Multi-panel layout with charts, tables, and live data
- [Todo List](https://kahliburke.github.io/Tachikoma.jl/dev/tutorials/todo-list) — CRUD app with forms, validation, and modal dialogs
- [GitHub PRs](https://kahliburke.github.io/Tachikoma.jl/dev/tutorials/github-prs) — Async data fetching with DataTable and markdown rendering
- [Animation Showcase](https://kahliburke.github.io/Tachikoma.jl/dev/tutorials/animation-showcase) — Tweens, springs, timelines, and organic effects

Feedback, issues, and contributions welcome at [github.com/kahliburke/Tachikoma.jl](https://github.com/kahliburke/Tachikoma.jl).

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 2:58pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/2 "2026-02-27T14:58:20Z")

</div>

Oops! I realized that documentation assets were causing the repo to be large when cloning it, that’s been fixed now!

---

<div class="post-metadata">

**Author:** ![langestefan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/langestefan/32/207923_2.png) [@langestefan](https://discourse.julialang.org/u/langestefan)\
**Post date:** [February 27, 2026, 3:02pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/3 "2026-02-27T15:02:54Z")

</div>

The docs are not available, [https://kahliburke.github.io/Tachikoma.jl/](https://kahliburke.github.io/Tachikoma.jl/) returns a 404.

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 3:03pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/4 "2026-02-27T15:03:16Z")

</div>

Perhaps I posted too quickly, they are in the process of being generated!

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 3:12pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/5 "2026-02-27T15:12:31Z")

</div>

Please try again

---

<div class="post-metadata">

**Author:** ![rkube](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rkube/32/211198_2.png) [@rkube](https://discourse.julialang.org/u/rkube)\
**Post date:** [February 27, 2026, 9:29pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/6 "2026-02-27T21:29:08Z")

</div>

This looks awesome. I just played around a bit with [bubbletea](https://github.com/charmbracelet/bubbletea) and really liked it.

Does Tachikoma.jl work with juliac?

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 9:31pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/7 "2026-02-27T21:31:55Z")

</div>

Thanks for taking a look. I haven’t tried with juliac but would like to know your experiences. I don’t see why it shouldn’t work with it but there of course might be a few small bumps to smooth out.

I think this framework can be pushed pretty far. I have some code implementing the original DOOM with a native Julia engine, pixel level support rendered to the terminal via kitty…

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 27, 2026, 9:49pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/8 "2026-02-27T21:49:43Z")

</div>

I’m not a juliac expert by any means, but trying some juliac tests now, stay tuned. Initial report is that a few adjustments are needed, which I’ll be including as soon as I get it working.

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 3:37am UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/9 "2026-02-28T03:37:23Z")

</div>

Apparently …

 ![ald555](https://global.discourse-cdn.com/julialang/original/3X/c/3/c3dff0a5d881778cc09f7c943f683300f0ce5e8a.jpeg)

However, I did fix a couple issues I was having with some types that didn’t vibe with JuliaC as well as an issue with the GC due to a ccall Tachi was making on startup, the first GC pass it would segfault. Now I have tried all of the demo apps through the demo launcher and they are running smoothly, stable for \> 30 minutes and memory usage is stable. I’ve added another section to the docs on how I got it working. But it boils down to a very simple wrapper.

Consider it a bit experimental but please let me know how it works for you. Once the binary is compiled, startup times are quite fast. I’ve pushed the changes and docs to the repo here: [Compiled Binaries with juliac | Tachikoma.jl](https://kahliburke.github.io/Tachikoma.jl/dev/juliac)

---

<div class="post-metadata">

**Author:** ![devel-chm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/devel-chm/32/3572_2.png) [@devel-chm](https://discourse.julialang.org/u/devel-chm)\
**Post date:** [February 28, 2026, 4:11pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/10 "2026-02-28T16:11:29Z")

</div>

Any possibility of support for Julia LTS 1.10.x?

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 5:29pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/11 "2026-02-28T17:29:19Z")

</div>

Is this an important use case for your needs?

At this point I have not put any time into supporting older versions of Julia. No specific reason here other than it wasn’t a use case for me. I’ve created this framework in part to support some other projects (such as Kaimon.jl) and those are all focused on 1.12 and beyond.

I could take a quick look. If it seems it would take significant work then I would probably pass on spending that time myself but would welcome any contributions.

---

<div class="post-metadata">

**Author:** ![devel-chm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/devel-chm/32/3572_2.png) [@devel-chm](https://discourse.julialang.org/u/devel-chm)\
**Post date:** [February 28, 2026, 5:43pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/12 "2026-02-28T17:43:59Z")

</div>

Yes, the LTS Julia is the long term support release which provides the  
stability required for the software development. The difficulty of the  
port is largely depending on how much new functionality is used specific  
to the 1.11 and 1.12 versions.

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 6:38pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/13 "2026-02-28T18:38:40Z")

</div>

I made a couple small changes, seems like it works fine on 1.10. [Update Julia version badge and docs to reflect 1.10 LTS support · kahliburke/Tachikoma.jl@3b63be5 · GitHub](https://github.com/kahliburke/Tachikoma.jl/actions/runs/22526575239/job/65259432750)

I did some limited manual testing, running through the demo launcher in TachikomaDemos.

Please try it and let me know if everything is working well for you!

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [February 28, 2026, 7:32pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/14 "2026-02-28T19:32:20Z")

</div>

This is great, and very timely for me. I was looking into `go` to build a terminal app (and I still might) but good to know there is a Julia package as well. I am also on 1.10 LTS, so would be happy if this package was fully supported on 1.10.

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 7:35pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/15 "2026-02-28T19:35:41Z")

</div>

I just checked and there doesn’t seem to be anything I’m doing which is 1.12 dependent. So please try it and get in touch about any issues. I’ve done my best to test in the environments I have access to. There are extensive unit tests in this framework as well (over 3k of them).

The next step is for others to try it out and report back with any issues. I’ll be monitoring those on GitHub closely, or feel free to reach out directly at [kahli@kahliburke.com](mailto:kahli@kahliburke.com). Thanks and I hope you are able to create something cool using Tachikoma!

---

<div class="post-metadata">

**Author:** ![DoktorMike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doktormike/32/2736_2.png) [@DoktorMike](https://discourse.julialang.org/u/DoktorMike)\
**Post date:** [February 28, 2026, 7:56pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/16 "2026-02-28T19:56:24Z")

</div>

This is fantastic. I wanted to build my own coding agent (to learn) and this package will help a lot! Nice work. 💪🏻

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 8:06pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/17 "2026-02-28T20:06:21Z")

</div>

Thank you! Please get back about experiences or any issues. Since you are mentioning coding agent, you might also be interested in [GitHub - kahliburke/Kaimon.jl](https://github.com/kahliburke/Kaimon.jl)? It’s built on top of Tachi and integrates Julia with agentic AI.

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [February 28, 2026, 8:10pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/18 "2026-02-28T20:10:00Z")

</div>

I thought I would give it a try. I am on Windows 11 with integrated graphics and Julia 12.5. Here is the output I get on running `game.jl` (copied from [Getting Started | Tachikoma.jl](https://kahliburke.github.io/Tachikoma.jl/dev/getting-started)) from within Julia:

````julia-auto
(Tachikoma) pkg> st
Status `C:\data\st\Julia\Tachikoma\Project.toml`
  [7eb4fadd] Match v2.4.1
  [468859d6] Tachikoma v1.0.0 `C:\Users\jakez\.julia\dev\Tachikoma`

julia> includet("game.jl")
Precompiling Tachikoma finished.
  1 dependency successfully precompiled in 5 seconds. 40 already precompiled.
ERROR: could not load symbol "open":
The specified procedure could not be found.
in expression starting at C:\data\st\Julia\Tachikoma\game.jl:152
```

````

The open error comes from the line `app(PigGame())`. Is this a problem with my system or something else?

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 8:17pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/19 "2026-02-28T20:17:46Z")

</div>

Taking a look now, I don’t have windows and haven’t tested there, I will try to diagnose though.

---

<div class="post-metadata">

**Author:** ![kahliburke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kahliburke/32/208472_2.png) [@kahliburke](https://discourse.julialang.org/u/kahliburke)\
**Post date:** [February 28, 2026, 11:09pm UTC](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878/20 "2026-02-28T23:09:08Z")

</div>

Hey, needed to revert the change to make juliac work… Although I had tested and found some success, I later started experiencing segfaults which I’m linking to changes I make here. So I will investigate and get a better working version in soon. Sorry for any inconvenience.

[Next page](https://discourse.julialang.org/t/ann-tachikoma-jl-a-terminal-ui-framework-for-julia/135878.md?page=2)
