Graphical terminal emulator with visual effects (raylib + Odin) — built on ghosdin bindings to libghostty-vt
Stars
★ 2
Forks
⑂ 0
Language
Odin
Size
4,153 kB
Last Push
13d ago
Forged
28d ago
ghosttyodinodin-langraylibshadersterminal
# uzo-term
[](LICENSE)
[](https://odin-lang.org/)
[](https://ziglang.org/)
[](https://www.raylib.com/)
[](https://github.com/phiat/ghosdin)
[](#)
<p align="center">
<img src="docs/media/uzo-term-demo.gif" alt="uzo-term demo" width="720">
</p>
A graphical terminal emulator with visual effects and a built-in RPG progression layer, on [ghostty-vt](https://github.com/ghostty-org/ghostty) + [raylib](https://www.raylib.com/) in [Odin](https://odin-lang.org/).
## Effects
Boot CRT flash, screen shake, Enter shockwave + glyph explosion, key raindrops, cursor trail + gravity well, mouse field (repel-on-motion / attract-on-dwell), typing rhythm warmth, idle drift, line-age decay, character glitch, PWD tint, `cd` fly-through, forge sparks (build), kill smoke, clear whoosh, grep laser sweep, `ls` race-in, sudo vignette, exit doom-drip, alt-screen spinning drum (htop/vim/less), shardwall textured-cube backdrop, shimmer + CRT shader.
## Input
| Action | Key |
|--------|-----|
| Paste | Ctrl+Shift+V (bracketed-paste-aware) |
| Open OSC 8 hyperlink | Ctrl+Click (https/http/mailto/ftp) |
| Drum drag / pause | Left-drag while alt-screen / pause button upper-right |
| Character / class-select modal | F8 |
| Toggle RPG layer | F9 |
| Skill-tree overlay | F10 (Enter allocate, R refund, arrows navigate, Esc close) |
| Font zoom | Ctrl++ / Ctrl+- / Ctrl+0 |
## RPG layer
Default-on. XP on every char + Enter; class auto-detects from your last 50 commands into one of six Neuromancer/Rifts classes (Drifter, Console Cowboy, Spider, Techno-Wizard, Operator, Ice-Breaker). Curve targets ~Lv 10 in 5 min, ~Lv 100 in ~90 min of normal use. HUD pill in the bottom-right. F8 opens the character / class-select modal.
Spells: Spark on Command (Lv 2), Teleport (Lv 5, on `cd`), Biome Shift (Lv 10), Map Pulse (skill-tree gated). Each of the six classes has a 30-node skill tree (F10) — allocate nodes with Enter, refund with R (cascades through dependents).
## Configuration
```
just run --rand # randomize all effects + palette
just run --shake-intensity=15
just run --no-rpg # disable RPG layer
just run --rpg-class=cowboy # pin a class
just play cowboy --rand # shortcut: pin class + randomize
./uzo-term_bin --help # full flag list
```
Class names: `drifter`, `cowboy`, `spider`, `wizard`, `operator`, `icebreaker`.
## Build
Requires Odin (nightly), Zig 0.15.2 (`.mise.toml`-pinned), raylib, and a sibling clone of [ghosdin](https://github.com/phiat/ghosdin) at `../ghosdin`.
```
git clone https://github.com/phiat/ghosdin.git ../ghosdin
just build # build libghostty-vt + uzo-term
just run
just check
```
Binary writes to repo root and runs from there so `shaders/` and `fonts/` resolve.
### Fonts
Prefers JetBrains Mono Nerd Font; falls back to system paths or raylib default. Drop the TTF into `fonts/` (gitignored) to use without system install:
```
mkdir -p fonts
curl -L -o fonts/JetBrainsMonoNerdFont-Regular.ttf \
https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/JetBrainsMono/Ligatures/Regular/JetBrainsMonoNerdFont-Regular.ttf
```
## Layout
```
src/
main.odin PTY, input, rendering, 3D scene
config.odin Effect_Config, --rand, CLI parsing
util.odin Pure helpers
effects.odin Ambient: shake, trail, gravity, rhythm, glitch, idle
effects_<feature>.odin One file per effect (boot, drum, forge, search, …)
rpg.odin RPG state + XP/level + HUD
rpg_classes.odin Class table
rpg_modal.odin F8 character / class-select modal
rpg_items.odin Item / inventory data
rpg_spells.odin Spell struct + registry + dispatcher
rpg_spell_<name>.odin One file per spell, self-registers via @(init)
rpg_biome.odin Biome registry + dispatcher
rpg_biome_<class>.odin One file per class biome overlay, self-registers
rpg_skill_tree.odin F10 overlay + node allocation/refund
rpg_tree_<class>.odin 30-node tree per class, self-registers each node
shaders/ Post-processing GLSL
docs/ Design notes
```
**Adding a spell / biome / skill tree**: drop one new `src/rpg_spell_<name>.odin`, `src/rpg_biome_<class>.odin`, or `src/rpg_tree_<class>.odin` — each self-registers via `@(init)` with no central wiring. **Adding a class**: append to the `RPG_Class` enum in `rpg.odin` AND a matching `Class_Def` row at the same index in `rpg_classes.odin`; biome and tree files are optional. See `AGENTS.md` for the full guide.