Portfolio — roguelite deckbuilder Playable
SEVEN GATES
Go down for your friend. Every gate takes something.
Version m3a-told · content level m3a · playable in the browser · about 50 minutes for a winning run. TypeScript · Vite · Vitest · Playwright · ElevenLabs · Blender · opentype.js. A wide composite of relief renders from the game, rendered in Blender as fired clay and set side by side on a dark ground.
What it is
Enkidu is dead, and every underworld has a claim on him. His shade is torn between them: one realm keeps his heart, another his shadow, his body, his name, his breath, his voice. Gilgamesh goes down to gather him. He passes the seven gates of Kur, where the roads of other peoples’ dead cross the Sumerian underworld. At each gate the gatekeeper Neti takes a power from him: one of the Me, the divine gifts of civilisation, which serve as the run’s relics. Each realm he crosses adds its own Law, and the Laws stack. At the bottom waits Ereshkigal, Queen of the Great Below. Then comes the climb back up, with the galla close behind. A narrator, the Scribe, reads the road aloud like a tablet. The game is also a production experiment. A swarm of Claude agents built it against a contract that the human owns.
By the numbers
- 7 gates and 4 realms in this build (Duat, Hades, Yomi, Hel), each with its own Law; 6 realms are designed
- 136 cards in the data; 98 of them can be offered as rewards in this build
- 51 foes in this build: 31 normal foes, 10 elites, 4 Keepers, 3 bosses, the galla and 2 summons
- 32 shrines with 72 choices, 40 amulets, 12 Me, 15 oaths, 15 offerings
- about 50 minutes for a winning run, estimated by the simulator’s time model for its skilled bot (median of 142 wins)
- 1,222 unit tests (1,207 pass, 15 skipped, none fail) and 49 browser end-to-end tests
- 343 audio files, 83.3 minutes: 235 voice files, 43 music tracks and layers, 65 sound effects
- 542 agent-drawn SVG files and 23 Blender relief renders
- 737 commits in 8 calendar days, from 9 to 16 October 2026
How it was built
The human owns the design. Claude, working as the planner, drafted the rules with the human. The
result is a contract: GDD.md for the game rules, SPEC.md for code
structure and tickets, and src/core/ for the types and a pure engine core that
enforces the hook order in one place. Before the first agent ran, an independent seam review of
that contract found 44 issues, and all of them were fixed. A lead session in Claude Code runs the
swarm. It dispatches tickets, keeps the logs, runs the gates and commits, but it never writes game
code. The workers come in 9 agent types: builder, test writer, writer, SVG artist, Blender artist,
balancer, reviewer, playtester and gatekeeper. The work was planned as a Haiku swarm. On 14 October
the human moved everything the player sees or reads onto Opus: art, UI, writing, reviews, balance
analysis and the engine modules where rules interact. Sonnet took the other engine code, data
tables, tests and the simulator. Haiku kept the jobs that only run things. At peak, 20 agents
worked at once, which is the harness cap.
The lead never decides a rule. A question goes into a mailbox, ESCALATIONS.md (121
numbered items so far). The planner answers with a ruling file in prompts/rulings/
(64 so far). The lead applies each ruling to the GDD and SPEC and checks the md5 sums against the
ruling’s copies. The GDD’s decision log holds 72 entries. From the first commit to the
m3a-told tag took eight calendar days, 9 to 16 October 2026.
Five principles, from the rules every agent reads:
-
01
Own only your ticket’s files
Dozens of agents write at once, so every file has exactly one owner.
-
02
The contract is law
A new id, event, field or test hook is asked for, never invented.
-
03
The engine is pure
Every random number comes from a seeded stream owned by one module, so a run code replays a run exactly.
-
04
Measure, don’t reason
A layout change comes with measured sizes at 1280×800 and 1024×700, and a balance change with a simulator report.
-
05
Look at your output
Artists render their SVGs to PNG and look at them, and playtesters open every screenshot.
Every stage passed the same lean gates before its tag. G1 is the typecheck. G2 runs the unit tests, fast and slow. G3 runs end-to-end tests in a real browser. G4 is the balance simulator, run when numbers changed. G5 is one Opus review of the stage’s diff, G6 one Opus playtest over screenshots, and G7 a smoke test of the production build. Only a crash, a softlock, a save break, a rule that contradicts the GDD or unusable UI can block a tag. Everything else goes to a polish backlog.
Lessons, from the bottleneck log:
Check that a rule can exist before asking for it: the map generator went through four rework rounds (186 minutes of builder time) on a rule no map could satisfy, and a two-minute exhaustive search proved it. A feasibility check now comes before any structural rule is ruled.
The heaviest job sets the pace: one simulator ticket took 4 h 31 min, and the tag waited 3 h 38 min with nothing else in flight. Heavy jobs are now split into a build-and-probe ticket and a sim-only ticket with a time box.
A shell waiting for input can stall a night: on this Windows machine
python3 is a store stub that hangs. There were ten stuck processes in 24 hours. After
one rule went into every brief (scripts are files, never piped into an interpreter), the next stage
had two.
Tests should read numbers from the data, not pin them: every change made by design left small test-fix tickets behind, seven in one stage and eight in a later one.
Change the contract between waves, not during them: in one polish round eight rulings in four hours changed the contract under running agents. Each one meant held applies and fill-in tickets.
What worked best was one owner per file. In the first batch of the amulet stage, 18 builders worked in parallel and finished in 30 minutes with no file collisions.
Feature highlights
-
The Laws of the realms
Each realm adds a Law taken from its own myth. Duat weighs every card you play against a feather, and Ammit bites when the heart is too heavy. In Hades, every reshuffle leaves one card behind, and looking back at your discards costs Life. Yomi halves all healing, and the food of the dead binds you for the Flight. In Hel, while several foes stand, none can die until every one of them has wept. The Laws persist, so by the bottom you obey four at once. All 15 pairs of the six Laws have written rulings. Every card shows its live numbers, and every action previews its full result before you commit, Law penalties included. The preview is the engine itself, run on a copy of the state.
-
The gates and the Me
At each gate Neti demands a Me. You can surrender it, and it waits at that gate for the climb back. You can keep it under an oath taken from the taboos of Tablet XII, such as wear no clean garment or anoint yourself with no oil. You can give two amulets, or a garment of flesh in max Life. A broken oath loses the Me and adds a curse. An oath kept until the Throne makes the Me Hallowed, a stronger form. After Ereshkigal come three chases against the galla. Each Me you reclaim on the way up brings one more galla after you. At the surface the galla take a substitute. That choice and the pieces of Enkidu you carry out decide the ending.
-
The deep mechanics
There are 18 statuses. Rot spreads when a foe dies, and a foe with Rot cannot heal. Doom kills a unit once it reaches that unit’s Life, though Doom on Gilgamesh only drops him to 1 Life. Enough Chill freezes a foe for a turn. Seven weapons have Durability and a passive, and Gilgamesh holds the equipped one in his hand. Omen lets you look at the top of your deck and reorder it. Etched cards grow each time you play them, for the rest of the run. Chant cards can be played only after enough other cards that turn. Amulets are a second relic layer: 40 of them, each drawn as a real object of its culture. Seven Descents raise the difficulty, each named after one of Inanna’s garments.
-
The Wall of Deeds
The engine keeps every run’s story as data: the gates, the oaths, the foes slain, the pieces found and the death or the ending. When a run ends, the story is carved as a temple wall, one register per depth. The Scribe writes a caption for each deed and reads the wall as it unrolls. Each ending has its own final panel. The Hall of Tablets keeps the last 20 walls and up to 50 won runs, and a wall can be saved as an image.
-
The carved world
Every realm is drawn in its own culture’s art: cylinder-seal relief for Kur, papyrus vignettes for Duat, black-figure pottery for Hades, sumi ink for Yomi and picture stones for Hel. The interface is made of objects too. The run bar is a stone lintel and the panels are fired-clay tablets, and the main buttons are cylinder seals that roll when pressed. Behind every screen stands a relief wall of its place, rendered in Blender. Figures are rigged reliefs (52 rigs) that strike, guard and recoil, and they crumble into shards when they die. The title shows the bier of Enkidu in flickering lamp light. The display face, Seven Gates Display, was drawn for the game with wedge-cut terminals, as if pressed into clay with a reed.
-
The told road
The Scribe tells everything that happens on the road, not only the story beats. He sets the scene at each of the 32 shrines and says what came of the choice, and each of those lines stays true whatever a random outcome turns out to be. Urshanabi greets you at his ferry. The Scribe speaks at the grave goods and introduces each of the 14 elites and Keepers as the fight opens. Story lines play every run by default, and a setting can limit them to new lines or turn them off. Every story line is subtitled, and Space skips it.
Also included: the Feast of Enki, where the drunken god offers the Me; Siduri’s tavern; Urshanabi’s ferry; Utnapishtim’s sleep trial; four allies; the Tablet of Enkidu’s pieces across runs; loading tablets with 103 quotes and 61 hints; and run codes that replay a run step by step.
Where it stands
This is milestone m3a-told, content level m3a. The whole run is in: the Feast, the seven gates, the four M2 realms, Humbaba, the Bull of Heaven, Ganzir, Ereshkigal on her throne, the Flight, the substitute and every ending. Descents go up to D7, and every event on the road is narrated. Next comes M3b, which adds Tuonela, Annwn and Mictlan. Tuonela’s Meter and Annwn’s Cauldron are designed, and their Law texts, first cards and foes are already in the data, though not yet in play. M3c brings alternate bosses (the Scorpion pair of Mashu, the Lions of the Passes) and the Library of Ashurbanipal. M4 follows, and then version 1.0, which ends with a full playthrough by Opus playtesters at both screen sizes.
Screens
-
The titleThe bier of Enkidu in lamp light, the menu as clay tablets and the Descents as seven garment niches. -
The WaysThe road walked so far, carved as a frieze, and the archways open next, with an inscription above each one. -
Combat in DuatThe Scales’ Heart gauge beside the Breath bead, foes with their intents, and the hand. -
Combat in HelFoes marked wept or dry-eyed under All Must Weep. -
A shrineThe shrine’s mural, its text, and a carved panel for each choice with its numbers before and after. -
The gateNeti in front of the coming realm’s backdrop, with the Me he demands and the ways to pay him. -
The Wall of DeedsA run carved register by register, with the Scribe’s captions. -
An endingThe ending’s scene and the run summary.
Tech stack
- Game: TypeScript (strict) and Vite, with no framework and no runtime libraries. The engine is pure and deterministic: it uses eight seeded random streams and never reads the time or the DOM.
- Testing: Vitest for 1,222 unit tests, plus a slow suite that runs the heavy files with full seed counts. Playwright runs 49 end-to-end tests, 125 playtest captures and a smoke test of the production build. A balance simulator runs five bots, 400 seeds each.
- Art: SVG drawn by agents to a style bible and 30 golden samples. Blender turns flat SVG sources into fired-clay relief renders.
- Audio: ElevenLabs voices, music with layers for percussion and peril, and sound effects. All of it is generated at build time under credit caps per stage. The game itself makes no network calls.
- Fonts: Seven Gates Display, drawn as SVG glyphs and built with opentype.js. IBM Plex Sans for text, and Noto Sans Cuneiform, Egyptian Hieroglyphs, Ogham and Runic for ornament.
- Production: Claude Code, one lead session and a swarm of Opus, Sonnet and Haiku agents. Git, a ticket list, a mailbox of rulings and a bottleneck log.
Play it
Use a desktop browser at 1280×800 or larger; the game also works at 1024×700. It is played with the mouse or entirely from the keyboard. Your run and your progress are saved automatically in the browser. Sound starts after your first click.
Credits. Design by dilmun.at, with Claude (Anthropic) as co-designer. Built by a swarm of Claude agents in Claude Code. Voices, music and sound effects were made with ElevenLabs. Relief renders were made in Blender. Fonts: IBM Plex Sans and Noto Sans Cuneiform, Egyptian Hieroglyphs, Ogham and Runic, under the SIL Open Font License 1.1 (via @fontsource). Seven Gates Display was drawn for the game. Build tools: Vite, Vitest and opentype.js (MIT), TypeScript and Playwright (Apache 2.0). The story draws on public-domain sources: the Epic of Gilgamesh with Tablet XII, the descents of Inanna and of Ishtar, the Book of the Dead and the Amduat, the Iliad, the Odyssey, the Homeric Hymn to Demeter, the Theogony and the Metamorphoses, the Kojiki, the Kalevala, the Eddas and the Mabinogion. All in-game text is original. The loading-tablet quotes are our own renderings of those texts, each with its source line.