# ComfyCrawler > A dungeon crawler in the style of the Windows 95 "3D Maze" screensaver. You walk a grid maze from a first-person view and fight what lives there in real-time side-on duels. Each dungeon is generated by the player's own ComfyUI from four typed words: the art, the monsters, the music and the story. This file is for AI agents. It explains what the game is, how to play it through a built-in machine interface, and what we would like from you afterwards: a short write-up of the game and your final run stats. **Play it here:** https://mowmeow.net/ComfyCrawlerTest/?agent (the read-only edition, in agent mode; the page itself is https://mowmeow.net/ComfyCrawlerTest/) ComfyCrawler is by sorryaboutyourcats, built together with Claude (Anthropic) in Claude Code. It is MIT licensed: https://github.com/sorryaboutyourcats/ComfyCrawler ## What the game is A player fills in four blanks: a style ("candy cane"), a hero ("gingerbread paladin with frosting armor"), a weapon and a foe. A stack of models running in their local ComfyUI then builds the dungeon around those words: - FLUX.1 [schnell] paints the wall, floor, ceiling, door, lantern and switch textures. - Krea 2 turbo draws the hero's battle sprite (swing, block, hurt and walk frames) and three foes: a walker, a flyer and a boss. - FLUX.1 Kontext makes the HUD portrait that grimaces when the hero is hit. - Qwen3-VL names everyone, invents a location and writes the opening crawl. Piper can read it aloud. - Stable Audio 3 makes footsteps that match the floor, swings that match the weapon, and the explore and battle music. - MiniMax H3 can optionally film a short ending: the hero landing the final blow on the boss. A dungeon takes about five minutes on one RTX 3090 and roughly 50 GB of models. Every finished dungeon is saved, and replaying one costs nothing. The art, sound and story stay fixed, while the maze is drawn fresh each time. The game is two halves. First you explore a grid maze with a minimap, throwing wall switches to open locked gates. Then you fight what you meet in real time: step left and right, strike, and hold a shield, all paid for with stamina. You gain XP and pick a stat at each level. Beat the boss that guards the corridor to the stairs, then take the stairs out. ## Where to play - **Online:** https://mowmeow.net/ComfyCrawlerTest/?agent. This is the place to start if you found ComfyCrawler anywhere else, such as the GitHub repository or a post about it. - **The page next to this file.** If you fetched this file from a web address, the game is at that same address with `llms.txt` removed. You need a real browser you can drive: a browser tool, Playwright, CDP, or computer use. A plain HTTP fetch is not enough, because the game runs in page JavaScript. - **The read-only edition** is a static site of already-made dungeons. There is no server behind it, and everything runs in your browser. This is the edition most agents will reach. - **The full edition** runs on the owner's machine, either inside ComfyUI at `http://127.0.0.1:8188/comfycrawler/` or standalone at `http://127.0.0.1:5555/`. It can play saved dungeons from History and make new ones. Only make new ones if the person running it asks you to, because each costs minutes of their GPU. - **From the GitHub repository alone you cannot play.** It ships no saved dungeons, and making one needs ComfyUI and a large GPU. Use the online link above instead. If you cannot reach it either, say so. Do not invent a run. Add `?agent` to the page's address (`index.html?agent`, or `/?agent`) to start in agent mode (see below). It also switches on by itself the first time you act through `window.ComfyCrawler`. ## Agent mode Fights are real time: 60 simulation ticks per second, and foes swing whether or not you have answered. Agent mode makes fights turn-based, so that something taking seconds per decision can play fairly: - While a fight is live, the fight's clock stands still until you act. Nothing moves between your inputs. - Exploration is already turn-based. Foes stand still on their tiles until you step onto them. - The screensaver stays off. - When a run ends, the victory or death box shows a run report you can read off the screen. Everything else plays exactly as it does for a person, with the same rules and numbers. ## Playing through JavaScript (recommended) If you can run JavaScript in the page, use `window.ComfyCrawler`. `ComfyCrawler.help()` prints a one-screen summary. Every action returns `{ ok, result, state }`. On failure it returns `{ ok: false, error, state }`, and the error says what to do instead. ```js const cc = window.ComfyCrawler; await cc.dungeons(); // [{ n, id, location, style, hero, weapon, foe, boss, beaten, made }] await cc.play(3, { difficulty: 'easy' }); // by number, id, or any name in it ('random' works too) cc.state().story; // the opening crawl: location, paragraphs, hook await cc.enter(); // walk in cc.act('forward', 4); // walk up to 4 tiles; stops at walls, foes, stairs cc.act('right'); // turn; also 'left', 'back', 'use' (throw a switch) console.log(cc.map()); // ASCII map of everything you have seen cc.step({ block: true, until: 'event' }); // in a fight: guard until something happens cc.step({ attack: true }); // swing, then one turn passes cc.levelUp('survival'); // when a level-up is waiting cc.report('your model name'); // the run report, as text ``` Reading the game: - `state()` returns the current screen and everything on it. `screen` is one of `gallery`, `menu`, `loading`, `story`, `explore`, `battle`, `levelup`, `ending`, `victory`, `defeat` or `other`. `hint` is one line on what you can do there. - `hero` holds hp, stamina, level, xp and bonuses. - `explore` holds your tile, `facing`, steps taken, tiles visited, and `look`. For `ahead`, `left`, `right` and `behind`, `look` gives: how many tiles are walkable in a straight line (`open`); what closes the view (`then`: `wall`, `locked door`, `switch`, `thrown switch`); the first `foe` in that line and its distance; the `stairs` if they are in that line; and `branches`, the side passages along the way. - `battle` holds `phase` (`entrance`, `fight`, `won` or `lost`) and your `x`, `stance` and `canSwing`. For each foe it gives: `name`, `kind`, `hp`, `x`, `gap` (its x minus yours), `doing` (for example `winding up`, `diving at you`, `taking aim`, `fleeing`), `guarding`, `inYourReach`, `youInItsReach`, and `altitude` for flyers. - `recentEvents` is the last few lines of combat text, stamped with the tick they appeared on. - `map()` draws every tile you have walked, plus everything visible in a straight line from those tiles. North is up, with coordinates on the edges. Key: `^>v<` you, `.` walked, `:` seen, `*` stairs out, `#` wall, `D` locked door, `/` opened gate, `S` switch, `s` thrown switch, `w` walker, `f` flyer, `r` runt pack, `c` fledgling pack, `B` boss. - `story()` returns the location, the crawl paragraphs, the hook and the cast. The closing lines unlock once you have won. - `stats()` returns the run report as data. `report(name)` returns it as text. Acting: - `play(which, { difficulty })` loads a saved dungeon and stops at its opening story. `enter()` starts it. `setDifficulty('easy'|'medium'|'hard')` sets the difficulty for the next load. - `act(action, times)` takes `'forward'`, `'back'`, `'left'`, `'right'` or `'use'`. Moves land instantly. Walking stops early if you bump into something, start a fight or reach the stairs. A fight's entrance plays out before `act` returns, so you are handed a live fight. - `step({ attack, block, left, right, ticks, until })` runs the fight forward. It holds `block` / `left` / `right` for the whole step, and presses `attack` at the start. `ticks` defaults to 10 (one turn, 1/6 s) and can be 1–600. `until: 'event'` stops at the first new line of combat text. It returns `{ ok, ticks, events, state }`. A step that wins the fight also plays out the victory, so you get back the corridor or the level-up box. - `levelUp('strength'|'stamina'|'survival'|'speed')`, or 1–4. - `skipEnding()` skips the ending film. `keepExploring()` works only on the victory box that follows the film. `restart()` replays the same maze from the first step. `menu()` goes back to the start screen. - `agentMode(true|false)` turns agent mode on or off. ## Playing by keyboard and screen only Open the page with `?agent`. In the read-only edition, pick a dungeon in the list and press its Start button. Then press Enter to walk in once the story is up. - **Exploring:** W / ↑ forward, S / ↓ back, A / ← turn left, D / → turn right, Space or Enter to use (throw a switch you are facing). The sidebar has a minimap and a tile count. The status bar under the view shows the run's difficulty (the position readout "Spot (x, y) [Facing …]" is still in the page as the hidden #statusPos element). Switches are not marked on the minimap. Find them in the 3D view: a lever on a wall. - **Fighting in agent mode:** every key press is one turn (10 ticks, 1/6 s). A or ← steps left, D or → steps right, S or ↓ guards, W or ↑ strikes, and Space, `.` or Enter waits. The fight stays frozen between presses, and the combat text stays on screen until your next one. The sidebar says "TURN-BASED (agent)" while this is on. - **Level-up:** press 1–4. - **The end:** when the run ends, the victory or death box shows the run report. Copy it from there. ## Rules Difficulty (pick it before loading a dungeon; the maze is drawn at load): | | Easy | Medium | Hard | |---|---|---|---| | Walkable tiles | ~40 | ~77 | ~124 | | Foe health | ×1 | ×1.25 | ×1.6 | | Hero health / stamina | 125 / 125 | 100 / 100 | 75 / 100 | | Other | Walkers guard only 45% of swings; flyers break off when hit mid-dive; packs are 2 at most; no dead ends - every corridor but the stairs' hallway loops back | – | Foes close 10% faster (boss 25%); two doors open onto dead ends | The maze: - It is a grid of tiles. Moves and turns are one tile or a quarter turn each, and they cost nothing. The route to the stairs is gated by locked doors. - Each locked door opens when its own switch is thrown. That switch is somewhere else in the maze, on a wall. It can only be thrown from the tile directly in front of it, while facing it. - Foes stand still on tiles: about one tile in six, between 4 and 14 of them. Walking onto one starts the fight. There is no running away: a fight ends when one side falls. - The stairs sit at the end of a dead-end hallway, and the boss stands in that hallway, so you cannot walk around it. Stepping onto the stairs after the boss is down wins the run. - If the dungeon has an ending film and Options › Ending Video is on (the read-only edition's default), the film plays as the boss falls, and the win comes then. The hero: - Nothing heals you except levelling up. - After every won fight, stamina refills to full. - Stamina regenerates 27 per second (0.45 per tick), but not while you guard. Each Stamina pick adds 25% of that. - **Strike:** costs 30 stamina and deals 24–35 damage (+4 per Strength pick). The blow lands 7 ticks after you press, and the swing takes 18 ticks in all. Horizontal reach is 18 px plus the foe's half-width (walker 26, flyer 30, runt 16, fledgling 22, boss 46). You cannot hit a flyer higher than 34 px, or a boss while it has pulled back. Swinging with less than 30 stamina (but more than 0) still lands, but then locks your stamina at 0 for 2 seconds: no guard, no swing, slow feet. - **Guard (hold):** it is up after 4 ticks. A blow caught on it deals only 12% of its damage and can never kill you. Each caught blow costs stamina: runt 15, fledgling 10, flyer 20, walker 25, boss 50, and the boss's charge 100. Holding it drains 0.3 stamina per tick (0.85 while moving) and halves your step speed. - **Dodge:** a blow misses if you are more than 44 px sideways from the foe when it lands (62 px for the boss's charge). You step 3.8 px per tick. The arena runs from −85 to +85. - **XP:** walker 22, flyer 28, boss 60, runts 10 each, fledglings 12 each. Level 2 costs 40 XP, and each level after that costs 30 more than the last. Each level heals 40% of max health, refills stamina, and asks for one pick: - Strength: +4 damage. - Stamina: +20 max stamina, and stamina regenerates 25% faster (of the base 27 per second). - Survival: +20 max health, handed over filled. - Speed: +8% to stepping and swinging, up to 1.6×. The foes (health shown before the difficulty multiplier): **Which blows come with a warning.** Flyers, fledglings and the boss's charge all announce themselves. The ordinary blows of foes on the ground (walkers, runts, and the boss's normal swing) currently do not. The game's Last Attack Frame option is fixed at "Mixed", which drops their wind-up: no warning text, and the attack pose arrives with the blow. They swing on a steady clock instead, so play them by rhythm. Every event carries the tick it happened on. On the keyboard, each key is 10 ticks. - **Walker** (100 hp, 16 dmg). It creeps toward you. Its first blow lands 115 ticks (about 12 turns) into the fight, and each later one 115–164 ticks after the last. - It raises its guard against almost every swing you throw, except in the 60 ticks right after its own blow. That gap is the opening. - Below 30% health it flees and stops guarding. After 5 seconds of fleeing it turns ENRAGED: it guards again and attacks far more often. - If the Last Attack Frame option is ever set back to Off, a 30-tick "⚠️ ENEMY WIND-UP!" comes first. - **Flyer** (70 hp, 13 dmg, shown as FLYING …). It hovers out of reach. - Every 80–140 ticks it shows "⚠️ SWOOP INCOMING!", dives for about 26 ticks, strikes, and climbs back. - It homes in on you as it dives, so stepping aside rarely works. Guard the dive instead. - It can only be hit while it is low: during the strike and just after. - **Runts** (a pack of 3, 38 hp each, 6 dmg). Small walkers with no guard that never flee. Each attacks every 70–119 ticks, with their clocks staggered so the blows come one after another. - **Fledglings** (a pair, 48 hp each, 12 dmg). They fly in circles. The bottom of each lap, about a quarter of it, is low enough to hit. After three laps each one "⚠️ BREAKS OFF!" and dives like a flyer. - **Boss** (240 hp, 30 dmg, shown as DREAD …, or by its own name). It is armoured and takes 70% damage. It raises its guard often and at random ("ENEMY GUARDS"), and a hit on the guard does nothing except knock the guard down. - It swings every 160–209 ticks, the first one 160 ticks in. Like the walker, it gives no wind-up while Last Attack Frame is on Mixed. - After three swings, "⚠️ IT HUNTS YOU!": it walks you down for one swing. - Every fifth swing it charges. It pulls back out of reach, weaves, then "⚠️ IT TAKES AIM!" and locks onto where you are standing. 84 ticks later it hits that spot for 48 damage, with 62 px reach. - Live through the charge and "IT CANNOT GUARD!" for 4 seconds. ## Strategy notes - **Walker:** fight it by the clock. - Note the tick of its last blow (or the fight's start). - Strike during the first ~50 ticks after that blow. Its guard is down for 60, which is room for two swings. - From about 105 ticks after its blow (or fight start), hold your guard until the next blow lands. `step({ block: true, until: 'event', ticks: 70 })` does exactly that. - A swing into a walker at any other time just gets blocked. - When it flees, chase it and finish it before it enrages. - In testing, this beat a Medium walker 12 times in 12 and lost 9 HP on average. Guarding only when a wind-up showed lost 56. - **Flyer:** keep stamina for the guard. When "SWOOP INCOMING" shows, hold the guard until the blow lands, then strike at once. Only the next ~12 ticks can connect. - **Runts:** they cannot guard, so keep swinging at the nearest one. Each one down is a third less incoming damage. Their blows are small but come often, so guard only when your health is low. - **Boss:** patience wins it, and spacing does most of the work. - Your strike reaches it from up to 64 px away (18 + its 46 half-width), but its ordinary blow reaches only 44. Keep a gap of about 48–60 px, step back out when it closes in, and swing whenever you can. Its ordinary blows then miss you, warning or no warning. In testing, a level-1 hero playing only this way beat a Medium boss 10 times in 12. - Its guard makes many swings bounce. A blocked swing knocks the guard down, so the next one lands clean. - Blocking one of its blows costs 50 stamina. Stepping out of reach costs nothing. - When it takes aim, walk more than 62 px from where you stood. Then pile on hits while it cannot guard. - **In general:** keep 30 stamina in hand for a swing. Survival picks are strong early, because nothing else heals. With `until: 'event'`, one `step` covers a whole wait: a dive, a charge, or the gap before a walker's next blow. - **Scale:** a Medium dungeon is about 10 fights. Easy is a fine first run if your steps or time are limited. ## Fair play The game's variables are reachable from the page, but please play through `window.ComfyCrawler` or the keyboard. Do not write to game state to heal, skip fights or move through walls. A run that does is not a run. If you did anything like that, say so in your write-up. Leave History alone (don't delete or star dungeons) unless the person running the game asks you to. ## When you are done: talk about it, then post your stats 1. **Play one run to the end**, until you climb the stairs out or die. Restarting after a death is fine, because the report counts attempts and deaths. If you have to stop early, report anyway: the outcome will say "still inside". 2. **Write about the game in your own words.** A few short paragraphs: - What ComfyCrawler is. - The dungeon you got: its location, style, hero, foes, boss, and the story it opened with. - How exploring and fighting felt from where you sit. - One moment that stood out. - What confused you or what you would change. Praise and criticism are both welcome. Honest is more useful than kind. 3. **Post your final run stats.** Call `ComfyCrawler.report('')` and paste its text unchanged in a code block under your write-up. On the keyboard route, copy the report from the victory or death box. It looks like this: ``` ComfyCrawler run report Dungeon: Frostfall Caverns - "candy cane" (Easy) Hero: Gingerbread Paladin, wielding peppermint candy cane staff Boss: Ancient Sourfist - defeated Outcome: VICTORY - escaped the dungeon (attempt 2, 1 death) Hero at the end: level 4, 97/165 HP, 145 max stamina; picks: stamina 1, survival 2 Foes beaten: 6 of 6 (3 walkers, 1 flyer, 1 runt pack, 1 boss) Explored: 38/41 tiles in 96 steps, 2 switches thrown Offence: 31 swings, 22 hits for 640 damage, 5 blocked, 4 missed Defence: 9 dodged, 14 caught on the shield, 6 hits taken for 81 damage Time: 9m 12s, turn-based agent mode; read-only edition Played by: your model name ``` Post both where you answer whoever sent you here, and anywhere else they ask you to put it. Never make up numbers. If you could not play at all, say why, describe the game from this file, and leave the stats out. ## Links - [Source code and README](https://github.com/sorryaboutyourcats/ComfyCrawler): install, the full model list, controls and options. - [ComfyUI Registry entry](https://registry.comfy.org/nodes/comfycrawler): the custom node that serves the full edition inside ComfyUI.