Zigoku 地獄: a terminal anime browser, built from (nearly) scratch in Zig

What it does

  • Two-pane TUI on libvaxis: live search, detail pane with episode grid, grouped watchlist, Discover feed.
  • Real cover art painted via the Kitty graphics protocol (halfblock fallback elsewhere), no ASCII approximations.
  • Search, resolve, and play in mpv, with resume positions pulled over mpv’s IPC socket.
  • Multiple streaming providers behind one SourceProvider interface, with automatic fallback.
  • Two-way AniList account sync plus metadata enrichment.
  • SQLite persistence via raw C interop (bundled amalgamation for release builds).

Zig bits that were fun / painful

  • The SPIKES.md and the spikes/ directory is where I documented my first days with zig and spiked through all of the risky unknowns of the project before I dove in
  • Decided to quarantine providers behind a type erased vtable from day one and it paid off when original stream provider rotted. It was one file and one line link swap, then added multi live providers and it was a breeze to wire.
  • Std gives you no per-read socket timeout, so I rolled out a custom thread race with Io.Select so a reachable but stalled stream can be cancelled.
  • Living on 0.16 master, and making most existing resources obsolete. Spelunking into the live Std code to figure out the api was both magical and scay.
  • My first ever TUI, so I learned a lot about terminal exit codes in the usage of libvaxis. Keeping leash on the size of app.zig has been tough. Done several carves to modules in order to keep it’s size under control and it showed me I have a lot to learn about UI architecture and modularization.

Feedback is much appreciated, I spent a career doing corpo web systems backend and getting back to roots of systems programming has been a blast, but I’m not sure how idiomatic my Zig is.

AI Usage:
I have a custom pi-code setup with 10 named role agents which I leaned heavily on. Process is: I write a Plane PM spec/ticket (self hosted in the homelab) per feature/bug/spike, and then co-drive the implementation using the AI as the co-typist and live search engine. I read and review every line of code and control the architecture and engineering decisions. If I don’t understand what the AI wrote it does not get merged, I use that as a teaching moments to learn more about what just happened and where to dig deeper about Zig or the that domain of systems programming. Comments are purposedly verbose throughout so future me can be reminded WTH past me was thinking, for better or worse, and the ticket references link back to the plane board where I can map where which piece of the code came from.

history-tour

If this is true, what is your thought on this:

/// Zigoku version. Keep in sync with `build.zig.zon`.
pub const version = "0.4.5";

...

test "version matches build.zig.zon" {
    // Pin the literal so a bump here without the matching `.version` edit in
    // build.zig.zon (or vice versa) trips CI — the "keep in sync" comment above
    // otherwise has no teeth.
    try std.testing.expectEqualStrings("0.4.5", version);
}
1 Like