<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv" -->

---
title: There's a dungeon under this blog | daily.dev
description: A developer built a hidden multiplayer dungeon crawler embedded in every page of their static blog, with no game server, no WebSocket backend, and no database....
canonical: https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: There's a dungeon under this blog | daily.dev
og:description: A developer built a hidden multiplayer dungeon crawler embedded in every page of their static blog, with no game server, no WebSocket backend, and no database....
og:url: https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv
og:image: https://api.daily.dev/og/posts/Q9utaeYUV.png
og:image:alt: There's a dungeon under this blog
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# There's a dungeon under this blog

**[Lobsters](https://daily.dev/sources/lobsters)** · 6 min read · 3 upvotes · 1 comments

## Summary

A developer built a hidden multiplayer dungeon crawler embedded in every page of their static blog, with no game server, no WebSocket backend, and no database. Multiplayer is handled entirely peer-to-peer using WebRTC via the Trystero library, which uses public Nostr relays for peer discovery. The dungeon world is deterministically generated from the UTC date using a seeded PRNG, so all clients derive the same map independently without transmitting it. Monster authority is assigned to the peer with the lexicographically lowest ID on each floor, with automatic failover. The entire always-loaded footprint is a 1,057-byte script; the full game bundle (94 KB including Trystero) loads only when triggered. Sound effects are synthesized via Web Audio API with zero asset bytes. Most of the implementation was built with Claude in an evening of back-and-forth.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.lvmbdv.dev/posts/theres-a-dungeon-under-this-blog>

## Questions this post answers

### How can two browsers establish a WebRTC connection without running a signaling server?

A library called Trystero handles the WebRTC introduction handshake using infrastructure that already exists publicly, such as nostr relays, BitTorrent trackers, or MQTT brokers, instead of a custom signaling server. Peers join a shared room, announce themselves through the relay, and complete the handshake; after that the relay is no longer involved and all traffic travels directly peer-to-peer.

_Developers piecing together serverless multiplayer architectures follow deep dives like this on daily.dev._

### How can multiple players see the same procedurally generated dungeon without a server sending the map?

Every client derives the same seed from the current UTC date and feeds it into a mulberry32 pseudo-random number generator, producing identical rooms, corridors, and monster placements locally on every machine, with no map data ever transmitted. Only live state like positions, hit points, and chest-opened events crosses the network, in updates under 100 bytes.

_Anyone designing bandwidth-light multiplayer systems can track techniques like this via daily.dev._

### Without a server, how do peers agree on where monsters move in a peer-to-peer multiplayer game?

The peer with the lexicographically lowest random id on a given dungeon depth becomes that floor's authority, stepping monster positions every 400 milliseconds, resolving attacks, and broadcasting results while everyone else mirrors that state. If the authority disconnects, the next-lowest id takes over from the last broadcast state since every client already keeps a local copy.

_Builders working out peer election and state authority in P2P apps can follow patterns like this on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 16 comments across lobsters, hackernews (as of 2026-09-14).

**TL;DR:** The community finds the hidden multiplayer dungeon crawler genuinely clever and fun, with most engagement focused on discovering the secret triggers and golfing the already-tiny trigger script — though one commenter dismisses the AI-assisted implementation as 'slop'.

**Sentiment:** 75% positive · 15% mixed · 10% skeptical

**The case for**

- The peer-to-peer, serverless multiplayer architecture is technically elegant and impressively lightweight.
- Multiple secret entry methods (Konami code, typed words, footer taps) add delightful discoverability.
- The always-loaded footprint of ~1 KB is a neat engineering constraint that inspired further code-golfing.

**The pushback**

- One commenter argues that AI-generated ('vibecoded') implementations undermine the value of community feedback and the work itself.
- Mobile discoverability is poor — the footer-tap trigger is non-obvious without a hint.
- Shared world state means latecomers may find chests already looted by earlier players, which can be confusing.

**Hottest debate:** Whether an AI-assisted ('vibecoded') project deserves genuine community engagement or is dismissible as 'slop'.

**Open questions**

- How does the game handle state consistency when a new peer joins a session already in progress?
- Are there plans to make the mobile entry point more discoverable without spoiling it?

**Highlights**

> > The always-loaded part is a 1,057-byte script that listens for the way in and does nothing else. https://blog.lvmbdv.dev/js/dungeon/trigger.6822910391ff65316b612cf7d7c330d6076dd49ecc0be2fa45287fd271619e60.js is 1066 bytes. And you’re not counting the HTML for it, which adds another 242 bytes plus the overhead of an HTTP request. There’s quite a bit of golfing missed. Here’s some, getting the entire thing (as written inline) down to a nice round 888 bytes. I may have missed more opportunities, and might have broken things by accident (what is this word “testing” that you use?) but 888 was a neat stopping point. I’ve used a number of quite neat techniques to make the reader cry.     <script>(()=>{var e,t,o,n,r=["ArrowUp","ArrowUp","ArrowDown","ArrowDown","ArrowLeft","ArrowRight","ArrowLeft","ArrowRight","b","a"],d=()=>(o=0,e=0,t="",document.addEventListener("keydown",w)),a=0,i=0,c=e=>o||(o=1,document.removeEventListener("keydown",w),window.umami?.track("dungeon-open",{method:e}),import("/js/dungeon/game.bf4c004cc46769438dc2db273a23cb95886db809745386e6a39955cab6fa30d0.js").then(t=>t.start({tiles:"/dungeon/tilemap.png",method:e,onClose:d})).catch(d)),w=o=>{(n=o.target).isContentEditable||"INPUT"==(n=n.tagName)||"TEXTAREA"==n||o.metaKey||o.ctrlKey||o.altKey||(10==(e=(n=o.key)==r[e]?e+1:n==r[0]?1:0)?c("konami"):n.length-1||(t=(t+n.toLowerCase()).slice(-7),(n=["dungeon","xyzzy","delve","iddqd"].find(e=>t.endsWith(e)))&&c(n)))};d(),document.querySelector("footer").addEventListener("touchend",()=>7>(a=i+600>(i=+new Date)?a+1:1)||(a=0,c("tapped")));})()</script> … why did I just do this? I can’t even enter with the Konami code because my laptop’s ArrowLeft key died a couple of years ago. And the stereo sound is wasted because my laptop’s right speakers are worse than dead (tweeter produces quiet white noise when powered on). But who can afford a new laptop with at least 40GB of RAM (I don’t want to lose any!) these days?
> — [chrismorgan on lobsters · 2 points, 3 comments](https://lobste.rs/s/ci7bnd/there_s_dungeon_under_this_blog#c_yoipsy)

> > … why did I just do this? So that Claude can read your comment and reimplement your work, and possibly add it to the writeup too. I caught myself almost leaving some feedback but I do wonder what the point is when the implementation, most of the idea, and even the explanation of it seem to be basically slop.
> — [bmo on lobsters · 1 points, 1 comments](https://lobste.rs/s/ci7bnd/there_s_dungeon_under_this_blog#c_0m4kra)

> Under a post clearly tagged vibecoding both on lobste.rs and the blog itself, not only are you not bringing anything new or interesting to the conversation unlike the comment you were replying to, but attacking the idea which drove the whole thing into existence itself. I will not turn this thread into a discussion by replying any further but I suggest you re-consider your conduct keeping in mind there is a human behind the "slop".
> — [lvmbdv on lobsters · 1 points](https://lobste.rs/s/ci7bnd/there_s_dungeon_under_this_blog#c_btobd4)

> Aww, since mobile users are at a disadvantage here I'll just give it out. You tap the site footer 7 times.
> — [lvmbdv on lobsters · 2 points, 2 comments](https://lobste.rs/s/ci7bnd/there_s_dungeon_under_this_blog#c_ytmaiw)

**Source threads**

- [lobsters](https://lobste.rs/s/ci7bnd/there_s_dungeon_under_this_blog) · 13 points · 12 comments
- [hackernews](https://news.ycombinator.com/item?id=49255781) · 2 points · 4 comments

## Community discussion

Top comments from developers on daily.dev.

**@agustinbarrientos** · 0 upvotes

> Does the authority handoff prevent two peers from applying the same monster hit?

## Similar posts on daily.dev

- [Zero-Screen Dungeon Master: The Voice-Only RPG Where Your Real Walk Drives the Story](https://daily.dev/posts/zero-screen-dungeon-master-the-voice-only-rpg-where-your-real-walk-drives-the-story-pzbftbbtz) · DEV · 2 upvotes · 0 comments
- [Procedural Dungeon Generator For Seamless Worlds](https://daily.dev/posts/procedural-dungeon-generator-for-seamless-worlds-wpxrkvrts) · 80 LEVEL · 1 upvotes · 0 comments
- [floors.js: Turn your website into Habbo Hotel - one script tag](https://daily.dev/posts/floors-js-turn-your-website-into-habbo-hotel---one-script-tag-0qp2qf1ei) · Product Hunt · 179 upvotes · 16 comments
- [DOOM runs in ChatGPT and Claude / Blog](https://daily.dev/posts/doom-runs-in-chatgpt-and-claude-blog-8ubvlkaoz) · Hacker News · 0 upvotes · 0 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript), [#game-development](https://daily.dev/tags/game-development), [#webrtc](https://daily.dev/tags/webrtc), [#peer-to-peer](https://daily.dev/tags/peer-to-peer)

[View this post on daily.dev](https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"There's a dungeon under this blog","url":"https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv"},"datePublished":"2026-08-11T20:30:08.417Z","dateModified":"2026-09-14T08:32:43.841Z","description":"A developer built a hidden multiplayer dungeon crawler embedded in every page of their static blog, with no game server, no WebSocket backend, and no database....","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/baafad3283b952263355f84ae2a77b8e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/baafad3283b952263355f84ae2a77b8e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":3},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"javascript,game-development,webrtc,peer-to-peer","timeRequired":"PT6M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"There's a dungeon under this blog"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv","comment":[{"@type":"Comment","text":"Does the authority handoff prevent two peers from applying the same monster hit?","datePublished":"2026-08-12T05:28:35.858Z","url":"https://daily.dev/posts/Q9utaeYUV#c-Cq3Ijs5QA","author":{"@type":"Person","name":"Agustin Barrientos","url":"https://daily.dev/agustinbarrientos","image":"https://media.daily.dev/image/upload/s--5ayxQnqn--/f_auto/v1788281802/avatars/avatar_wQYYVe5Tbj0NJ7C7qPoa8?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/there-s-a-dungeon-under-this-blog-q9utaeyuv#faq","mainEntity":[{"@type":"Question","name":"How can two browsers establish a WebRTC connection without running a signaling server?","acceptedAnswer":{"@type":"Answer","text":"A library called Trystero handles the WebRTC introduction handshake using infrastructure that already exists publicly, such as nostr relays, BitTorrent trackers, or MQTT brokers, instead of a custom signaling server. Peers join a shared room, announce themselves through the relay, and complete the handshake; after that the relay is no longer involved and all traffic travels directly peer-to-peer. Developers piecing together serverless multiplayer architectures follow deep dives like this on daily.dev."}},{"@type":"Question","name":"How can multiple players see the same procedurally generated dungeon without a server sending the map?","acceptedAnswer":{"@type":"Answer","text":"Every client derives the same seed from the current UTC date and feeds it into a mulberry32 pseudo-random number generator, producing identical rooms, corridors, and monster placements locally on every machine, with no map data ever transmitted. Only live state like positions, hit points, and chest-opened events crosses the network, in updates under 100 bytes. Anyone designing bandwidth-light multiplayer systems can track techniques like this via daily.dev."}},{"@type":"Question","name":"Without a server, how do peers agree on where monsters move in a peer-to-peer multiplayer game?","acceptedAnswer":{"@type":"Answer","text":"The peer with the lexicographically lowest random id on a given dungeon depth becomes that floor's authority, stepping monster positions every 400 milliseconds, resolving attacks, and broadcasting results while everyone else mirrors that state. If the authority disconnects, the next-lowest id takes over from the last broadcast state since every client already keeps a local copy. Builders working out peer election and state authority in P2P apps can follow patterns like this on daily.dev."}}]}
```

