ViF

vi motions meet a roguelike terminal shooter

Live on this site In active development. Play in terminal, the browser, or host a multiplayer game in the lobby.

ViF (short for vi-fighter) is a real-time terminal game that combines Vim-style navigation and text operations with typing, shooting, procedural encounters, adaptive enemies and generative audio.

Movement, targeting and editing use vi motions: hjkl, w/b/e, f/t, counts, operators, registers, searches and macros, across Normal, Insert, Visual, Search, Command and Overlay modes. Play with the keyboard, the mouse, or both.

It is written in Go around a custom Entity-Component-System, an event-settled fixed-step runtime and TOML-authored hierarchical state machines, with no CGO. The same build plays solo, hosts or joins a multiplayer game, runs as a dedicated server with no terminal, replays recorded runs, and runs headless for deterministic tests.

Several levels, mouse control, god mode. Ubuntu 26.04, alacritty, tmux.

The browser build is the Go game compiled to WebAssembly and drawn by xterm.js. It opens in its own tab, because the terminal captures the keyboard and mouse while it has focus. It plays solo, or joins a game hosted in the multiplayer lobby over a WebSocket on this site.

Requires
A modern browser with JavaScript and WebAssembly. WebGL2 draws the terminal when available; otherwise xterm.js falls back to its slower DOM renderer.
Audio
Silent in the browser. Native builds synthesize music and effects; they start muted, and Ctrl-S cycles the channels.
Performance
Usually below the native build: the Go runtime, the game loop and the renderer all share the browser.
Multiplayer
Host a game in the lobby, then join it from the browser or from a native build with the command it hands back. A native build can also do it in one step: vif -join https://lixen.com.

ECS runtime

Typed sparse-set component stores, a fixed-step scheduler that settles events in stable order, and a spatial grid for area, proximity and line-of-sight queries. Motion and physics run on cell-centred float64.

Adaptive enemies

Dijkstra flow fields route groups around moving obstacles. A multi-armed bandit, reinforcement learning online, learns which corridors pay off, and a streaming genetic engine evolves enemy parameters from how each one fared.

Multiplayer

Every participant runs the shared simulation and the host corrects it with hashed, page-level diffs. Roster changes land on one agreed tick, and a game carries on when a peer drops.

Terminal compositor

Layered TrueColor and xterm-256 output with blend modes, semantic masks, camera transforms and post-processing — grayscale, dim, strobe, occlusion.

Procedural audio

Pure-Go synthesis, effect mixing and a three-slot sequencer. A conductor tracks your actions per minute and shifts tempo and intensity to match.

Input and replay

Keys and mouse become semantic intents routed through a bounded MPSC queue. Macros record intents; a journal and a manual clock replay a headless run bit-exact for one build.

Runtime

  • Platforms: Linux and FreeBSD; WebAssembly in the browser; experimental Windows
  • Toolchain: Go 1.27, no CGO
  • Dependencies: own Go modules for terminal, TOML, colour and logging
  • Data: TOML scenarios, species, visuals, audio and keymaps, with embedded fallbacks
  • Modes: interactive, dedicated server, headless simulation, journal replay
  • Multiplayer: framed TCP, or WebSocket for browsers and blocked networks
  • License: BSD-3-Clause

Build

Clone
git clone https://github.com/lixenwraith/vif --depth 1
Build
cd vif && make release
Play
./bin/vif
Online
./bin/vif -join https://lixen.com