npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

quendor

v0.3.0

Published

A Specification-Accurate Z-Machine Implementation

Readme

npm license node


And thus begins my foray into learning how to emulate the Z-Machine. What does that mean, you ask? Well, let's head down a maze of twisty little passages.


And thus begins Zork, a text adventure game from the 1980s by a company called Infocom. It's really what started off the whole Z-Machine business and thus, indirectly, started off my interest in creating an emulator for it.


The goal of the Quendor project is to provide a working emulator of the Z-Machine and an interpreter for z-code programs that will run on that machine.

As part of this project page, I state that Quendor will strive to be specification accurate, which is different than saying specification complete. A reference implementation needs to be specification complete. That's why it's a reference implementation in the first place. Quendor's aims are a bit more modest in that this project is entirely pedagogical in nature, essentially being created in order to understand how to write the emulator and interpreter and to better understand the Z-Machine itself.


The Z-Machine is the virtual machine Infocom designed in 1979 to run its text adventures, and that Inform still targets today. Quendor — named for the ancient kingdom that became the Great Underground Empire — is a faithful reimplementation of that machine: give it a story file and it plays.

⚠️ Pre-1.0, and honest about it. Quendor plays Z-code versions 1–5 — enough to run Zork I (both its v3 and v5 releases) from start to finish, to play v4 games like Trinity, and to pass the czech v3, v4, and v5 conformance suites (349/349, 367/367, and 406/406). Save/restore (Quetzal, including v5's in-memory undo) and the windowed screen model — status line, quote boxes, single-keystroke input — work today. Coloured text, Unicode, and mouse input are not yet implemented, and versions 6–8 are still to come. See Version support.

Install

npm install -g quendor

This puts two commands on your path — quendor and its short alias qdor — which are the same terminal player.

Play

quendor path/to/zork1.z3

Options

| Flag | Description | | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | --seed N | Fix the RNG seed for reproducible playthroughs (handy for testing and bug reports). | | --tandy | Set the v1–3 "Tandy" flag (some games soften their prose when it's set). | | --interpreter N | Set the interpreter number reported to the game (default 6, IBM PC). | | --interpreter-version C | Set the interpreter version letter (default A). | | --accept FILE | Replay a solution file (one command per line) and print the transcript — see Scripted playthroughs. | | --oracle FILE | With --accept, diff the transcript against a saved one; exit 1 on any difference. | | -h, --help | Print usage and exit. |

Scripted playthroughs

Rather than typing, you can hand quendor a solution file — a plain-text list of commands, one per line (although they can be chained commands with periods) — and it plays the game through, printing the transcript:

quendor --accept walkthrough.txt zork1.z3

The file is just commands, with # comments and blank lines ignored:

# West of House — grab the egg from the tree
n
n
u
get egg

At a "press a key" prompt, a line naming a key sends that single keystroke: SPACE, RETURN, ESC, or an arrow (UP / DOWN / LEFT / RIGHT).

Because quendor's randomness is seeded, the same solution, seed, and game replay identically every time — even a game that leans on chance, like a Zork sword fight. That makes a whole playthrough reproducible: record one, then check it still holds later with --oracle.

# Record a known-good transcript…
quendor --accept walkthrough.txt --seed 1 zork1.z3 > transcript.txt

# …then confirm a later run still matches it, byte for byte:
quendor --accept walkthrough.txt --seed 1 --oracle transcript.txt zork1.z3

--oracle exits 0 on a match and 1 on the first difference (printing where the two diverge) — a quick way to catch anything that changes how a game plays, whether in the game file or in quendor itself. Pin --seed so the reproducibility is explicit rather than riding the default.

Use as a library

Quendor ships as an engine, not just a player. The main entry is pure: no DOM, no node: built-ins. So, it runs unchanged in the browser or in Node. The Node-only story loader lives behind a separate quendor/node entry, so importing the engine never pulls in node:fs.

import { Machine, RunState } from "quendor";
import { loadStoryFromFile } from "quendor/node";

const story = await loadStoryFromFile("zork1.z3");
const machine = new Machine(story, { randomSeed: 1 });

machine.onOutput = (text) => process.stdout.write(text);

// Drive the fetch–decode–execute loop, feeding input when the game asks.
while (machine.run() === RunState.WaitingForInput) {
  machine.provideInput(await readCommandFromSomewhere());
}

In a browser you would load the story bytes yourself (fetchUint8Arraynew Story(bytes)) and skip the quendor/node import entirely.

The package is fully typed; Machine, Story, the instruction decoder, the Z-text codec, and the object/property tables are all exported from the main entry.

Version support

| Z-code version | Status | | -------------- | ---------------------------------------------------------------------------------------------- | | v1 – v5 | Playable. Runs Zork I (v3 and v5) and v4 games like Trinity; passes czech v3, v4 & v5. | | v6 | Not yet (graphical, needs the full screen model). | | v7 – v8 | Not yet. |

Save/restore uses the standard Quetzal format, cross-compatible with other interpreters, and v5's in-memory undo (save_undo / restore_undo) works too. The windowed screen model — split windows, status line, quote boxes, and single-keystroke input — is in place for v1–5. Coloured text, the Unicode opcodes, and mouse input are not yet implemented, and v6-style graphics are not yet supported.

Conformance

Correctness is checked against czech (Comprehensive Z-machine Emulation CHecker), a test program that self-verifies a large fraction of the opcode set and prints a pass/fail report. Quendor passes it clean for v3, v4, and v5:

v3 — Passed: 349, Failed: 0, Print tests: 19
v4 — Passed: 367, Failed: 0, Print tests: 19
v5 — Passed: 406, Failed: 0, Print tests: 19

All three suites run as part of the automated test suite on every CI build, so opcode regressions surface immediately. The v3 run is additionally replayed end-to-end and diffed byte-for-byte against a recorded transcript, so even subtle changes in output are caught.

Development

vp install   # install dependencies
vp test      # run the unit + conformance tests
vp pack      # build the library

Quendor is part of a larger project — a Z-Machine engine plus a companion debugger — developed in the open as a study in specification-accurate implementation. See the project repository for the full story, architecture notes, and the reference material behind it.

License

MIT © Jeff Nyman