A zero-dependency stack-based bytecode VM with an animated playground UI.
Write assembly, watch the stack breathe, and step through every instruction — all in the browser with no runtime dependencies.
- Stack VM from scratch — 18 opcodes (
src/vm/vm.ts), values, globals, call frames, and recursion. - Two-pass assembler — labels, constants, jumps, and calls (
src/vm/assembler.ts,src/vm/opcodes.ts). - Step debugger — per-instruction trace with stack snapshot, disassembly tape, and output console.
- Animated playground — 5 themed categories with 24 runnable example programs (
src/data/categories.ts). - Zero runtime dependencies — VM, assembler, and animation layer are hand-written TypeScript. Only
typescript+viteare used as build-time dev dependencies. - Animation engine — small hand-written engine on the Web Animations API + CSS (
src/ui/tween.ts,src/ui/motion.ts).
Prerequisites: Node.js 20+ and npm.
git clone https://github.com/chirank25/StackVM.git
cd StackVM
npm install
npm run devOpen the printed local URL (default http://localhost:5173).
Production build and preview:
npm run build
npm run previewnpm install stackvm-playgroundimport { VM, assemble, disassemble } from "stackvm-playground";
const vm = new VM(`push 2\npush 3\nadd\nprint\nhalt`);
const result = vm.run(true);
console.log(result.state.output); // ["5"]
console.log(disassemble(result.code, result.constants, result.names));Library entry: src/vm/index.ts (re-exports VM, assemble, disassemble, opcodes, and value helpers). Type declarations are shipped via dist-vm/*.d.ts.
| Opcode | Operands | Description |
|---|---|---|
PUSH n |
u16 const | Push number or label address |
POP |
— | Discard top of stack |
ADD / SUB / MUL / DIV |
— | Binary arithmetic (DIV errors on divide-by-zero) |
NEG |
— | Negate top of stack |
EQ / LT / GT |
— | Comparison, pushes true/false |
LOAD x |
u16 name/slot | Push global or call-frame slot |
STORE x |
u16 name/slot | Pop into global or call-frame slot |
JMP label |
u16 addr | Unconditional jump |
JZ label |
u16 addr | Pop and jump if falsy (nil, false, 0) |
CALL argc |
u8 | Call function address on stack with N args |
RET |
— | Return to caller, pushing return value |
PRINT |
— | Pop and append to output |
HALT |
— | Stop execution |
Comments start with ;. Labels end with : (loop: or @fn:). See src/vm/assembler.ts and src/data/categories.ts for full syntax and examples.
push 2
push 3
add
print
halt
@square:
load 0
load 0
mul
retRun it:
import { VM } from "stackvm-playground";
const { state } = new VM("push 2\npush 3\nadd\nprint\nhalt").run(true);
// state.output -> ["5"]| Category | Theme | What you learn |
|---|---|---|
| 01 Basics | Arithmetic and stack fundamentals | add, mul, neg, div, comparisons |
| 02 Loops | Countdowns, conditions, branching | jmp, jz, eq/lt/gt |
| 03 Variables | Store, load, swap | load, store, globals |
| 04 Functions | Reusable blocks | call, ret, slots |
| 05 Classic | Factorial, Fibonacci, primes | Recursion and control flow |
All programs live in src/data/categories.ts with expected outputs.
src/
vm/ # VM, assembler, opcodes, values (pure, no DOM — published to npm)
vm.ts
assembler.ts
opcodes.ts
value.ts
index.ts
ui/ # Playground app (DOM + animation)
app.ts
motion.ts
tween.ts
background.ts
cursor.ts
data/
categories.ts # 5 categories, 24 examples
styles/
main.css
main.ts
index.html
vite.config.ts
tsconfig.json
tsconfig.lib.json
| Command | Description |
|---|---|
npm run dev |
Start Vite dev server |
npm run build |
Type-check + build playground (dist/) and library (dist-vm/) |
npm run build:app |
Build playground only |
npm run build:lib |
Build importable library only (dist-vm/) |
npm run preview |
Preview production build locally |
- TypeScript (strict), Vite 7
- No runtime npm dependencies
- Web Animations API + CSS transitions/keyframes for motion
- More example programs (sorting, string ops)
- Shareable program URLs + export
- Breakpoints in the step debugger
- Hosted demo link
Issues and PRs are welcome. Keep the runtime dependency-free: no new dependencies, devDependencies for tooling only.
MIT — see LICENSE.