vimee.mp4
vimee is a framework-agnostic, pure-function Vim engine that you can plug into any editor UI. The core engine has zero runtime dependencies β it takes a keystroke and returns state transitions. Framework bindings (React, etc.) are thin wrappers that turn those transitions into reactive state.
| Package | Description | Version | Size |
|---|---|---|---|
@vimee/core |
Headless vim engine with pure function API | ||
@vimee/react |
React useVim hook |
||
@vimee/plugin-textarea |
Attach vim to any textarea | ||
@vimee/shiki-editor |
Vim editor component with Shiki syntax highlighting | ||
@vimee/testkit |
Test utilities for Vim operations |
npm install @vimee/core @vimee/react @vimee/shiki-editor shikiimport { Vim } from "@vimee/shiki-editor";
import "@vimee/shiki-editor/styles.css";
import { createHighlighter } from "shiki";
const highlighter = await createHighlighter({
themes: ["vitesse-dark"],
langs: ["typescript"],
});
function App() {
return (
<Vim
content={`const greeting = "Hello, vim!";`}
highlighter={highlighter}
lang="typescript"
theme="vitesse-dark"
onChange={(c) => console.log("Changed:", c)}
onSave={(c) => console.log("Saved:", c)}
/>
);
}npm install @vimee/core @vimee/reactimport { useVim } from "@vimee/react";
function Editor() {
const { content, cursor, mode, handleKeyDown } = useVim({
content: "Hello, vim!",
onChange: (c) => console.log("Changed:", c),
});
return (
<div tabIndex={0} onKeyDown={handleKeyDown}>
<div>Mode: {mode}</div>
<pre>{content}</pre>
<div>
Cursor: {cursor.line}:{cursor.col}
</div>
</div>
);
}npm install @vimee/coreimport {
TextBuffer,
createInitialContext,
processKeystroke,
} from "@vimee/core";
const buffer = new TextBuffer("Hello, world!");
let ctx = createInitialContext({ line: 0, col: 0 });
// Type "dd" to delete a line
const r1 = processKeystroke("d", ctx, buffer);
ctx = r1.newCtx;
const r2 = processKeystroke("d", ctx, buffer);
ctx = r2.newCtx;
console.log(buffer.getContent()); // ""processKeystroke(key, ctx, buffer, ctrlKey?, readOnly?)
β { newCtx: VimContext, actions: VimAction[] }
The engine is a pure function β no side effects, no DOM, no framework dependency. All state transitions are explicit and testable. The VimAction[] array tells the UI layer what happened (cursor moved, content changed, mode switched, etc.).
- Modes: Normal, Insert, Visual, Visual-Line, Visual-Block, Command-Line
- Motions:
hjklwWbBeE0$^ggGfFtT;,HML{} - Operators:
dyc><with motions and text objects - Text Objects:
iwawi"a"i'a'i(a(i[a[i{a{i<a<i`a` - Search:
/pattern?patternnN*# - Command-Line:
:w:q:wq:{number}:set:s/pattern/replace/flags - Editing:
xXrsSJoO~.uCtrl-R - Registers:
"aβ"znamed registers, unnamed register - Macros:
q{a-z}record,@{a-z}playback,@@repeat last - Marks:
m{a-z}set mark,'{a-z}jump to mark - Counts:
3dd,5j,2dw, etc. - Visual Block:
Ctrl-V, blockI/Ainsert - Scroll:
Ctrl-UCtrl-DCtrl-BCtrl-F - Indent:
>><<with configurable style/width
# Install
bun install
# Build all packages
bun run build
# Run all tests
bun run test
# Type check
bun run typecheck
# Lint
bun run lint
# Generate a changeset
bun run changeset:gen # auto-detect from commits
bun run changeset:gen major # force major bumpA live playground app is included as a git submodule.
# Clone with playground
git clone --recursive https://github.com/vimeejs/vimee.git
# Or, if you already cloned without --recursive
git submodule update --init
# Install dependencies (includes playground)
bun install
# Build all packages, then start the playground
bun run build
cd playground && bun run devThe playground uses workspace:* to reference local packages, so any changes you build in packages/* are reflected immediately.
packages/
βββ core/ # @vimee/core β headless vim engine
βββ react/ # @vimee/react β React useVim hook
βββ plugin-textarea/ # @vimee/plugin-textarea β vim for any textarea
βββ shiki-editor/ # @vimee/shiki-editor β editor component with Shiki
βββ testkit/ # @vimee/testkit β test utilities for Vim operations
playground/ # Live demo app (git submodule)
Built with Bun workspaces, tsup for bundling, and Vitest for testing.
MIT