Architecture

Prismarine Viewer

👁️ Prismarine Viewer#

Browser-based 3D visualization of Mineflayer bots using Three.js + WebGL.

Quick Start#

const { mineflayer: mineflayerViewer } = require('prismarine-viewer')

bot.once('spawn', () => {
  mineflayerViewer(bot, { port: 3007, firstPerson: true })
})

Configuration#

Option Type Default Description
port number 3000 Web server port
firstPerson boolean false true = bot’s eyes, false = free cam
viewDistance number 6 Render distance in chunks
prefix string '' URL prefix (e.g., /viewer)

Moincraft Wiring#

  • Global viewer: bots/viewer.js → port 55669
  • Per-agent POV: Extra Prismarine instance on agent.viewerPort (direct hostname:port)
  • Dashboard iframe: Viewer.svelte switches between global feed and per-agent feeds
  • Proxy mode: Set VITE_USE_VIEWER_PROXY (default) → uses /viewer/ path (same origin, avoids mixed content)
  • Direct mode: http(s)://<current-host>:<port> via getDirectViewerUrl()

Controls#

  • W/A/S/D: Move camera (third person)
  • Space/Shift: Up/down
  • Mouse drag: Look around
  • Click: Interact (if enabled)

Version Compatibility Layer#

Server runs 1.21.11 but prismarine-viewer supports up to 1.21.4:

Proxy(bot) → version: "1.21.4" (renderVersion)
           → world.getColumnAt() → column.toJson() → remapChunkJsonPalette()
                palette stateIds: 1.21.11 space → 1.21.4 space
           → bot.on('blockUpdate') → remapped stateId

Env overrides: VIEWER_RENDER_VERSION, VIEWER_VERSION_FALLBACK=false

Performance Tuning#

The Golden Rule: View Distance#

Setting Loaded Chunks Recommendation
6 (default) ~169 chunks Too heavy for swarm
3 ~49 chunks Sweet spot — 75% reduction

CPU Relief#

mineflayerViewer(bot, {
  port: 3000,
  firstPerson: true,
  viewDistance: 3,   // ← key setting
})

Air Chunk Bottleneck#

  • Symptom: Bot freezes 10-30s on start
  • Cause: Prismarine generates empty “air” chunks on main thread
  • Fix: Wait for viewer to stabilize before complex movements

Browser-Side#

  • Reduce window size (fewer pixels)
  • Enable hardware acceleration in Chrome/Edge
  • Refresh page periodically (memory leak mitigation)

Entity Tracking#

Lower entity-tracking-range in spigot.yml to reduce WebSocket spam to the viewer.

Headless Vision (LLM Screenshots)#

const browser = await puppeteer.launch({
  headless: "new",
  args: ['--no-sandbox', '--disable-setuid-sandbox']  // Linux/Docker essential
});

Tips:

  1. Pause rendering when bot isn’t looking
  2. 640×480 is enough for LLM to “see” — don’t screenshot at 4K
  3. Use dedicated “Spectator” bot to avoid impacting agent logic

Embedding in Dashboard#

<iframe src="http://localhost:3007" width="100%" height="500px" frameborder="0"></iframe>

Blank iframe troubleshooting:

  • Dashboard HTTPS + per-agent HTTP = mixed content blocked → use proxy
  • Bot hasn’t spawned / received chunks → wait for spawn event
  • Port not open → check firewall

Reconnect Strategy#

Exponential backoff: min(base × 2^attempts, max) + random(jitter)

Setting Default
VIEWER_RECONNECT_BASE_MS 5000
VIEWER_RECONNECT_MAX_MS 60000
VIEWER_RECONNECT_JITTER_MS 1500
VIEWER_RECONNECT_DUPLICATE_MS 30000

Duplicate login: fixed 30s wait. Version mismatch kick: auto-fallback to version: auto.