Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

arena: spectator polish — hide own body, see own avatar, leave on exit

Three user-visible fixes in the multi-tab flow:

1. Local body (feet/arms, plumb line, shadow) was still rendering
while spectating, making it look like the spectator cam had a
ghost body. Now gated on !netSpectator — when another tab takes
over, this tab shows pure noclip free-fly cam.

2. Spectator couldn't see themselves being driven by the other tab.
onSnap previously routed any p.h === myHandle blob to
myServerState and dropped it from the renderable-remotes set.
Now, when netSpectator is true, the "me" entry is *also* pushed
into the interpolation buffer so paintRemotes draws it like any
other stick figure. Cleanup on returning to play mode: drop the
self entry from `others` so paint doesn't double-draw.

3. Added a leave() export that sends arena:bye. Without it, the
server had to wait 30s (stale sweep) before removing the player
after a navigate-away. Now it's instant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+28 -13
+28 -13
system/public/aesthetic.computer/disks/arena.mjs
··· 187 187 } 188 188 const seen = new Set(); 189 189 for (const p of blobs) { 190 - if (p.h === myHandle) { 190 + const isMe = p.h === myHandle; 191 + if (isMe) { 191 192 myServerState = p; 192 193 myServerStateMs = snap.serverMs; 193 194 myServerAckCmdMs = typeof snap.ackCmdMs === "number" ? snap.ackCmdMs : myServerAckCmdMs; 194 - continue; 195 + // While spectating, our "me" entry is being driven by another tab — 196 + // render it as just another remote stick figure so we can watch. 197 + // Otherwise skip (cam-doll is already drawing us locally). 198 + if (!netSpectator) continue; 195 199 } 196 200 seen.add(p.h); 197 201 let o = others[p.h]; ··· 210 214 }); 211 215 while (o.buffer.length > 32) o.buffer.shift(); 212 216 } 217 + // If we just left spectator mode, drop the self entry we had been tracking. 218 + if (!netSpectator && others[myHandle]) delete others[myHandle]; 213 219 // Prune others not in this snap for >2s (graceful drop). 214 220 for (const h of Object.keys(others)) { 215 221 if (seen.has(h)) continue; ··· 1805 1811 if (!phys.onGround) activeShadow = shadowAir; 1806 1812 else if (phys.crouch > 0.5) activeShadow = shadowCrouch; 1807 1813 } 1808 - // Only draw ground-anchored shadow/plumb while on solid ground. 1814 + // Only draw ground-anchored shadow/plumb while on solid ground AND we're 1815 + // playing (spectators are flying around without a body — no shadow). 1809 1816 const onSolidGround = phys?.onGround; 1810 - if (activeShadow && onSolidGround) ink(255, 255, 255).form(activeShadow); 1811 - if (plumbLine && onSolidGround && plumbLine.scale[1] > 0.05) { 1812 - ink(255, 255, 255).form(plumbLine); 1813 - } 1814 - // Feet + arms render regardless of ground state (they fall with you). 1815 - // Dropped entirely in LOW perf mode — wireframes are nice-to-have. 1816 - if (!perfLowMode) { 1817 - if (bodyFeet) ink(255).form(bodyFeet); 1818 - if (bodyArms) ink(255).form(bodyArms); 1817 + if (!netSpectator) { 1818 + if (activeShadow && onSolidGround) ink(255, 255, 255).form(activeShadow); 1819 + if (plumbLine && onSolidGround && plumbLine.scale[1] > 0.05) { 1820 + ink(255, 255, 255).form(plumbLine); 1821 + } 1822 + // Feet + arms render regardless of ground state (they fall with you). 1823 + // Dropped entirely in LOW perf mode — wireframes are nice-to-have. 1824 + if (!perfLowMode) { 1825 + if (bodyFeet) ink(255).form(bodyFeet); 1826 + if (bodyArms) ink(255).form(bodyArms); 1827 + } 1819 1828 } 1820 1829 1821 1830 // 🏟️ Remote players (interpolated from server snapshots, rendered ~100ms behind). ··· 2342 2351 }; 2343 2352 } 2344 2353 2354 + // 🏟️ Lifecycle: tell the server we're leaving so our player record is 2355 + // deleted immediately instead of waiting for the 30s stale sweep. 2356 + function leave() { 2357 + try { netServer?.send("arena:bye", { handle: myHandle }); } catch {} 2358 + } 2359 + 2345 2360 export const system = "fps"; 2346 - export { boot, sim, paint, act }; 2361 + export { boot, sim, paint, act, leave };