haxtory/STAGES.md
type-two 594fd584fa An arms race, a cure that cannot get there, and a board that closes
THE WAR — the trojan arms race. WinNuke, Sub7, Smurf, DCC send. Each one
works, and then the level patches it seventy seconds after you first use
it, with the countdown on screen and a line about how it died: a hotfix
went out; the scanners caught up; the amplifiers stopped answering
broadcast; the client asks before it accepts now. You cannot finish the
level on one tactic. An exploit is not a tool you own, it is a window that
is already closing while you are climbing through it.

Plus a rival crew who turn up after the first rejoin, who have read the
same text files you have, and who will take the ghost crown out from under
you during a split.

THE WORM — you can try to stop it. An antidote, three seeds, and it
travels only over live links while you are killing links. It cures fast
and then stops dead with its component severed, while the death count
climbs past it. Measured: 4, 12, 18, 19, stall — dead 20 through 30. It
works perfectly on everything it can reach. It cannot reach the rest,
because you already took the road. The phones ring all night and nobody
can send mail to warn anybody, because the broken thing is the thing you
would have used.

Pacing fix: spread rate now scales with the infection, since every
infected host is running a copy. Correct, and the only way the level ever
reached its own milestones — before this, nothing died inside ten minutes.

THE BOARD — three days.

Day one as before, and you post to FidoNet on the way out. Then the 04:00
run dials five nodes across the world while nobody is awake. Day two the
board knows you: last on yesterday, calls 2, user #44 of 44 — and the
first message is FIDONET quoting what you actually typed, with an answer.
Four days, three boards, a long distance call somebody else paid for.
Received. Hello. If you over-took on the files, your ratio has been
adjusted to 1:1, because he said it would be.

Day three is LAST CALL. Not raided, not busted: the second line was never
coming, the long distance is forty dollars a month out of a job he does
not much like, and a third of them have shell accounts now and are not
calling any more, and he does not blame them, because it is better, it is
genuinely better. Nine years. Forty-four users. Six real names. Never met
one of them. Ratio off, elite board open, the NUP given away because it
does not matter now. He asks nobody to say anything sad in the message
base. They all ignore him.

65 philes. All 13 hops swept clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 16:54:14 +10:00

18 KiB
Raw Blame History

HANDSHAKE — stage briefs

One page per hop. What's built, what's thin, what I'd add, ranked. Write your direction under DIRECTION and I'll build to it.

Current state: 13 playable hops, ~7,400 lines, all clean.

Since the first pass (you gave me the wheel; these were my calls): the philes are readable, the game saves, MTU costs you distance, ROOT reads your whole save and your FidoNet message comes back on Tuesday, TIME_WAIT is a room with sixteen people in it and one of them ages out mid-sentence, SMASHING THE STACK has ret2libc, THE CLIMB is a graded final exam with one gate per era, THE BLUE BOX has the routing card and the 2111 bridge, and THE COPPER lets you follow one call through seven banks of relays to a wrong number. Items marked DONE below.

Remaining gap is still duration: most hops are 36 minutes against a doc that calls for 520.

Repo: ssh://git@100.71.119.27:222/monster/haxtory.git · run: python3 serve.py 8123

Global rule I'm working to: nothing gets added that doesn't earn its minutes. A longer level is not a better level; a level with a second idea in it is.


1 · COLD BOOT — src/levels/coldboot.js

hop 1 · first person · ~90 s · v.90

In: 512-slot NIC ring buffer, instanced packets breathing in their slots, HEAD and TAIL pointers circling, six lines of script establishing what you are, then the DMA fires and rips the camera out at 1400 units/sec into the title card.

Thin: it's a corridor with narration. You can walk but there's nothing to walk to. The "you have left your slot" beat is the only interaction.

What I'd add, ranked

  1. The tail pointer as a threat you can see coming. It's already circling. Make it actually reach you — a slow, unhurried countdown of the ring, so the DMA feels like something that arrived rather than something scheduled.
  2. One other packet who talks. A neighbour in the next slot who has been transmitted before and come back. Three lines. Sets up FIN at hop 9.
  3. The descriptor you can read. Walk to the slot wall, press E, see your own header laid out — seq number, window size, flags. Establishes the SYN/ACK vocabulary the ending depends on.

DIRECTION:

_


2 · THE STACK — src/levels/stack.js

hops 28 · third-person platformer · ~5 min · v.90

In: seven descending layers, one per OSI layer, each shedding a header shell. NX floors you fall through, rate-limit gates on a real 1.2 s cycle, canaries that scream, ASLR reshuffling the NETWORK layer on every death, CSMA/CD platforms flickering on DATA LINK, and the stateful FIREWALL boss where the solution is to make it send something outbound and arrive as the reply.

Thin: seven platforms per layer generated from one rule, so all seven layers play the same. The hazards are one-note — you meet each idea once.

What I'd add, ranked

  1. Give each layer its own verb, not just its own hazard. PRESENTATION should be about encoding (platforms that only exist in one representation), SESSION about state (platforms that remember whether you've been on them). Right now they're all "jump accurately, but with a different colour of danger".
  2. Make the firewall a three-stage fight. It currently has one idea. Stage 2: it starts blocking the pad. Stage 3: it inspects the reply and you have to make the outbound packet look like the thing you want to be answering.
  3. Vertical shortcuts. Skipping a layer should be possible, hard, and cost you the header you'd have shed — so you arrive at the bottom still wearing TLS and the copper levels behave differently.
  4. The canaries should be worth waking. Right now they're pure punishment. Make one of them guard something.

DIRECTION:

_


3 · TIME_WAIT — src/levels/timewait.js

hop 9 · walking sim · ~2 min · v.32bis

In: the beige room. Plastic chairs, 50 Hz strip-light hum synthesised from actual 50/100/150 Hz, a wall clock doing a real two-minute lap, six seated half-open connections with three lines each, and FIN by the door with nine.

Thin: it's the shortest emotionally-load-bearing level in the game. Six NPCs is not a room. And FIN's nine lines fire on a single E-mash.

What I'd add, ranked

  1. More people, fewer words each. DONE — sixteen seated, one or two lines apiece, most of it not about you.
  2. Someone ages out mid-sentence. DONE — at 38 s, quietly, and nobody in the room looks up.
  3. The clock should matter. DONE — a full two-minute lap is noticed, and is a phile.
  4. FIN refuses if you rush him. DONE — three real conversations before he'll tell you about the door.
  5. Still open: somebody should arrive while you're in there, not just leave.

DIRECTION:

_


4 · THE WAR — src/levels/war.js

hops 1016 · top-down twin-stick · ~3 min · 9600

In: #2600 on EFnet. Sixteen nicks milling and saying things, the op wearing a crown and chasing you to kick you, ten seconds of telegraphed lag, the netsplit, the ghost crown on the empty side, and the rejoin that makes it real. Sub7 body-snatch on the bots.

Thin: two successful split-rides and it's over. The Sub7 possession has no purpose — you take somebody over and then there's nothing to do with them.

What I'd add, ranked

  1. The trojan arms race. DONE — WinNuke, Sub7, Smurf, DCC send, each patched by the level 70 s after first use, with the countdown on screen. You cannot finish on one tactic.
  2. DCC send. DONE — PAMELA.JPG.EXE. They take it. They always take it, and then they're yours and they body-block the rivals.
  3. Rivals. DONE — a crew turns up after the first rejoin who've read the same text files you have, and they'll take the ghost crown out from under you.
  4. A second channel. #phreak next door, different rules, and the war is over which one the population ends up in.
  5. Give possession more point. A possessed client should go where you can't — through a ban, into +i.

DIRECTION:

_


5 · SMASHING THE STACK — src/levels/smash.js

hops 1720 · 2D side-scroll · ~3 min · 9600

In: one char buf[64] you walk right along, the canary value on a ledge, the canary bird at the boundary, four return-address bytes you write little-endian by standing on them in order, a 40-tile NOP sled you slide down, shellcode at the end, and Aleph One chain-smoking at the start.

Thin: ret2libc is described in the design doc and isn't in. The level is one straight line — no reason to ever go back.

What I'd add, ranked

  1. ret2libc as a real second route. DONE — NX lands the instant you reach the shellcode; libc appears; four gadgets in order, four real decoys, and the chain lays the bridge behind you.
  2. Make the address matter. Any four bytes work because they're prewritten. Let the player choose, including wrongly.
  3. A second buffer. Off-by-one into the low byte of the saved pointer. Harder, better.
  4. Aleph One should say more than one line. He's the mentor and he's got four words.

DIRECTION:

_


6 · THE WORM — src/levels/worm.js

hops 2128 · RTS · ~3 min · 9600

In: 60 ARPAnet hosts on a graph with real names, three vectors (fingerd overflow, sendmail DEBUG, rsh trust) with different reach and rate, load accumulating per host, hosts dying at load 7, links dying with them, and the 1-in-7 reinfection locked on and displayed and unchangeable.

Thin: you pick a vector and watch. The only input is 1/2/3.

What I'd add, ranked

  1. Let the player try to stop it. DONE — an antidote, on K, three seeds. It travels only over live links, one hop per carrier per tick, while you are killing links. It cures fast and then stops dead with its component severed while the death count climbs past it. In testing: 4 → 12 → 18 → 19, stall, dead 20 → 30. The cure works perfectly on everything it can reach. It cannot reach the rest, because you already took the road.
  2. Named hosts that fall over. DONE — the first six are named as they go.
  3. The phone calls. DONE — six, and none of them can send mail to warn anybody, because the broken thing is the thing you'd have used.
  4. Pacing note: attempt rate now scales with the infection (every infected host runs a copy), which is both correct and the only way it reached its own milestones inside a human lifetime. First deaths ~22 s, endgame ~60 s.
  5. A win condition that is worse. Spread to everything before anything dies. Should be possible and should require restraint the worm didn't have.

DIRECTION:

_


7 · THE CUCKOO'S EGG — src/levels/cuckoo.js

hops 2934 · terminal stealth · ~3 min · 1200

In: LBL VAX 11/780, logged in as sventek. A filesystem with six real documents, ls/cd/cat/who/ps, and a "lines still being watched" bar that decays on real elapsed connect time. The SDINET bait file costs you a third of your margin for reading it. You get caught; the only variable is what you got first.

Thin: six files and five commands. The tension is a timer, not a decision.

What I'd add, ranked

  1. Make him visible in ps. He's already in there as a joke. Let the player actually watch his processes change — cat /dev/tty01 > /dev/lp0 appearing on your line is the moment the level turns.
  2. Choices that trade time for cover. Clearing logs costs 40 seconds and buys you 10 lines. Reading a file costs time and gains a phile. Right now everything is free except reading.
  3. More filesystem. The pleasure is poking around. Twenty files, most of them boring on purpose, three that matter.
  4. The Hannover number. It's mentioned in roster.txt and goes nowhere. It should go somewhere — even if where it goes is the blue box level, forty hops later.

DIRECTION:

_


8 · THE BOARD — src/levels/board.js

hops 3544 · terminal · ~8 min · whatever you earned

In: the heart, and the most finished level. Busy signal on the first dial, ANSI logo painting at baud/10 characters a second, six message-base messages, five files with a real 1:3 ratio, the ANSI bomb that actually remaps your movement keys, the sysop breaking into chat and telling you he can see you typing, the NUP gate, the elite sub-board that tells you how to leave, FidoNet's overnight run, and a playable LORD in the corner.

Thin: LORD is one fight. Trade Wars is a joke that's closed. The message base is read-only.

What I'd add, ranked

  1. Come back tomorrow, properly. DONEthree days. Day 1 as before. You post to FidoNet on logoff, watch the 04:00 run dial five nodes across the world while nobody is awake, and come back to "you were last on yesterday, calls: 2, you are user #44 of 44."
  2. Let the player post and be replied to. DONE — day 2's first message is FIDONET quoting what you actually typed, with an answer. Four days, three boards, a long distance call somebody else paid for.
  3. Leeching consequences. DONE — over-take on day 1 and day 2 opens with your ratio adjusted to 1:1. He said he would.
  4. The board should close. DONE, and it's the level's payload now — day 3 is LAST CALL. Not raided, not busted: the second line was never coming, the long distance is forty dollars a month, and a third of them have shell accounts and aren't calling any more and he doesn't blame them because it's better. Nine years, forty-four users, six real names, never met one of them. Ratio off, elite board open, NUP given away because it does not matter now. "do not say anything sad in the message base. i will only read it." They all ignore him.
  5. Finish Trade Wars. A sector map, a trade route, a Ferrengi.
  6. More messages per day. Five or six each is still thin for a board.

DIRECTION:

_


9 · THE HANDSHAKE — src/levels/handshake.js

hops 4550 · rhythm boss rush · ~6 min · sets your baud

In: the showpiece. Five bosses, every one a real frequency doing the real thing. Dial tone as two-circle interference you chase the intersection of; DTMF as a 4×4 grid where you attack at the crossing of a row and column tone; ANSam at 2100 Hz flipping its attack direction on its own 450 ms phase reversals; V.8bis as bullet hell where clean dodges declare capabilities and your score becomes your baud rate for the next two hours; then the carrier ride. Ends on a real CONNECT string.

Thin: the bosses don't escalate into each other. Each is a self-contained idea that stops when it's beaten.

What I'd add, ranked

  1. A second phase for each. Dial tone should eventually stop being patient. ANSam should shorten its deaf window. Right now every boss is at full difficulty from the first second and stays there.
  2. Let the player fail upward. Failing the scream currently just means worse graphics. It should also mean the carrier ride is harder — a bad negotiation is a bad line.
  3. Retrain. Real modems renegotiated mid-call when the line degraded. A retrain event later in the game that drops you back into a 30-second scream fight, at whatever hop you happen to be on, is the best possible callback.
  4. The DTMF number should be dialable wrong on purpose. Dial something that isn't GET-ROOT and see where it goes.

DIRECTION:

_


10 · THE COPPER — src/levels/copper.js

hops 5158 · first person · ~4 min · whatever you earned

In: 300 m of sodium-lit duct with cable bundles, three load coils, a lineman's handset you clip onto a pair to listen to a stranger's phone call, and a central office with 4,200 instanced Strowger switches stepping in a wave, plus the Almon Strowger plaque.

Thin: it's a corridor with three exhibits. The cathedral is the best-looking thing in the game and you walk through it in forty seconds.

What I'd add, ranked

  1. Follow one call. DONE — start it at the MDF and follow it down the aisles through seven banks of relays. Each digit is counted out at ten pulses a second, because that is how a step-by-step switch dials. It connects. It is a wrong number.
  2. Make the cathedral navigable. You now walk the aisles, but it should be somewhere you can get lost.
  3. More to listen to. One phone call on the lineman's handset. There should be six, and one should be a modem, and one should be somebody who hears you.
  4. Weather. The doc says it's the first level with weather. There's no water in it.

DIRECTION:

_


11 · THE BLUE BOX — src/levels/bluebox.js

hops 5963 · music/puzzle · ~5 min · whatever you earned

In: the gut punch. A playable thirteen-button blue box with correct R1 MF pairs and real 100 ms KP / 60 ms digit timing. Hold space for 2600 Hz to seize the trunk, then KP + digits + ST to route, four times, stacking tandems. Then the call comes back and rings the payphone six feet behind you and you hear your own signalling a quarter-second late. Then SS7 arrives and it stops working and Joybubbles keeps whistling anyway.

Thin: the routing codes are dictated. You type what you're told.

What I'd add, ranked

  1. Let the player route. DONE — the routing card is on the wall, the objective names a destination, and Joybubbles refuses to give you the digits.
  2. The 2111 conference. DONE — dialable from anywhere, forever, by anyone who knows the number. Six voices, no faces, loops indefinitely, and holding 2600 drops the bridge. After SS7 there is nothing on it.
  3. Joybubbles should teach by ear only. He half does. Take the frequencies off the readout during his lessons.
  4. Free-play mode after SS7. You keep the box. Let the player still press the buttons.

DIRECTION:

_


12 · THE CLIMB — src/levels/climb.js

hops 63→1 · on rails · ~2 min · whatever you earned

In: an accelerating flight up through eight era palettes in reverse, with the three modern toys: Spectre as a split timeline where you carry a token out of the branch that gets discarded, Rowhammer as a wall you bang on 24 times until a bit flips next door, and Log4Shell as a sign you hold up.

Thin: two minutes for what the design doc calls the best eleven minutes in the game. The eras flash past as colour changes with no content in them.

What I'd add, ranked

  1. One mechanic callback per era. DONE — seven gates: seize, wiper, 450 ms reversal, ANSI bomb, worm, netsplit, NX. Graded, not lethal (you arrive at TTL 2 by design, so nothing up here spends TTL).
  2. Everything on fire. DONE — embers, thickening as you climb.
  3. Log4Shell's beat of silence. DONE — the world stops, the fortress walks over and reads it.
  4. The Spectre section should be a real split screen. Two viewports, two timelines. Scissor test and a second camera.

DIRECTION:

_


13 · ROOT — src/levels/root.js

hop 64 · ~3 min · v.90

In: an empty white room with uid 0 in the middle distance and nobody in it. Four beats of narration at your own pace, then the ACK arrives from 220 units away, ESTABLISHED, a sixteen-second countdown, then FIN / FIN-ACK / ACK / CLOSED, then TIME_WAIT with FIN saying told you, then it loops to hop 1.

Thin: the loop is instant. And the ending doesn't know what you did.

What I'd add, ranked

  1. The ending should read your save. DONE — philes, expiries, the baud you negotiated and lived with, the climb grade, whether somebody vouched for you, whether you hung up without saying goodbye.
  2. Your FidoNet message comes back. DONE — Tuesday. Somebody replied, because somebody always did.
  3. The loop keeps the philes. DONE (flags.looped counts rounds) — but hop 1 is not yet different the second time.
  4. CHECKSUM. The anonymous pass-by. Needs a server. Last.

DIRECTION:

_


Cross-cutting, if you'd rather direct by system than by stage

The philes 65 of 200 written. All in src/philes.js, all readable with P. Pure writing.
Audio Every tone is real but the music isn't built — the design says each level's pad is generated from that era's protocol and right now they're just chords.
The retrain A mid-game renegotiation that drops your baud without warning. One system, touches every level after it.
Difficulty Nothing scales. TTL is the only pressure and it's linear.
The 64 hops 13 levels covering 64 hop numbers. Either fill in more levels or make the existing ones properly own their ranges.