Early access · vimancer.com

VIMANCER

A Vim tutorial that fights back. An atmospheric horror-puzzle game where the text you are editing is the terrain — and the commands you are learning are the only thing that can get you out.

Started
27 Nov2022 — first commit
Commits
591across 3 yrs 8 mths
Active weeks
66of 191 — 125 silent
Code
26.8klines of TS, 187 files
Content
96playable segments
TODOs
0in the whole codebase

The pitch

A distant-future software engineer and her AI assistant enter a virtual world to learn Vim, and find themselves trapped by a corrupting force that turns the tutorial into a nightmare. Master the ancient discipline, or be consumed by the Aether.

The conceit that makes it work: you are not the hero. You are the neural chip. Zara — the Supreme Techno-Magista — is the one with the body; you are the AI fused into her subconscious. You type the commands, she moves. Her line, before any of it goes wrong:

As my AI assistant you are merged with my subconscious, I’m sure nothing can go wrong.

Zara, Act I

The tone starts light and whimsical and descends into digital horror. The Corruption announces itself in scrambled text with a real message underneath it — Yslofu tghogught ydoud dwedree asgrafe oint the gidi mgital alarealm resolving to “You thought you were safe in the digital realm.”

Four narrative pillars hold it together, and two of them are rules rather than themes. The Mind as Battleground mandates permanent ambiguity — “Never definitively answer the origin question. Theories are allowed; certainty is not.” And Code is Power, which is the whole design in four words: “VIM commands aren't metaphors for power — they are power.”

The Aether

The map is not decoration — it is the game’s progress screen, drawn under a procedurally generated fog of war that burns away region by region as you unlock them.

Who is down there

Zara The Mycelium Sprout Vex The Prime Beholder sprite sheet

Zara has seven portraits — neutral, angry, crying, happy, laughing, sad, surprised — called by name in the dialogue scripts. The Sprout speaks in pollen metaphors. The boss is a photograph of a well-known Vim streamer with the eyes set on fire, committed under the message add primeagen.

The text is the terrain

The game is a Phaser canvas layered over a live CodeMirror editor running a real Vim engine. That is not a visual metaphor — the two are physically coupled. Every rendered character is measured at runtime with document.createRange() and getBoundingClientRect(), converted into world space, and given an invisible physics body in the words group.

So the letters on screen are the platforms Zara stands on. Delete a line and the floor goes with it. Resize the window and the whole terrain is rebuilt, because the text reflowed.

A door is one character

Objects live inside the buffer as single obscure Unicode letters, so Vim's word motions treat each one as exactly one character:

ObjectIn the bufferWhich means
Closed doorƉf Ɖ jumps the cursor to it
Open doorĎthe level exit
Spike*x deletes the hazard
Memory chipϻa collectable you must reach
Key / lockƘ / Ƚa two-character puzzle

A custom tokenizer tags each character and CSS swaps the glyph for a sprite. The player sees a door; Vim sees one letter. Both are correct.

Rules as data, not code

Win and lose conditions are fourteen composable checks defined declaratively — reach the open door, time limit, collect at least n, text is correct, text changed, cursor on char, key in list, line count below n, keypress limit, missing characters, wrong inserted characters. Each carries a field schema that the editor renders into a form automatically, and they combine into groups with All/Any operators and an action.

That is how a level like “solve this in two keystrokes or restart” exists without anybody writing code for it.

The game is its own level editor

The in-browser level editor: scene tree, document preview and two rule cards

Fourteen components, about 4,000 lines, running in the browser beside the game. A scene tree down the left, a live document preview with the collectable sitting on the text, and the rules as coloured cards — green for “Next level if all rules apply: collect at least 1 mushroom”, red for “Restart if: key presses limit 2 — too many keys pressed”. It has a Notion-style / command palette with fuzzy search, drag-and-drop dialogue with bezier-curved arrows between lines, and it saves straight to disk.

Two things worth stealing

Dangerous Dave’s PC speaker, ported

The sound effects are not samples. They are the original 1988 Dangerous Dave PC-speaker data — arrays of hex divisors where the frequency is 1193180 / divisor, 0x0000 is silence and 0xFFFF ends the sequence — replayed through the Web Audio API with an envelope tuned for the sharp attack and release a real PC speaker had. The commit that added it: testing legendary dangerous dave sounds for reference.

The diff that paints corruption

A vendored Patience Diff compares your buffer against the target text, and the result is rendered as infection: wrong characters get an overlay, missing ones get a floating tooltip. The masking is done with stacked CSS gradients — one stop per character — so a single animated element shows through only where the text is corrupted.

Its author's own assessment is preserved in the git log, and it is the most honest commit message in any of these repositories:

i think the paintCode algo is ready. don’t ask me whats going on there

2025-07-04

Where it stands

Live and playable at vimancer.com. Fourteen scenes and 96 segments are built, with login required from scene four and early access ending at scene nine. Core systems, the level editor and the playable prototype are all done; what remains is the back half of the story.

Act III has a written strategy and a sharp idea behind it — nine remaining command groups collapsed into four narrative beats (Learning to Change, Destroy, Remember, Command) rather than nine chapters, on this principle:

Stop relying on NPCs. Trust the text itself. If a level is designed so that only one command solves the puzzle, the player will discover that command without being told.

docs/01_Narrative_Design/Act_III_Design_Strategy.md