Skip to content

Zeecka/VimLegends

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VimLegends logo

:VimLegends

Learn Vim by playing. Real editor · real keystrokes · real muscle memory.

TypeScript React CodeMirror three.js Tests Offline

VimLegends home — Nightglass UI over a cel-shaded 3D world

Unlike maze-style Vim games, every challenge runs inside a real CodeMirror editor with genuine Vim keybindings — the skills transfer 1:1 to actual Vim/Neovim.

Tip

Try it in 30 seconds: npm install && npm run dev → press x once and you've beaten level 1 at par. It escalates from there. 😄


✨ What's inside

🎯 VimGolf scoring every keystroke counts — beat par for ⭐⭐⭐
👾 Boss fights multi-stage battles with a keystroke-budget HP bar; undo can't rewind a cleared stage, and losing costs nothing but a retry
🤖 Your Hero a cel-shaded robot you restyle — body/visor/accessory colors + a custom aura — that idles, punches while you type, and celebrates your wins
🌋 Living worlds WebGL scenes behind smoked-glass panels (react-three-fiber, selective bloom) — with a full SVG lite mode for low-power devices
🧠 Vim-state goals challenges can verify registers, marks, modes and macros — not just buffer text
⌨️ Command Belt your growing, category-grouped collection of mastered commands
📄 Downloadable cheatsheet every command the game teaches, grouped by world — export as Markdown or a printable HTML page (→ Save as PDF), or open it in-play to look a key up
🎛️ Play, unstuck look up Commands, Restart a fumbled attempt, or Quit to the map — right from the play screen, without losing Vim focus
🕹️ Motion Rush whack-a-mole arcade drilling hjkl speed with combos
📱 Quiz mode a touch-first, tap-to-answer trainer covering the whole curriculum — the mobile way to drill when the real editor isn't practical, no keyboard needed
💾 Zero backend progress in localStorage with versioned migrations; fonts & models self-hosted — fully offline
Level results — three stars, keystrokes vs par, XP and coins earned
Beat par for ⭐⭐⭐ — every keystroke counts.

🗺️ The worlds

World You learn Boss Status
🟢 1 · Survive modes i a o Esc · motion hjkl · first edits x dd u 🚪 The Gatekeeper
🔵 2 · Comfortable words w b e · line ends 0 $ · jumps gg G · f · cw 🖋️ The Proofreader
🟠 3 · Faster operators × motions × text objects (ciw ci( ci" daw cit) · visual v V Ctrl-v ⚔️ The Refactor Gauntlet
🟣 4 · Seeker search / ? n * · find f t ; · % · substitute :s :%s//g :s///gc · marks 🔎 Grep & Gut
🩷 5 · Superpowers registers "a "0 "_ "A · macros q @ @@ · the dot . · gn · Ctrl-a 🏭 The Automaton
🟡 6 · Legend :g :v · :sort · :normal · case ops gU g~ · J gJ · block-insert I $A · gqip 🐉 The Archivist

All six worlds shipped — 77 levels (71 challenges + 6 bosses) — every par machine-proven solvable, and each new level re-verified solving at ⭐⭐⭐ in a real browser.

A challenge — the real Vim editor and your Hero over a 3D scene A boss fight with the keystroke-budget integrity bar
A real editor, your Hero, and a living 3D world Boss fights drain a keystroke-budget HP bar
World map with stars and world unlocks Motion Rush — the hjkl speed-drill arcade
Star-rated progression across worlds Motion Rush — drill hjkl speed for combos

🎨 Make it yours

One Hero, styled your way — pick body / trim / visor colors, a visor style, an accessory and a custom aura, previewed live in 3D. It then shows up everywhere you play. Earn coins by clearing levels and spend them in the Shop on animated scene backgrounds and terminal color themes.

The Hero studio — live 3D preview with colour, visor, accessory and aura controls The Shop — buy and equip animated scene backgrounds with coins
The Hero studio — a live 3D preview you can restyle Spend coins on scenes & themes

🚀 Quick start

npm install
npm run dev        # play at http://localhost:5173
npm run build      # production build → dist/
npm run preview    # serve the build (port 4173)

Deploy dist/ anywhere static (Netlify / Vercel / GitHub Pages). No special headers — it's CodeMirror's vim keymap, not WASM, so no cross-origin isolation needed.

👤 Optional accounts & verified scores

The game is 100% playable anonymously. Running the tiny zero-dependency backend in server/ adds Google / GitHub sign-in, cross-device progress sync (local + server merged on login, nothing lost), and verified share links (?u=<id>) whose numbers come from the database instead of editable text. docker compose up wires it automatically (/api behind nginx); a static deployment simply hides all account UI. Set GOOGLE_CLIENT_ID/SECRET and/or GITHUB_CLIENT_ID/SECRET plus SESSION_SECRET — see server/.env.example.

Optional sign-in dialog — Continue with Google or GitHub, or keep playing anonymously
Accounts are optional — the game is 100% playable signed out.

Note

Graphics tiers: quality is auto-detected per device — there's no toggle to fuss with. Reduced-motion, low-memory, or software-GL devices get Lite: the original procedural-SVG art, fully featured and not a downgrade of gameplay. If the WebGL context is ever lost, the session falls back to Lite automatically.

🧪 Testing — pars are proven, not guessed

npm run test       # 105 vitest tests
npm run qa         # browser checks (needs `npm run preview` running)
npm run typecheck
cd server && npm test   # backend tests (validator + live HTTP round-trips)
Layer What it guarantees
tests/content.test.ts ids unique · taught commands resolve · cursors in bounds · boss budgets sane
tests/par.test.ts every challenge's par is solved by a reference solution driven through the real vim keymap — including search/ex/confirm dialogs, macros, Ctrl-a, :g/:sort/:normal and visual-block edits
tests/cheatsheet.test.ts the downloadable cheatsheet covers every catalog command; the HTML export is self-contained and HTML-escaped
tests/hero.test.ts · account.test.ts the Hero model resolves & normalizes and old saves migrate; the account / share-link layer round-trips
scripts/qa/ real-Chromium suites: tier isolation (lite fetches zero 3D bytes), boss flow, save migration, offline reload

Important

Adding a challenge? Its reference solution in tests/par.test.ts is mandatory — see the authoring guide.

🏗️ Architecture in one picture

flowchart LR
    subgraph SYNC["⚡ sync bundle · ~278 KB gz · 3D-free"]
        APP[App + Nightglass UI]:::ui
        ED[VimEditor<br>CM6 + real vim]:::core
        CT[content/tier1-6<br>challenges as data]:::data
        VF[verify.ts<br>vim-state checkers]:::data
        ST[(zustand store<br>saves v15)]:::data
        CT --> ED
        VF --> ED
        APP --> ED
        APP --> ST
    end
    subgraph LAZY["🎨 lazy chunks · fetched on demand"]
        S3[Stage3D underlay]:::three
        H3[Hero3D robot]:::three
        TH[three + r3f + drei<br>~208 KB gz]:::three
        LH[lang-html<br>~64 KB gz]:::three
        CS[CheatsheetModal<br>+ generator]:::three
        S3 --> TH
        H3 --> TH
    end
    APP -. "React.lazy (webgl tier only)" .-> S3
    APP -. "React.lazy" .-> H3
    APP -. "React.lazy (on open)" .-> CS
    ED -. "loadLang (tag levels only)" .-> LH

    classDef ui fill:#7c6bff,color:#0b0d14,stroke:none
    classDef core fill:#ff6ac1,color:#0b0d14,stroke:none
    classDef data fill:#1a2030,color:#e2e6f0,stroke:#7c6bff
    classDef three fill:#4cc9f0,color:#0b0d14,stroke:none
Loading

The full story — z-stack contract, quality tiers, save migrations, the goal-check pipeline — lives in docs/ARCHITECTURE.md.

✍️ Adding content

Challenges are pure data — a new level is ~15 lines:

{
  id: 't3-daw',
  tier: 3,
  title: 'Word Surgeon',
  brief: 'Delete the duplicated the cleanly with daw.',
  taughtCommands: ['aw'],
  startText: '… over the the lazy dot',
  startCursor: { line: 1, ch: 36 },
  goal: { targetText: '… over the lazy dot', describe: 'Single spaces everywhere' },
  par: 3,
  hint: 'daw = delete A word — the word PLUS its trailing space.',
}

Step-by-step guide (goals, par math, bosses, the traps): docs/AUTHORING.md.

📍 Roadmap

  • Worlds 1–6 complete · boss mechanic · Nightglass 3D slice · vim-state verification
  • 📄 Downloadable cheatsheet (Markdown / printable HTML) · in-play Commands · Restart · Quit
  • 🎨 Visual rollout — per-world 3D environments, Map/Shop/Results polish
  • ⚙️ Mechanics — achievements, daily quests, spaced-repetition review
  • 🏌️ Golf mode, onboarding, remappable keys

🙏 Credits

🤖 3D hero RobotExpressive by Tomás Laulhé (CC0, mod. Don McCurdy) — meshopt-optimized, re-shaded with the game's toon ramp
🎨 2D Hero mark original procedural SVG — the lite-tier twin of the 3D Hero, painted by the same colors, visor & accessory
😀 UI glyphs Twemoji (CC-BY 4.0), bundled locally
🔤 Fonts Space Grotesk + JetBrains Mono (OFL), self-hosted via Fontsource
🌋 Scenes original procedural CSS/SVG (lite) and three.js (3D) — no asset downloads

Free & open source. Built with real Vim keybindings. ⌨️💜

About

Learn Vim by playing — VimLegends is a gamified, real-editor Vim trainer: VimGolf scoring, boss fights, a customizable 3D hero and WebGL worlds. 100% offline-capable.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages