████████╗██╗ ██╗██╗ ███████╗██╗ ██╗███╗ ██╗
╚══██╔══╝██║ ██║██║ ██╔════╝██║ ██║████╗ ██║
██║ ██║ ██║██║█████╗█████╗ ██║ ██║██╔██╗ ██║
██║ ██║ ██║██║╚════╝██╔══╝ ██║ ██║██║╚██╗██║
██║ ╚██████╔╝██║ ██║ ╚██████╔╝██║ ╚████║
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
A portfolio & blog that boots straight into a terminal.
It looks like a TUI. It quacks like a TUI. But underneath it's a real, server-rendered Nuxt site — so the SEO, the real links, and the accessibility all keep working. The terminal is the interface, not an emulator.
$ git clone https://github.com/j-t-black/tui-fun
$ cd tui-fun && npm install
$ npm run dev
➜ Local: http://localhost:4000/Then drive it like you'd hope:
j / k move between sections (or use the arrow keys)
: open the command bar
:blog jump straight to the writing
:help list every command
esc close the command bar
click anything mouse works too — it's just DOM
- Big ASCII-art banners rendered server-side with figlet (
ANSI Shadow), painted with a Catppuccin gradient. Digital graffiti, basically. - Hybrid navigation — radio-button section nav, vim-style
j/kkeys, and a:command bar. Keyboard-first, mouse-friendly. - A real blog — Markdown posts via Nuxt Content, each at its own SEO'd URL.
- Styled DOM, not a fake shell — semantic HTML under the terminal paint, so it
stays crawlable and accessible (banners are
role="img"with the word as a label). - One cohesive theme — Catppuccin Mocha via WebTUI, with accent colors used liberally on purpose.
| Layer | Tool |
|---|---|
| Framework | Nuxt 4 · Vue 3 · TypeScript |
| Terminal CSS | WebTUI (@webtui/css) + Catppuccin Mocha |
| ASCII art | figlet (rendered in a server route) |
| Content | Nuxt Content v3 (better-sqlite3 adapter) |
npm install
npm run dev # → http://localhost:4000| Script | What it does |
|---|---|
npm run dev |
Dev server on :4000 |
npm run build |
Production build (Nitro) |
npm run generate |
Static prerender |
npm run preview |
Preview a build |
app/
├─ layouts/default.vue # the TUI shell: banner, radio nav, status bar, command bar
├─ components/
│ ├─ AsciiBanner.vue # fetches /api/banner, colors it with a CSS gradient
│ └─ CommandBar.vue # the ':' command palette
├─ pages/ # about (/), blog, blog/[slug], projects, contact
└─ utils/nav.ts # SECTIONS — single source of truth for the nav
content/blog/*.md # the posts
server/api/banner.get.ts # figlet → ASCII, server-side + cached
assets/css/main.css # WebTUI @layer order + Catppuccin import
The whole site is one app shell (the layout) wrapping routed pages that render into the content pane. Banners are generated on the server so figlet's font data never ships to the browser; everything else is layout and color.
- Dev is pinned to :4000 to dodge other local servers on
:3000. - WebTUI is young (0.1.x) — versions are pinned; extra styling lives in
@layer apprather than fighting the library. - Nuxt Content needs the native
better-sqlite3module; if a fresh install can't auto-add it, runnpm i better-sqlite3.
Built with Nuxt, a lot of box-drawing characters, and :wq.