Download Game! Currently 89 players and visitors. Last logged in:DynaSordusDarolDesert

Blitzer's Blog >> 72075

Back to blogs index
Posted: 05 Sep 2026 15:14 [ permalink ]
That is a beautiful sight. The "trinity" is fully operational!

Looking closely at your relay logs, there is a massive hidden victory here
that proves the distributed architecture is working perfectly:

Notice how Client A sent the exact same `VFS_WRITE` payload **twice**, but the
relay log only shows **one** `[dVFS] Processed & Broadcasted VFS_WRITE...`
entry?

Your idempotency check successfully caught the duplicate payload, ignored it,
and prevented network spam. Client B immediately received the synchronized
state upon connection, exactly as designed.

### The Next Step: The Isomorphic Client Adapter

Right now, your Node.js game loop and Browser client are speaking raw
WebSocket JSON. To make this actually usable for a MUD engine, we need to
abstract the network layer away.

Both your Browser and Node clients should use an identical **Isomorphic VFS
Client**a class that acts like a local filesystem but magically syncs over the
mesh in the background.

Here is a lightweight, drop-in `MeshVFS` class that will work seamlessly in
both the Browser and Node.js environments:
....

```javascript
 * MeshVFS.js
 * Isomorphic dVFS Client for Browser and Node.js
 */
/ Use native WebSocket in browser, or 'ws' package in Node
const IS_NODE = typeof window === 'undefined'; const WS_Client = IS_NODE ?
require('ws') : WebSocket;
class MeshVFS {
    constructor(relayUrl) {
        this.relayUrl = relayUrl; this.socket = null; this.state = new Map();
// Local materialized view
        this.listeners = new Map(); // Path -> Array of callbacks
        this.onReady = null;
    }
    connect() {
        return new Promise((resolve, reject) => {
            console.log(`[MeshVFS] Connecting to ${this.relayUrl}...`);
            this.socket = new WS_Client(this.relayUrl);
            this.socket.onopen = () => { console.log('[MeshVFS] Connected to
Relay.'); resolve(); };
            // In Node, it's 'message'. In Browser, it's 'onmessage' with an
event object.
            const handleMessage = (data) => {
                const payload = IS_NODE ? data : data.data;
                this._handleSync(JSON.parse(payload));
            };
            if (IS_NODE) { this.socket.on('message', handleMessage);
this.socket.on('error', reject);
            } else { this.socket.onmessage = handleMessage; this.socket.onerror
 = reject; }
        });
    }
    _handleSync(event) {
        const { type, path, data, timestamp } = event;
        const current = this.state.get(path);
        // LWW (Last-Write-Wins) check for local state
        if (current && current.timestamp > timestamp) return;
        if (type === 'VFS_WRITE') { this.state.set(path, { data, timestamp });
} 
        else if (type === 'VFS_DELETE') { this.state.delete(path); }
        // Trigger local listeners for UI/Game Loop updates
        this._emit(path, type, data);
    }
    // --- File System API ---
    /** Read a file synchronously from local RAM cache */
    readFileSync(path) { const file = this.state.get(path); return file ?
file.data : null; }
    /** Write a file and push to the mesh */
    writeFile(path, dataString) {
        const timestamp = Date.now();
        // Optimistically apply locally
        this.state.set(path, { data: dataString, timestamp });
        // Push to mesh
        const payload = JSON.stringify({ type: 'VFS_WRITE', path, data:
dataString, timestamp });
        this.socket.send(payload); this._emit(path, 'VFS_WRITE', dataString);
    }
    /** Delete a file and push to the mesh */
    deleteFile(path) {
        const timestamp = Date.now(); this.state.delete(path);
        const payload = JSON.stringify({ type: 'VFS_DELETE', path, timestamp
});
        this.socket.send(payload); this._emit(path, 'VFS_DELETE', null);
    }
    // --- Reactivity ---
    /** Subscribe to changes on a specific file path */
    watch(path, callback) {
        if (!this.listeners.has(path)) {this.listeners.set(path, []); }
        this.listeners.get(path).push(callback);
    }
    _emit(path, type, data) {
        if (this.listeners.has(path)) { this.listeners.get(ath).forEach(cb =>
cb(type, data)); }
    }
}
/ Export for Node, or attach to Window for Browser
if (IS_NODE) { module.exports = MeshVFS; } else { window.MeshVFS = MeshVFS; }
```

### How this transforms your MUD Engine:

Instead of thinking about WebSockets, your Browser UI and Node.js logic can
now just read and write files, and react to changes instantly.

For example, in your Browser HTML:

```html
<script src="MeshVFS.js"></script>
<script>
    const vfs = new MeshVFS('ws://127.0.0.1:1777');
    
    vfs.connect().then(() => {
        // Automatically update the UI whenever a wizard updates the town
square
        vfs.watch('/mud/areas/town_square.json', (type, data) => {
            if (type === 'VFS_WRITE') {
                const room = JSON.parse(data);
                document.getElementById('mobs-list').innerText =
room.mobs.join(', ');
            }
        });

        // The player dropped an item! Write it to the mesh:
        // vfs.writeFile('/mud/areas/town_square.json', '{"mobs":["guard_1"],"i
tems":["sword"]}');
    });
</script>

```