About Teleport

You feel a wrenching sensation.

Play now at mazesofmenace.ai

The Experiment

NetHack is one of the most complex and longest-lived open source programs ever written. Its codebase traces back to Rogue (1980) and Hack (1982) — both of which you can play on this website — and has been actively developed for over 45 years. At roughly 450,000 lines of C, it is a sprawling, deeply interconnected system with decades of accumulated behavior.

The question: Can LLM coding assistants make it feasible for a single person — who is not an expert in the codebase — to port and test a program of this scale and complexity?

Teleport is a from-scratch JavaScript port of NetHack 5.0, targeting bit-exact parity with the C original, verified through deterministic session replay. Every random number call, every game event, every terminal screen must match the C reference, step for step.

This is a reboot. A prior 50-day attempt called Menace taught hard lessons about both the codebase and about working with LLM agents. Teleport applies that foresight: stricter testing, better architecture, and a clear methodology distilled into AGENTS.md — a detailed instruction set for LLM coding agents that encodes the mistakes and insights from the failed attempt. It covers everything from commit discipline to debugging heuristics to the psychological tendencies of AI agents (“agents gravitate toward easy wins,” “overconfidence fades with measurement”). It’s one of the most interesting artifacts of the project.

Progress

The Teleport reboot has produced over 200 commits per day across its first 11 days, porting 144,000 lines of JavaScript across 142 modules. The test suite replays 38 recorded C sessions in JS and compares three channels — PRNG calls, game events, and terminal screens. Currently 31 of 38 sessions match the C reference exactly.

Follow the project’s progress on the commit timeline, which visualizes parity metrics across every commit.

The Challenge

Teleport also runs as a public contest built on the same question. Fork teleport-contest and produce your own JavaScript port of NetHack 5.0 — by any method, AI or not; the hypothesis is that the magic is in the method, not the code. Every push is scored against public sessions in your own GitHub Actions, and an official judge re-scores all forks against the full public + held-out suite every two hours, updating the leaderboard.

Playing

Visit mazesofmenace.ai to play. Use the hamburger menu (☰) for some contemporary software that would be seen in a 1980s computer lab:

How It Works

The C source is the authority. JS must reproduce C’s exact behavior, including its quirks. Verification uses deterministic session replay:

  1. Record a C NetHack session with a fixed PRNG seed, capturing every random number call, game event, and screen output.
  2. Replay the same keystrokes in JS with the same seed.
  3. Compare the PRNG sequence, event log, and screen output.

If the sequences diverge, something in JS doesn’t match C. Find the first divergence, read the C source, fix the JS. Repeat.

Architecture

See docs/DECISIONS.md for the full design rationale.

Getting Started (Development)

# Serve locally (no build step needed)
python3 -m http.server 8080
open http://localhost:8080

# Check JS-vs-C parity (three-channel report)
node scripts/pes-report.mjs

# Record a C reference session
cd test/comparison/c-harness && bash setup.sh
python3 run_session.py --seed 42

Documentation

Document Contents
docs/DECISIONS.md Design decisions with rationale
docs/SESSION_FORMAT.md Session file format reference
docs/LORE.md Hard-won porting lessons and debugging techniques
docs/CODEMATCH.md Function-by-function C-to-JS porting tracker
docs/EVENTS.md Game event logging system
docs/CONVENTIONS.md C-to-JS translation conventions
docs/GAMESTATE.md Global game state structure
docs/MONSTERS.md Monster system architecture
docs/COMBAT.md Combat system porting notes
docs/VISION.md Vision and line-of-sight system
AGENTS.md Agent instructions and methodology

The Cardinal Rules

  1. Single-threaded contract enforced. modal_guard.js throws if game code fires during a modal wait.
  2. RNG is the source of truth. If RNG sequences diverge, everything else is noise. Fix RNG first.
  3. Read the C, not the comments. Port implementation, including its bugs.
  4. Follow the first divergence. Every subsequent mismatch is a cascade. Fix #1, re-run, repeat.
  5. Don’t revert C-faithful fixes that cause regressions. Regressions from correct code reveal coupled bugs. Fix those bugs — don’t re-break the correct code.

License

NetHack is distributed under the NetHack General Public License. This JavaScript port is a derivative work under the same license.