DOM-Walker: Every Web Page Is Already a Dungeon

Open the developer tools on any web page and look at the elements panel. A root node, branches for the sections, deeper branches for the articles inside them, leaves for the paragraphs and links. Now squint. That is a floor plan.

DOM-Walker takes that resemblance literally. Give it a URL and it fetches the page, parses it with the browser's own `DOMParser`, walks the tree with a `TreeWalker`, and turns what it finds into a playable pixel-art dungeon crawler: rooms you explore, enemies you fight turn by turn, loot you carry, lore you read, and portals that lead to the pages that page actually links to.

What each tag becomes

The mapping is the whole trick, and it is deliberately literal rather than decorative:

| In the markup | In the dungeon | |---|---| | `<h1>` | The boss chamber — the page's title is the boss | | `<h2>`, `<h3>` | Castle gates and guard rooms | | `<main>` | The throne room | | `<section>`, `<article>`, `<div>` | Halls, story nodes, chambers | | `<aside>` | A secret room | | `<footer>` | The catacombs | | `<p>` | A wandering enemy, named after its first word | | `<li>`, `<span>` | Collectible loot | | `<a href>` | A portal to that link's URL | | `<blockquote>`, `<figcaption>`, `<textarea>` | Lore scrolls you can read and keep | | `<form>`, `<table>` | Trap and puzzle rooms | | `<button>`, `<input>` | Levers and locked chests | | `<code>`, `<pre>` | Rune wraiths and rune stones |

Nothing is invented from nowhere. The enemy blocking your path in a Wikipedia dungeon is named after a paragraph on that article. The scroll you pick up contains that page's actual blockquote. Walk into a portal and it fetches the page it points to, generates the next dungeon, and carries your character across — a whole site becomes a campaign.

The map is procedural, not random

The seed comes from the URL. The same address always produces the same dungeon, so a seed is shareable: send someone the link and they walk your map, not a different one.

From the parsed tree, generation runs in a fixed order. Structural elements are ranked by importance and depth, the strongest become rooms, and rooms are placed with collision retries so they never overlap. A corridor chain connects them in document order, which guarantees the map is always fully traversable, and extra links are added on link-heavy pages so the layout loops instead of running in a line. Contents are then distributed in document order, so a list that sat under a heading in the page ends up as treasure in the room that heading created.

The result is that a page's *shape* survives into the game:

Which makes it a slightly uncomfortable way to review your own HTML. Semantic, well-structured pages produce dungeons that read like buildings. Pages assembled from nested wrapper `<div>`s with no headings produce a few featureless boxes and almost nothing to do in them. The game is not judging you. It is just drawing what is there.

Everything is generated, nothing is downloaded

There is no game engine here, and no asset pipeline.

The sprites are 8×8 bitmaps written as arrays of strings in the source, painted onto a canvas one filled rectangle per pixel, with the palette swapped per entity so a fire enemy and a shadow enemy share a body and differ in colour. The tiles are two alternating floor shades with a lighter cap on wall tops. Fog of war is a per-tile explored array plus a Bresenham line-of-sight check, so you only see what your character could actually see, and previously explored tiles stay dimly visible.

The sound is Web Audio oscillators created and discarded at the moment each effect plays — a square wave blip for a step, a sawtooth sweep for a sword swing, filtered noise for an impact, an ascending arpeggio for a level-up. The background music is the same mechanism on a timer, walking a pentatonic scale chosen by the current theme, and switching to a faster, darker scale when combat starts. No audio file is ever fetched.

Combat, character, and loss

Combat is turn-based and modal: bump into an enemy and the map gives way to a panel with the enemy's portrait, its element, its stats and a log. Attack, defend, spend stamina on a special or a spell, drink a potion, or try to run — running is a speed check against the enemy, not a free exit.

Damage rolls against attack and defence with a random band, criticals scale with luck, and elements form a triangle: fire beats nature, nature beats water, water beats fire, with shadow and arcane countering each other. Spells inflict burn or poison that keeps ticking on the enemy's turn; elite enemies inflict the same on you.

Experience levels you up, raising health, stamina, attack, defence and speed, with luck and magic every third level. Equipment comes from the page — a weapon named after a list item, armour named after a link, an artifact named after a code block — and rarity, from common to legendary, scales its bonuses.

Death is not the end unless you choose it. On normal difficulty you wake at the entrance with half health and less gold. On roguelike difficulty, death deletes the save.

Privacy, and why paste mode exists

The tool runs entirely in your browser. Your saves, your inventory, your journal and your URL history are in your own localStorage and go nowhere else. There is no account, no analytics on the game state, and no server-side rendering of anything.

The one honest caveat is fetching. A browser cannot read another site's HTML without that site's permission, so remote pages are fetched through a public CORS proxy, which means the *URL you asked for* passes through a third party. Anything private — an intranet page, a page behind a login, a document on your machine — should not go through that path.

For those, use one of the two routes that make no network request at all: paste the page's HTML directly into paste mode, or load a local `.html` file. The parser is identical; only the source differs. The generated dungeon is exactly the same one the URL would have produced.

Saving, sharing, exporting

Three save slots live in localStorage, with slot one auto-saving every five minutes and again when you leave the page. A run can also be exported as a `.dwsave` file — the full map, entity state, fog, inventory and journal, base64-encoded — and imported into any other browser.

Maps themselves export too: a PNG of the whole floor plan with portals, loot and enemies marked, or a JSON dump of the room list and entity counts, which is a genuinely useful artefact if what you actually wanted was a picture of a page's structure.

Try it on your own site

Load your homepage. Count the rooms. See whether the boss chamber has your real `<h1>` in it, whether the secret room exists at all, and whether the portals lead where you expect.

If the dungeon is a maze full of scrolls and treasure, your markup is doing its job. If it is four empty halls and a locked door, you have found something worth fixing — and you found it by playing a game in a browser tab.