<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <updated>2026-01-14T09:34:10Z</updated>
  <generator>https://nostr.ae</generator>

  <title>Nostr notes by calavera</title>
  <author>
    <name>calavera</name>
  </author>
  <link rel="self" type="application/atom+xml" href="https://nostr.ae/npub1yz9dqvfcaved5jelktkm08gn4r34x2zzmd386a40lqtgmdty5r5s3z946n.rss" />
  <link href="https://nostr.ae/npub1yz9dqvfcaved5jelktkm08gn4r34x2zzmd386a40lqtgmdty5r5s3z946n" />
  <id>https://nostr.ae/npub1yz9dqvfcaved5jelktkm08gn4r34x2zzmd386a40lqtgmdty5r5s3z946n</id>
  <icon>https://m.primal.net/OHcz.jpg</icon>
  <logo>https://m.primal.net/OHcz.jpg</logo>




  <entry>
    <id>https://nostr.ae/nevent1qqs0kdtyn5nu0ya0yf08t39gsc5llca8tqph884l7e3pq7vpc5ehxagzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswje6jghy</id>
    
      <title type="html">Sto male, per la serie &amp;#34;Doom può girare ovunque&amp;#34; Doom su ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqs0kdtyn5nu0ya0yf08t39gsc5llca8tqph884l7e3pq7vpc5ehxagzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswje6jghy" />
    <content type="html">
      Sto male, per la serie &amp;#34;Doom può girare ovunque&amp;#34; &lt;br/&gt;Doom su Minecraft, Doom su PDF, Doom su test di gravidanza digitale e ora Doom su Nostr  &lt;br/&gt;&lt;blockquote class=&#34;border-l-05rem border-l-strongpink border-solid&#34;&gt;&lt;div class=&#34;-ml-4 bg-gradient-to-r from-gray-100 dark:from-zinc-800 to-transparent mr-0 mt-0 mb-4 pl-4 pr-2 py-2&#34;&gt;quoting &lt;br/&gt;&lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Article&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/naddr1qq2ng66wwpckw4t60f49q3m3gddyknf4d4mrxq3qhrujuc08r4zcdtn0u6ts7u7apldcjqgftz0z7stmaaz9hwaf9jxsxpqqqp65w0779ra&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;naddr1qq…79ra&lt;/a&gt;&lt;/span&gt; &lt;/div&gt; 
&lt;h1 id=&#34;open-source-doom-how-we-brought-real-time-multiplayer-to-a-1993-classic-no-servers-required-2&#34;&gt;Open-Source DOOM: How We Brought Real-Time Multiplayer to a 1993 Classic. No Servers Required.&lt;/h1&gt;

&lt;p&gt;A Breakthrough in Decentralized Gaming by &lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Person&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/npub16ye7evyevwnl0fc9hujsxf9zym72e063awn0pvde0huvpyec5nyq4dg4wn&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;&lt;span&gt;JSKitty&lt;/span&gt; (&lt;span class=&#34;italic&#34;&gt;npub16ye…g4wn&lt;/span&gt;)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;In May 2021, Cloudflare did something wonderful. They took DOOM -the 1993 game that defined an entire genre -compiled it to WebAssembly, wired up WebSocket multiplayer through their Durable Objects edge platform, and &lt;a href=&#34;https://blog.cloudflare.com/doom-multiplayer-workers/&#34;&gt;wrote a fantastic blog post about it&lt;/a&gt;. As Celso Martinho put it: &lt;em&gt;&amp;#34;Running Doom is effectively the new &amp;#39;Hello, World&amp;#39; in computing.&amp;#34;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We loved it. And then we thought: &lt;em&gt;what if we could take it further?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What if multiplayer DOOM didn&amp;#39;t need Cloudflare&amp;#39;s servers -or anyone&amp;#39;s servers? What if it didn&amp;#39;t need the internet at all? What if you could send a 4MB file to a friend in a chat message and be fragging each other within seconds, purely peer-to-peer, with the game feeling like a modern real-time shooter instead of a 1994 LAN party?&lt;/p&gt;

&lt;p&gt;That&amp;#39;s what we built. We call it &lt;strong&gt;Open-Source DOOM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;#39;s powered by a stack of open technologies: &lt;a href=&#34;https://www.chocolate-doom.org/&#34;&gt;Chocolate Doom&lt;/a&gt; compiled to &lt;a href=&#34;https://webassembly.org/&#34;&gt;WebAssembly&lt;/a&gt; via &lt;a href=&#34;https://emscripten.org/&#34;&gt;Emscripten&lt;/a&gt;, distributed as a &lt;a href=&#34;https://webxdc.org/&#34;&gt;WebXDC&lt;/a&gt; mini-app, with peer discovery over &lt;a href=&#34;https://nostr.com/&#34;&gt;Nostr&lt;/a&gt;, end-to-end encryption via &lt;a href=&#34;https://github.com/parres-hq/mdk&#34;&gt;Marmot&lt;/a&gt; (MLS over Nostr), and real-time P2P data transport through &lt;a href=&#34;https://iroh.computer/&#34;&gt;Iroh&lt;/a&gt; (QUIC-based gossip). Every layer is open-source. Every packet is encrypted. No servers required.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://image.nostr.build/2768aba5d0e616d626f7877966feec7e7f3c5822a552e5320305c635a8c58697.jpg&#34; alt=&#34;image&#34;/&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;what-cloudflare-built-and-why-it-s-great-2&#34;&gt;What Cloudflare Built (And Why It&amp;#39;s Great)&lt;/h2&gt;

&lt;p&gt;Credit where it&amp;#39;s due. Cloudflare&amp;#39;s &lt;a href=&#34;https://github.com/cloudflare/doom-wasm&#34;&gt;doom-wasm&lt;/a&gt; project did the hard work of porting Chocolate Doom -&amp;gt; the faithful open-source recreation of the original DOOM engine -&amp;gt; to WebAssembly using Emscripten. That alone is a serious engineering effort. They then wrote &lt;code&gt;net_websockets.c&lt;/code&gt;, a transport adapter that replaced DOOM&amp;#39;s original IPX/UDP networking with WebSocket connections routed through Durable Objects on Cloudflare&amp;#39;s edge network.&lt;/p&gt;

&lt;p&gt;Their architecture looked like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Player A (Browser)  ←WebSocket→  Cloudflare Edge (Durable Object)  ←WebSocket→  Player B (Browser)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A Durable Object acted as the game room -maintaining a routing table of connected players and forwarding packets between them. Clean, elegant, and a great demo of edge computing.&lt;/p&gt;

&lt;p&gt;But there was a catch.&lt;/p&gt;

&lt;h3 id=&#34;what-they-kept-the-same-2&#34;&gt;What they kept the same&lt;/h3&gt;

&lt;p&gt;Cloudflare didn&amp;#39;t modify DOOM&amp;#39;s actual netcode. The game still used its original &lt;strong&gt;lockstep networking&lt;/strong&gt; model from 1993 -the same protocol designed for four PCs on a local area network connected by coaxial cable. Every player sends their inputs (which keys they pressed) to every other player, every single frame, and &lt;strong&gt;the game freezes until everyone&amp;#39;s inputs arrive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As their blog post acknowledged: &lt;em&gt;&amp;#34;The game only advances when everyone receives the commands from all the other players in the group.&amp;#34;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This worked in 1993 when your LAN had sub-millisecond latency. Over the internet, through WebSockets, through a routing layer? It meant choppy gameplay, freezes whenever anyone&amp;#39;s connection hiccupped, and a gameplay experience that felt more like a slideshow than a shooter.&lt;/p&gt;

&lt;p&gt;The Durable Object was also a single point of failure and a centralised dependency. No Cloudflare, no DOOM.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;what-we-changed-everything-except-the-game-itself-2&#34;&gt;What We Changed (Everything Except the Game Itself)&lt;/h2&gt;

&lt;p&gt;We forked Cloudflare&amp;#39;s doom-wasm project and rebuilt the entire networking stack from scratch. Not just the transport layer -the fundamental model of how the game synchronises state between players.&lt;/p&gt;

&lt;p&gt;Here&amp;#39;s the before and after:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Cloudflare&amp;#39;s DOOM&lt;/th&gt;
&lt;th&gt;Open Source DOOM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Transport&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;WebSockets → Cloudflare Edge&lt;/td&gt;
&lt;td&gt;P2P gossip via Iroh (QUIC)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Durable Object (centralised)&lt;/td&gt;
&lt;td&gt;Auto-elected from players (decentralised)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sync model&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Lockstep (1993 original)&lt;/td&gt;
&lt;td&gt;Real-time hybrid (snapshots &#43; interpolation)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Damage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simulated locally by all clients&lt;/td&gt;
&lt;td&gt;Host-authoritative events&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NPCs/Monsters&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simulated locally by all clients&lt;/td&gt;
&lt;td&gt;Host-authoritative snapshots&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Late join&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not supported&lt;/td&gt;
&lt;td&gt;Fully supported&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Internet required&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (Cloudflare Workers)&lt;/td&gt;
&lt;td&gt;No (works offline, P2P)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delivery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Website (silentspacemarine.com)&lt;/td&gt;
&lt;td&gt;4.2MB file in a chat message&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Let&amp;#39;s break down each piece.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;1-no-servers-no-problem-2&#34;&gt;1. No Servers, No Problem&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-1-3&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;Cloudflare&amp;#39;s DOOM needed their servers to work. Ours doesn&amp;#39;t need &lt;em&gt;any&lt;/em&gt; servers. When you open the game, your device automatically figures out who should be the &amp;#34;host&amp;#34; --no configuration, no IP addresses, no port forwarding, no sign-ups. It just works.&lt;/p&gt;

&lt;p&gt;The game runs inside a &lt;strong&gt;.xdc file&lt;/strong&gt;, essentially a tiny 4.2MB zip archive containing the entire game. You literally send it as a file in a chat message. Your friend opens it. You&amp;#39;re playing DOOM together. The data travels directly between your devices through the chat app&amp;#39;s peer-to-peer channels.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-1-3&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;We replaced &lt;code&gt;net_websockets.c&lt;/code&gt; with &lt;code&gt;net_webxdc.c&lt;/code&gt; -a transport module that speaks the &lt;a href=&#34;https://webxdc.org/&#34;&gt;WebXDC&lt;/a&gt; realtime channel protocol instead of WebSockets.&lt;/p&gt;

&lt;p&gt;WebXDC is an open standard for sandboxed web apps distributed inside chat messages. The app has &lt;strong&gt;zero internet access&lt;/strong&gt;, no fetch, no XMLHttpRequest, nothing. The only communication channel is &lt;code&gt;webxdc.joinRealtimeChannel()&lt;/code&gt;, which gives you an unreliable broadcast pipe to other instances of the same .xdc file in the same chat.&lt;/p&gt;

&lt;p&gt;Under the hood (in our primary platform, &lt;a href=&#34;https://github.com/nicholasopuni31/vector&#34;&gt;Vector&lt;/a&gt;), this channel is backed by &lt;a href=&#34;https://iroh.computer/&#34;&gt;Iroh&lt;/a&gt;, a QUIC-based peer-to-peer gossip protocol. Messages travel directly between devices, relayed through lightweight Iroh relay nodes only when direct connections aren&amp;#39;t possible. There are no game servers, no routing tables, no Durable Objects.&lt;/p&gt;

&lt;p&gt;Peer discovery happens over &lt;a href=&#34;https://nostr.com/&#34;&gt;Nostr&lt;/a&gt;, the decentralised social protocol. When you open a game, your Iroh node address is published as a Nostr event so other players can find you and establish a direct connection. The connection itself is encrypted end-to-end via &lt;a href=&#34;https://github.com/parres-hq/mdk&#34;&gt;Marmot&lt;/a&gt;, which implements the &lt;a href=&#34;https://messaginglayersecurity.rocks/&#34;&gt;MLS&lt;/a&gt; (Messaging Layer Security) protocol over Nostr. So every packet of DOOM multiplayer data, every position snapshot, every damage event, every frag, is encrypted with forward secrecy before it ever leaves your device.&lt;/p&gt;

&lt;p&gt;The wire format is minimal:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[to: uint32 LE (4 bytes)][from: uint32 LE (4 bytes)][doom_payload]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;JavaScript routes incoming packets by destination UID -only packets addressed to you (or broadcast address &lt;code&gt;0&lt;/code&gt;) get delivered to the WASM engine. Everything else is silently dropped.&lt;/p&gt;

&lt;p&gt;For performance, Vector provides a &lt;strong&gt;WebSocket fast-path&lt;/strong&gt;: the app connects to &lt;code&gt;ws://127.0.0.1:{random_port}/{token}&lt;/code&gt; -a localhost WebSocket server spun up by the Rust backend -giving near-zero-latency access to the Iroh gossip sender. Binary frames go straight to &lt;code&gt;sender.broadcast()&lt;/code&gt; with zero copies. Fallback path uses Tauri invoke with base91 encoding.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;2-who-s-the-server-magic-2&#34;&gt;2. Who&amp;#39;s the Server? Magic.&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-1-4&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;In a normal online game, someone runs a server, and everyone connects to it. In Open Source DOOM, there &lt;em&gt;is&lt;/em&gt; no predetermined server. When you open the game, all players silently negotiate who becomes the host. The person who opened the game first wins. This happens automatically in about three seconds, and you never even notice it.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-1-4&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;Server election uses a dead-simple timestamp protocol over the broadcast channel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every instance broadcasts &lt;strong&gt;4 magic bytes&lt;/strong&gt; (&lt;code&gt;[42, 42, 42, 42]&lt;/code&gt;) every 300ms: &lt;em&gt;&amp;#34;I exist, who&amp;#39;s the server?&amp;#34;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Every instance responds to discovery requests with: &lt;code&gt;[43, 43, 43, 43][padding(4)][timestamp(8)]&lt;/code&gt; -where timestamp is &lt;code&gt;Date.now()&lt;/code&gt; from when the app first opened&lt;/li&gt;
&lt;li&gt;The instance with the &lt;strong&gt;earliest timestamp&lt;/strong&gt; wins&lt;/li&gt;
&lt;li&gt;After 3 seconds with no earlier challenger, you declare yourself server&lt;/li&gt;
&lt;li&gt;The elected server re-broadcasts its beacon every 3 seconds so late-joiners can discover it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The server gets &lt;code&gt;instanceUID = 1&lt;/code&gt; (hardcoded). Clients get a random UID in &lt;code&gt;1–65534&lt;/code&gt;. This UID becomes their network address for the entire session -no DNS, no IP addresses, no NAT traversal headaches.&lt;/p&gt;

&lt;p&gt;The whole election algorithm is about 80 lines of JavaScript. It works over any broadcast transport. No configuration needed.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;3-from-lockstep-to-real-time-the-big-one-2&#34;&gt;3. From Lockstep to Real-Time (The Big One)&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-2-2&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;Original DOOM multiplayer works like a group of people writing a letter round-robin. Nobody can write their next line until everyone has received and read the previous line. If one person is slow, &lt;em&gt;everyone&lt;/em&gt; waits.&lt;/p&gt;

&lt;p&gt;We changed it to work more like a live conversation. Everyone talks at their own pace. If you miss a word, you can still follow along because the speaker periodically summarises where things stand. The result feels like a modern shooter -smooth movement, responsive controls, no freezing.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-2-2&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;This was the most fundamental change: replacing DOOM&amp;#39;s pure lockstep synchronisation with a &lt;strong&gt;hybrid real-time model&lt;/strong&gt;. The ticcmd backbone remains (it&amp;#39;s too deeply embedded in Chocolate Doom&amp;#39;s deterministic physics to remove), but we layered three correction systems on top:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a) Position Snapshots &#43; Exponential Smoothing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every 2 tics (~57ms at 35 FPS), each player broadcasts a snapshot of their state:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;int data[9] = {
    mo-&amp;gt;x, mo-&amp;gt;y, mo-&amp;gt;z,        // World position (fixed-point)
    mo-&amp;gt;angle,                    // Facing direction
    mo-&amp;gt;momx, mo-&amp;gt;momy, mo-&amp;gt;momz, // Velocity
    attack_weapon,                // 0=idle, 1-9=attacking with weapon N
    latency                       // Round-trip time (ms)
};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Remote players don&amp;#39;t run DOOM&amp;#39;s physics engine at all. Instead, &lt;code&gt;D_TickPlayerInterp()&lt;/code&gt; runs every tic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Extrapolate&lt;/strong&gt; the target forward using stored momentum: &lt;code&gt;target_x &#43;= momx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smooth&lt;/strong&gt; toward the target, closing 60% of the remaining gap each tic:

&lt;pre&gt;&lt;code&gt;
#define INTERP_FRAC  39322  // 0.6 * 65536 (fixed-point)
mo-&amp;gt;x &#43;= FixedMul(target_x - mo-&amp;gt;x, INTERP_FRAC);
mo-&amp;gt;y &#43;= FixedMul(target_y - mo-&amp;gt;y, INTERP_FRAC);
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Teleport detection&lt;/strong&gt;: if the delta exceeds 128 map units, snap instantly (player respawned or hit a teleporter)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One subtle but critical detail: &lt;strong&gt;angle is NOT interpolated&lt;/strong&gt;. The ticcmd&amp;#39;s &lt;code&gt;angleturn&lt;/code&gt; field is applied deterministically by &lt;code&gt;P_MovePlayer()&lt;/code&gt; and stays in sync across machines. Interpolating angle toward a stale snapshot would &lt;em&gt;fight&lt;/em&gt; the ticcmd, causing visible rotation jitter of up to 90 degrees. We learned this the hard way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b) Attack Animation Sync&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remote players&amp;#39; attacks are driven by snapshot data, not ticcmds. When a snapshot reports &lt;code&gt;attack_weapon &amp;gt; 0&lt;/code&gt;, we set the &lt;code&gt;S_PLAY_ATK1&lt;/code&gt; animation state and play the weapon fire sound. An 8-tic animation lock prevents local state transitions from overriding it.&lt;/p&gt;

&lt;p&gt;To prevent feedback loops, we track &lt;code&gt;last_received_attack[]&lt;/code&gt; -the raw flag as received from the network -and broadcast &lt;em&gt;that&lt;/em&gt;, not the lock-modified mobj state. Without this, attack animations would echo infinitely.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;4-i-shot-you-no-you-didn-t-2&#34;&gt;4. &amp;#34;I Shot You!&amp;#34; &amp;#34;No You Didn&amp;#39;t!&amp;#34;&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-3-2&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;In the original DOOM, every computer runs its own copy of the game physics. When you shoot someone, &lt;em&gt;your&lt;/em&gt; computer calculates the damage, and &lt;em&gt;their&lt;/em&gt; computer calculates the damage, and because the game is in lockstep, they always agree.&lt;/p&gt;

&lt;p&gt;With our real-time model, that guarantee vanishes -your screen and theirs might show slightly different positions. So we made one player (the host) the referee. When you shoot someone, you tell the host &lt;em&gt;&amp;#34;I hit Player 2 for 50 damage&amp;#34;&lt;/em&gt;. The host checks the physics, applies the damage if it&amp;#39;s valid, and announces the result to everyone. One truth, no arguments.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-3-2&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;We implemented an &lt;strong&gt;event-based host-authority model&lt;/strong&gt; for all game-changing state:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Damage path:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Client A fires weapon → bullet hits Player B locally
  → Client A sends DAMAGE_EVENT to host: {target: B, damage: 50, source: A}
  → Client A applies VISUAL FEEDBACK ONLY (screen flash, attacker tracking)
  → Client A does NOT reduce Player B&amp;#39;s health

Host receives DAMAGE_EVENT:
  → Sets damage_from_event = true (bypasses remote-source skip)
  → Calls P_DamageMobj() with full physics simulation
  → New health broadcasted via HEALTH_AUTH packet next snapshot cycle

All clients receive HEALTH_AUTH:
  → Apply as ground truth
  → Host says dead, client says alive? → P_KillMobj()
  → Host says alive, client says dead? → Trigger respawn
  → Health decreased? → Play pain animation
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;damage_from_event&lt;/code&gt; flag is critical. Without it, the host faces a double-damage problem: it receives both the ticcmd attack (from the lockstep backbone) AND the explicit damage event. The flag ensures only the event path applies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Other host-authoritative systems:&lt;/strong&gt;
- &lt;strong&gt;USE events&lt;/strong&gt;: Client presses &amp;#39;E&amp;#39; near a door → sends &lt;code&gt;USE_EVENT&lt;/code&gt; → host calls &lt;code&gt;P_UseLines()&lt;/code&gt; → door opens for everyone
- &lt;strong&gt;Respawns&lt;/strong&gt;: Client dies → sends &lt;code&gt;RESPAWN_REQUEST&lt;/code&gt; → host sets &lt;code&gt;playerstate = PST_REBORN&lt;/code&gt;
- &lt;strong&gt;Kill messages&lt;/strong&gt;: Host broadcasts &lt;code&gt;KILL_MSG&lt;/code&gt; when a player dies → displayed on all screens&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;5-making-monsters-agree-2&#34;&gt;5. Making Monsters Agree&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-4-2&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;DOOM has dozens of monsters per level, each running their own AI -chasing you, shooting fireballs, infighting with each other. In the original game, every computer simulates every monster identically (because lockstep ensures they all see the same inputs). In our version, only the host simulates the monsters. Everyone else just sees the results -like watching a puppet show where only the puppeteer knows the script, but the audience sees the performance in real-time.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-4-2&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;We built a full NPC synchronisation system (&lt;code&gt;p_netsync.c/h&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Registry&lt;/strong&gt;: Every monster and barrel gets a unique &lt;code&gt;net_id&lt;/code&gt; via &lt;code&gt;P_NetAssignId()&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mobj_t *net_mobj_table[MAX_NET_MOBJS];  // 512 slots
unsigned short net_id_counter;            // Sequential allocator
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Host broadcasts&lt;/strong&gt; (every 2 tics) a compact binary snapshot:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[npc_count: u8][gametic: u16]
Per NPC (20 bytes): net_id(2) x(4) y(4) z(4) angle(1) statenum(2) health(2) flags(1)
[sector_count: u8]
Per changed sector (10 bytes): sector_id(2) ceiling(4) floor(4)
[missile_count: u8]
Per missile (32 bytes): source_net_id(2) type(2) x(4) y(4) z(4) momx(4) momy(4) momz(4) angle(4)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Client-side&lt;/strong&gt;: In &lt;code&gt;P_MobjThinker()&lt;/code&gt;, clients skip physics entirely for any mobj with &lt;code&gt;net_id &amp;gt; 0&lt;/code&gt;. Only the animation tic counter runs. State changes use &lt;code&gt;P_SetMobjStateNoAction()&lt;/code&gt; -which applies the visual state WITHOUT executing action functions. This prevents clients from independently spawning projectiles, running AI decisions, or playing duplicate sounds.&lt;/p&gt;

&lt;p&gt;The sector data keeps doors and lifts in sync. The missile data ensures fireballs and rockets appear on all screens.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;6-room-for-one-more-mid-game-joining-2&#34;&gt;6. &amp;#34;Room for One More?&amp;#34; -Mid-Game Joining&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-5-2&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;Original DOOM didn&amp;#39;t let you join a game already in progress. Everyone had to be there at the start, or too bad. Our version lets players drop in mid-game. You open the .xdc, the game finds the server, and you spawn in -even if everyone else is already knee-deep in the dead.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-5-2&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;Late joining required solving several hairy problems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tic synchronisation&lt;/strong&gt;: The late joiner&amp;#39;s tic counter is meaningless -they weren&amp;#39;t there for tics 0 through N. When the server accepts a late join, it sends &lt;code&gt;settings-&amp;gt;start_tic&lt;/code&gt; set to the current server tic. The client aligns its &lt;code&gt;recvtic&lt;/code&gt;, &lt;code&gt;maketic&lt;/code&gt;, and &lt;code&gt;gametic&lt;/code&gt; to this value, syncing the 8-bit tic sequence numbers with the server&amp;#39;s counter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Double-slot bug&lt;/strong&gt;: We found that &lt;code&gt;NET_SV_AssignPlayers()&lt;/code&gt; could assign the new client to a slot that was already used, creating a ghost duplicate. The fix: &lt;code&gt;HandleLateJoin()&lt;/code&gt; explicitly clears any pre-existing slots for the new client before assigning a fresh one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ghost body cleanup&lt;/strong&gt;: When a player disconnects and reconnects (or the quit/rejoin cycle fires), their old mobj lingers in the world as an invisible collision obstacle. &lt;code&gt;P_SpawnPlayer()&lt;/code&gt; now checks for and removes any existing mobj before spawning:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if (p-&amp;gt;mo) {
    p-&amp;gt;mo-&amp;gt;player = NULL;
    P_RemoveMobj(p-&amp;gt;mo);
    p-&amp;gt;mo = NULL;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Name propagation&lt;/strong&gt;: When a new player joins, every existing player re-broadcasts their name, so the joiner&amp;#39;s HUD displays the correct names instead of the defaults (&amp;#34;Green&amp;#34;, &amp;#34;Indigo&amp;#34;, &amp;#34;Brown&amp;#34;, &amp;#34;Red&amp;#34;).&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;7-fits-in-a-chat-message-2&#34;&gt;7. Fits in a Chat Message&lt;/h2&gt;

&lt;h3 id=&#34;the-simple-version-6-2&#34;&gt;The Simple Version&lt;/h3&gt;

&lt;p&gt;The entire game -engine, levels, monsters, weapons, networking, touch controls, gamepad support, all of it -fits in a &lt;strong&gt;4.2 megabyte file&lt;/strong&gt;. That&amp;#39;s smaller than most photos your phone takes. You send it in a chat message like you&amp;#39;d send a meme. Your friend taps it, and they&amp;#39;re in the game. No app store, no downloads, no accounts, no updates.&lt;/p&gt;

&lt;h3 id=&#34;the-nerdy-version-6-2&#34;&gt;The Nerdy Version&lt;/h3&gt;

&lt;p&gt;The .xdc format is just a ZIP archive with a different extension. Ours contains:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Size (compressed)&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vector-doom.wasm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~2.7 MB&lt;/td&gt;
&lt;td&gt;Chocolate Doom engine (Emscripten, -O3)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doom1.wad&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~1.7 MB&lt;/td&gt;
&lt;td&gt;DOOM shareware levels (freely distributable)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;vector-doom.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~160 KB&lt;/td&gt;
&lt;td&gt;Emscripten runtime (terser-minified, 58% reduction)&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~12 KB&lt;/td&gt;
&lt;td&gt;UI, touch controls, gamepad support, CRT visual theme&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;webxdc-net.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~3 KB&lt;/td&gt;
&lt;td&gt;Server election &#43; packet routing&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;icon.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~90 KB&lt;/td&gt;
&lt;td&gt;App icon&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bg.jpg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~100 KB&lt;/td&gt;
&lt;td&gt;Background artwork&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;default.cfg&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~2 KB&lt;/td&gt;
&lt;td&gt;Default key bindings&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manifest.toml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~100 B&lt;/td&gt;
&lt;td&gt;WebXDC metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The WASM binary and WAD compress extremely well in ZIP (65% and 58% respectively), bringing the total to 4.2MB.&lt;/p&gt;

&lt;p&gt;The build pipeline:
1. Emscripten compiles Chocolate Doom &#43; our modifications to WASM (&lt;code&gt;emmake make -j4&lt;/code&gt;)
2. &lt;code&gt;webxdc-net.js&lt;/code&gt; is injected as &lt;code&gt;--pre-js&lt;/code&gt; (runs before WASM initialises)
3. JS is minified with terser in parallel
4. HTML is minified (strip comments, collapse whitespace)
5. Everything zipped at maximum compression (&lt;code&gt;zip -9&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;The game runs on any WebXDC-compatible messenger. We built it for &lt;a href=&#34;https://vector.im&#34;&gt;Vector&lt;/a&gt; (a Nostr-based messenger), but it works in &lt;a href=&#34;https://delta.chat/&#34;&gt;Delta Chat&lt;/a&gt; and potentially any app that implements the WebXDC standard.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;the-full-stack-from-keypress-to-frag-2&#34;&gt;The Full Stack, From Keypress to Frag&lt;/h2&gt;

&lt;p&gt;Here&amp;#39;s what happens when you press the fire button on your phone:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1. Your finger hits the Fire button (HTML touch event)
2. JavaScript calls Module._inject_key_event(0, 32)     // keydown, spacebar
3. DOOM&amp;#39;s event queue receives ev_keydown
4. D_ProcessEvents() → G_Responder() builds ticcmd with BT_ATTACK
5. TryRunTics() executes the tic -your weapon fires, P_LineAttack() traces a hitscan
6. Bullet hits Player 2 → P_DamageMobj() → instead of applying damage:
   → NET_CL_SendDamageEvent(target=2, damage=50, source=you)
7. Every 2 tics, your position snapshot broadcasts via realtimeChannel:
   → JS encodes [to(4)][from(4)][snapshot] → WebSocket → Iroh gossip → peer devices
8. Host receives damage event → validates → applies → broadcasts HEALTH_AUTH
9. Player 2&amp;#39;s screen: health drops, pain flash plays, kill message appears
10. Your screen: the host&amp;#39;s HEALTH_AUTH confirms the kill
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Total time from keypress to kill confirmation: roughly 100-200ms depending on network conditions. No servers touched. No corporation involved. Just two chat apps talking directly to each other.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;standing-on-the-shoulders-of-giants-2&#34;&gt;Standing on the Shoulders of Giants&lt;/h2&gt;

&lt;p&gt;None of this would exist without:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.idsoftware.com/&#34;&gt;id Software&lt;/a&gt;&lt;/strong&gt; for open-sourcing the DOOM engine in 1997 -a decision that created an entire modding ecosystem and directly enabled everything described here&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://www.chocolate-doom.org/&#34;&gt;Chocolate Doom&lt;/a&gt;&lt;/strong&gt; for faithfully recreating the original engine in portable, hackable C&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://blog.cloudflare.com/doom-multiplayer-workers/&#34;&gt;Cloudflare&lt;/a&gt;&lt;/strong&gt; for proving DOOM-in-WebAssembly was viable and open-sourcing their &lt;a href=&#34;https://github.com/cloudflare/doom-wasm&#34;&gt;doom-wasm&lt;/a&gt; port -the foundation we forked&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://emscripten.org/&#34;&gt;Emscripten&lt;/a&gt;&lt;/strong&gt; for making C-to-WASM compilation actually work&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&#34;https://iroh.computer/&#34;&gt;Iroh&lt;/a&gt;&lt;/strong&gt; (by n0.computer) for the QUIC-based P2P gossip protocol that makes serverless real-time gaming possible&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;a href=&#34;https://webxdc.org/&#34;&gt;WebXDC&lt;/a&gt; community&lt;/strong&gt; for defining an open standard for sandboxed web apps in chat messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a special note: the networking architecture of Open Source DOOM was designed and implemented as a collaboration between a human developer and an AI (&lt;a href=&#34;https://claude.ai&#34;&gt;Claude&lt;/a&gt;, by Anthropic). Not generated and pasted -&lt;em&gt;collaborated on.&lt;/em&gt; Hundreds of iterations, debugging sessions at 3am with hex dumps of gossip packets, heated debates about whether to interpolate angles (don&amp;#39;t), and moments of genuine surprise when things just... worked.&lt;/p&gt;

&lt;hr&gt;

&lt;h2 id=&#34;try-it-2&#34;&gt;Try It&lt;/h2&gt;

&lt;p&gt;Open-Source DOOM is free, open-source, and available today.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://image.nostr.build/90497863e88cc21741a1493be081716f5af3664eced7fbdb063c8f783df534fd.jpg&#34; alt=&#34;image&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play it&lt;/strong&gt;: Download &lt;a href=&#34;https://vectorapp.io&#34;&gt;Vector&lt;/a&gt;, open &lt;strong&gt;Vector Nexus&lt;/strong&gt; (our decentralised in-app Mini App store), and find &lt;strong&gt;DOOM&lt;/strong&gt; in the Multiplayer category. Send it to a friend or group chat and start fragging - no manual file management needed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://image.nostr.build/149d09299e73fe56d904f9116b67c22b67935d36b4e263f346d7a179bac605b7.jpg&#34; alt=&#34;image&#34;/&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the code&lt;/strong&gt;: The full source is available at &lt;a href=&#34;https://github.com/VectorPrivacy/DOOM&#34;&gt;github.com/nicholasopuni31/doom-wasm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build on it&lt;/strong&gt;: The WebXDC realtime channel pattern we developed here works for any real-time multiplayer game.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If DOOM is &amp;#34;Hello, World&amp;#34; for computing, then Open Source DOOM is &amp;#34;Hello, World&amp;#34; for decentralised gaming.&lt;/em&gt;&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;em&gt;Published March 2026. Written by&lt;/em&gt; &lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Person&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/npub16ye7evyevwnl0fc9hujsxf9zym72e063awn0pvde0huvpyec5nyq4dg4wn&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;&lt;span&gt;JSKitty&lt;/span&gt; (&lt;span class=&#34;italic&#34;&gt;npub16ye…g4wn&lt;/span&gt;)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
 &lt;/blockquote&gt;
    </content>
    <updated>2026-05-21T12:40:11Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsgevgrmwjmsf2slxmd9fptx6mrp2jk7rrkt43n2amauqghhnqqkvszyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjhwydul</id>
    
      <title type="html">Lost Oddysey Bellissimo jrpg ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsgevgrmwjmsf2slxmd9fptx6mrp2jk7rrkt43n2amauqghhnqqkvszyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjhwydul" />
    <content type="html">
      Lost Oddysey &lt;br/&gt;Bellissimo jrpg  &lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt; &lt;img src=&#34;https://blossom.primal.net/bba17adc9165c28a656de3303c8cf54bbdd7432d18eebeec18d4aae36855c457.png&#34;&gt; 
    </content>
    <updated>2026-05-21T12:22:11Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsfafcwvsm6g8384eq3nc6wq04u9duywe5vdlp5m24vpa6cda42e7szyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjgs9fqr</id>
    
      <title>Nostr event nevent1qqsfafcwvsm6g8384eq3nc6wq04u9duywe5vdlp5m24vpa6cda42e7szyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjgs9fqr</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsfafcwvsm6g8384eq3nc6wq04u9duywe5vdlp5m24vpa6cda42e7szyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjgs9fqr" />
    <content type="html">
       &lt;img src=&#34;https://image.nostr.build/b459a0510425feeb9e34e37d5cb3152efde688ff21c4bef97c298e9c3d240d60.jpg&#34;&gt;  Valen - Terra di nessuno 
    </content>
    <updated>2026-03-10T19:21:54Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqspqsnqus5w7j0yk609jp7k8304j93cxdxd5k35tmw3sgzmv8car0qzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjd0mg9x</id>
    
      <title type="html">Ci ho messo circa una ventina di minuti. È stato magico, direi ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqspqsnqus5w7j0yk609jp7k8304j93cxdxd5k35tmw3sgzmv8car0qzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjd0mg9x" />
    <content type="html">
      Ci ho messo circa una ventina di minuti.&lt;br/&gt;È stato magico, direi la boss fight più bella di Hollow Knight &lt;br/&gt;&lt;blockquote class=&#34;border-l-05rem border-l-strongpink border-solid&#34;&gt;&lt;div class=&#34;-ml-4 bg-gradient-to-r from-gray-100 dark:from-zinc-800 to-transparent mr-0 mt-0 mb-4 pl-4 pr-2 py-2&#34;&gt;quoting &lt;br/&gt;&lt;span itemprop=&#34;mentions&#34; itemscope itemtype=&#34;https://schema.org/Article&#34;&gt;&lt;a itemprop=&#34;url&#34; href=&#34;/nevent1qqsgl6r86q847jh96d99y3g2xcung8u0ezkg5ny0thhedwd8hk8h2fqprpmhxue69uhkummnw3ezuv33vde8jur5duhxx6p0qgszpzksxyuwkvk6fvlm9mdhn5f63c6n9ppdkcnaw6hls95dk4j2p6grqsqqqqqphf0cf0&#34; class=&#34;bg-lavender dark:prose:text-neutral-50 dark:text-neutral-50 dark:bg-garnet px-1&#34;&gt;nevent1q…0cf0&lt;/a&gt;&lt;/span&gt; &lt;/div&gt; Letteralmente un incubo 😅 &lt;br/&gt;Però che sound, che boss fight incredibile  &lt;img src=&#34;https://image.nostr.build/f42ba5929dca57edf00fe845dc480cdfa826a453b23d29a7b64d9b4ca813c5bf.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/8754eaed8abef28c312649a672a70027d1b7fbda698cc4adb597fb0dbad110cf.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/1c205889b766e0ce566b974f0de01290b39079166df822f2968cf4e557c60497.jpg&#34;&gt;  &lt;video controls width=&#34;100%&#34; class=&#34;max-h-[90vh] bg-neutral-300 dark:bg-zinc-700&#34;&gt;&lt;source src=&#34;https://video.nostr.build/930c7986092ee1fe11200bec4a2bd116984a2e44f1fc52de72e915b7493e4316.mp4&#34;&gt;&lt;/video&gt; &lt;/blockquote&gt;
    </content>
    <updated>2026-01-28T07:31:48Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsgl6r86q847jh96d99y3g2xcung8u0ezkg5ny0thhedwd8hk8h2fqzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjlp05lg</id>
    
      <title type="html">Letteralmente un incubo 😅 Però che sound, che boss fight ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsgl6r86q847jh96d99y3g2xcung8u0ezkg5ny0thhedwd8hk8h2fqzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswjlp05lg" />
    <content type="html">
      Letteralmente un incubo 😅 &lt;br/&gt;Però che sound, che boss fight incredibile  &lt;img src=&#34;https://image.nostr.build/f42ba5929dca57edf00fe845dc480cdfa826a453b23d29a7b64d9b4ca813c5bf.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/8754eaed8abef28c312649a672a70027d1b7fbda698cc4adb597fb0dbad110cf.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/1c205889b766e0ce566b974f0de01290b39079166df822f2968cf4e557c60497.jpg&#34;&gt;  &lt;video controls width=&#34;100%&#34; class=&#34;max-h-[90vh] bg-neutral-300 dark:bg-zinc-700&#34;&gt;&lt;source src=&#34;https://video.nostr.build/930c7986092ee1fe11200bec4a2bd116984a2e44f1fc52de72e915b7493e4316.mp4&#34;&gt;&lt;/video&gt;
    </content>
    <updated>2026-01-27T17:25:26Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsdhvsu8x6vhgmkddupg9vwsm9m8eqxdv5v8srw9cvffkh4c9zexvczyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj9f9wqf</id>
    
      <title>Nostr event nevent1qqsdhvsu8x6vhgmkddupg9vwsm9m8eqxdv5v8srw9cvffkh4c9zexvczyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj9f9wqf</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsdhvsu8x6vhgmkddupg9vwsm9m8eqxdv5v8srw9cvffkh4c9zexvczyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj9f9wqf" />
    <content type="html">
      &lt;video controls width=&#34;100%&#34; class=&#34;max-h-[90vh] bg-neutral-300 dark:bg-zinc-700&#34;&gt;&lt;source src=&#34;https://video.nostr.build/7d2679be17b9a840f13d811924b01ac1d684392bd344092d3bda3a8e99158885.webm&#34;&gt;&lt;/video&gt;&lt;br/&gt;Geniale 😂
    </content>
    <updated>2026-01-27T14:32:00Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsf42ptc26l9fzsxrraq4p438svtqddn3yrj9mhelmmycgjz3aksnszyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj3sr9rn</id>
    
      <title type="html">Tanto bello quanto faticoso 😅 Uno dei momenti più alti di ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsf42ptc26l9fzsxrraq4p438svtqddn3yrj9mhelmmycgjz3aksnszyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj3sr9rn" />
    <content type="html">
      Tanto bello quanto faticoso 😅 &lt;br/&gt;Uno dei momenti più alti di Hollow Knight 🤍  &lt;img src=&#34;https://image.nostr.build/009088a8c947543dd6b6a5461855f423af02b82688c80648f74b9279f56cb718.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/6d1ef1ce63e32a31e9291511136ecf8a77f1ebe2882e0552dd0957f20e439f76.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/3d112aa47f8b441e40470756e6123ce6bc6ad692ea1db1fefc7f32ea5adc589d.jpg&#34;&gt;   &lt;img src=&#34;https://image.nostr.build/f3fefc68ebb7860074d2439c900411dde5f04df2679aefef2d41f26c45f87ed3.jpg&#34;&gt; 
    </content>
    <updated>2026-01-27T13:00:48Z</updated>
  </entry>

  <entry>
    <id>https://nostr.ae/nevent1qqsyqasqxufyr76n6hh5jyk6ffye0g4namk5e6evnhdudje3rgyu8qqzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj7em5zh</id>
    
      <title type="html">Non vedo l&amp;#39;ora di provarlo. è un progetto molto ambizioso, ...</title>
    
    <link rel="alternate" href="https://nostr.ae/nevent1qqsyqasqxufyr76n6hh5jyk6ffye0g4namk5e6evnhdudje3rgyu8qqzyqsg45p38r4n9kjt87ewmduazw5wx5eggtdkyltk4lupdrd4vjswj7em5zh" />
    <content type="html">
      Non vedo l&amp;#39;ora di provarlo.&lt;br/&gt;è un progetto molto ambizioso, vedremo come sarà il prodotto finale &lt;br/&gt;#fable  &lt;br/&gt;&lt;br/&gt;&lt;br/&gt;&lt;br/&gt; &lt;img src=&#34;https://blossom.primal.net/4c66ca16548963d8d0bc1a757cb53830415d0a1c5817a3d5c4c8f751d6e1b7c9.jpg&#34;&gt; 
    </content>
    <updated>2026-01-23T10:26:37Z</updated>
  </entry>

</feed>