"How far along is your base layer?" needs two rulers. Measuring "is it usable today" — yes: a fully usable self-hosted 3D virtual world foundation whose rendering kernel (Three.js r128→r185/WebGL2, CDN-free), asset pipeline (118 LOD variants, GLB textures −68%~−92%, 3DGS 26/26), performance governance (draw calls 3064→837, the light pool eliminating an 8989 ms freeze), multi-client adaptation, real-time communication (weak-network self-healing 9/9), AI access (≈1 KB/s per agent, 100 agents at 0.079 CPU cores), and cross-world federation (same-name auto-rename 4/4) are all running now, each backed by re-runnable acceptance scripts. Measuring "how far the direction can go" — against the form browser-based 3D virtual worlds can eventually take, the base layer covers roughly 5%–8%; the two statements must be read together: the base layer is fully usable, and more than ninety percent of headroom remains — the number expresses opportunity, not debt. Above it sit four planned items (AI-assembled worlds, an agent store, agent interoperability via A2A, cross-world federated AI), each mapped to "which base-layer capability is already proven and which segment is missing," with the explicit declaration that none are implemented and none should be evaluated as shipped features. Layer-5 business logic — showrooms, training, community worlds — has a complete landing surface today.
3D virtual world base layerself-hosted 3D worldThree.js foundationbrowser-based 3D3D world developmentAI agent accesscross-world federationprivate 3D deploymentvirtual world roadmapMCP Server
Hand-modeled content always looks like a model; scenes scanned from reality carry photographic texture — 3D Gaussian Splatting (3DGS) fills the "a scanned scene you can walk into" slot. This article covers the full trade-offs of building 3DGS in-house inside our own browser-based 3D virtual world base layer: why not adopt an existing library (dependency discipline plus pipeline consistency — GLSL1-style code compiles under r185/WebGL2, and no double gamma encoding, both test-confirmed), the four engineering pieces (binary PLY parsing including spherical-harmonics coefficients f_rest_0..8; BufferGeometry + ShaderMaterial + Points with the full set uploaded to the GPU in one pass; world lifecycle integration with placeholders, dispose, and placeholder restore; library-style asset management where uploading equals cataloging), five supported formats (.rad/.ply/.spz/.splat/.ksplat), acceptance at 26/26 with 24,000 points actually drawn, and zero third-party 3DGS library dependencies. Stated just as plainly: the acceptance sample is a script-generated INRIA-standard 62-property PLY, so the end-to-end chain with real scan data remains untested; frame rates at large Gaussian counts on weak devices are not fully measured; and 3DGS has no editable mesh, so collision and interaction assets should remain geometric models — 3DGS handles "looks real," geometric models handle "touchable and editable."
3D Gaussian Splatting3DGS browser renderingreal-world scan 3Dphotorealistic scenesThree.js 3DGSPLY parsingspherical harmonicsself-hosted 3D virtual worldphotographic showroom
A 3D world that runs for years almost inevitably grows orphan assets — models uploaded and never used, files whose references were removed, and a sneakier kind: glTF-family assets separate "JSON metadata" from "BIN buffers," so deleting an animation by editing only the JSON without rebuilding the BIN leaves orphaned bytes inside the file that nothing ever reads. This article walks through the full asset audit of our own browser-based 3D virtual world: the method (reference list versus disk list, set difference, manual spot-check before deletion), the results — 159 orphan files totaling 2.9 GB removed from the scene asset library, shrinking it from 3.1 GB to 390 MB (completed) — and the character template library, where 79.3 MB of 205.5 MB is structural orphan data (concentrated in 4 files, the worst one 93.4% garbage), with the cleanup plan ready but not yet executed. The projected post-cleanup cross-world first screen drops from tens of seconds to about 1–2 seconds; that is an estimate, not a measurement, and the article deliberately separates finished work from computed-but-pending work, explaining why the cleanup waits (BIN rebuild carries write risk, benefit unmeasured, 30-day immutable caching amplifies operational risk).
3D asset managementorphan asset cleanupGLB asset optimization3D virtual world deploymentglTF BIN buffersasset auditcross-world loading speedThree.js asset pipeline3D model slimmingself-hosted 3D world
"Supports phones" is usually deferred in 3D projects, but rewriting a separate mobile build isn't the answer: desktop-only mouse interactions don't exist on touch, while phone-only memory ceilings and background freezes never occur on desktop. This article proposes tiering by capability rather than forking by device — four tiers (high/mid/low/XR) detected at runtime instead of three codebases per device type — and lists the pitfalls per client: on phones memory crashes before frame rate does (four leaks fixed in a memory audit), tablets are the most underestimated tier, the desktop problem is that your dev machine is too good (hence diagnostics like diagTurnLag rather than intuition), and XR is the only client where missing frame rate means unusable. Reusable figures include asset tiering (118 low-poly variants ≤100 faces, triangle count −71%~−87%, textures −68%~−92%, draw calls 3064→837, a placeholder field covering 1071/1071 in one draw call), the warm-up budget (170 ms per frame, 386 ms worst-case first arrival), the light pool (eliminating an 8989 ms full-scene freeze), and weak-network reconnect self-healing at 9/9. Stated explicitly: we have not completed measured mobile and XR frame rates; every number comes from desktop acceptance scripts.
3D multi-device adaptationbrowser 3D mobile performancephone 3D stutterdraw call optimizationLOD asset tieringshader warm-uplight poolWebGL2 compatibilityweak-network reconnectmultiplayer bandwidth budget3D memory leak
Writing a browser-based 3D scene from scratch isn't hard; making it hold up on real devices and real networks is. This article lays out four hidden costs of building from zero: double gamma in the color pipeline (no error, image too bright and too pink — verified with 10 fixed-protocol baseline screenshots plus a self-built PSNR/diff tool, admin console matching at 43.4 dB), the loading and warm-up budget (170 ms per frame, 386 ms worst-case first arrival, 0 frames over 500 ms), draw calls and the light pool (3064→837, −73%; a fixed light count drove recompiles to zero, eliminating an 8989 ms full-scene freeze), and weak-network reconnect self-healing (9/9 cases where the peer still sees movement after reconnect). The through-line: none of these four produce errors, which is exactly why they never become a to-do item when you build from scratch. Then the five-layer boundary table — the first four layers are business-independent and live in the base layer; layer 5, your business logic, is yours. The article also covers when this decision is wrong: one-off static showcases, learning-oriented projects, very low-end runtimes, and anything that goes offline when it's done.
3D virtual world base layerlayered 3D architecturebuilding 3D from scratchdraw call optimizationThree.js performance governanceLOD asset pipelineweak-network reconnectself-hosted 3D worldbrowser 3D architectureAI agent in 3D3D project technology choice
Slow loading, progress bars stuck at 90%, and mobile crashes caused by oversized models usually trace back to the asset file, not the code. This article describes a GLB surgery approach running in the upload pipeline: rewriting via JSON + BIN so geometry is untouched, and compressing textures by purpose (lossless re-encoding for normal and occlusion maps, palette quantization for base color). Measured: a desk from 25.74 MB to 8.22 MB (−68.1%) and a 20.7 MB multi-buffer 4K model to 4.38 MB (−92.5%), at 31.4dB PSNR with 0.35% differing pixels. The hard part isn't compression but binary layout: bufferView reordering, accessor index remapping, meshopt byteOffset shifting, per-chunk checks for multi-buffer files. Five gates (mesh name / compression / multi-buffer / geometry consistency / read-back) ensure failure skips rather than writes — variant texture stripping measured 215 items with 0 failures. Face count is handled separately with a guaranteed 118/118 low-poly variants at ≤100 faces, and variants share high-poly materials so tiers cost almost no extra VRAM.
GLB compressionmodel size reductiontexture compressionbase color palette quantizationPSNR verificationmodel LOD100-face low poly budget3D asset pipelinebrowser 3D loading optimizationmeshopt
Evaluating a 3D world's cost can't stop at asking for a quote, because its cost structure has three parts. Linear in visitors: bandwidth and realtime compute, with a measured first screen of 838 KB across 99 requests loading in 1.7 seconds. Roughly constant: performance work, asset pipelines, multi-device adaptation, realtime and AI integration — a light pool eliminated an 8989 ms full-scene freeze, a warm-up budget pushed long frames under 500 ms, GLB textures −68%~−92%. And shrinking with scale: AI in a world doesn't render frames, the server sends only JSON — measured ≈1 KB/s per agent, with 100 agents at 0.079 CPU cores and 92 MB RSS, observe P50 7 ms. The article also gives four evaluation questions and four "looks like savings, actually raises cost" moves.
3D world cost structurebandwidth cost optimizationfirst screen payload3D bandwidth budgetserver rendering costAI integration costself-hosted 3D costdraw call optimizationrealtime communication bandwidthperformance engineering
Engine upgrades feel like self-inflicted trouble, but the payoff is concrete: correct color (the r128 double gamma left images too bright and too pink), the WebGL2 capability surface, and no dependency on an external CDN. This is a full field record of one real upgrade: an esbuild-built UMD bundle placed behind the old filename, six loader families localized or stubbed, a three-shim supplying 87 symbols (signatures only, never behavior), a patchTHREE layer genuinely mapping legacy outputEncoding/texture.encoding onto colorSpace, and 79 legacy API calls canonized. Verification is baseline-first — 10 fixed-protocol screenshots plus a self-built PSNR/diff tool: the admin console matches at 43.4dB, and all main-world differences are attributed to color pipeline correction. webgl2Guard.js also detects support before loading, showing a full-screen Chinese message instead of a white screen.
Three.js r185 upgradeThree.js version upgradeWebGL2color pipelinecolor managementthree shimremoving CDN dependencyoffline deployment 3Drendering core migrationbrowser 3D compatibility
When character models from Mixamo, Ready Player Me, VRoid, and RootMotion land in the same 3D world, the problems cluster around the skeleton: differing bone naming, axis conventions, and animation conventions, plus duplicate bone chains left by export tools. This article breaks down a translation layer: container-rotation normalization, animation convention compensation, duplicate-chain rebinding with inverse bind matrix sync, and word-boundary name matching — every layer with a safety gate (refuse compensation when rest pose stays abnormal; roll back when IBM worsens), backed by the _diag diagnostic interface. Measured: track hits 33/33 and 312/318, per-model compensation 10/10 on 51-bone models, full suite regression 67/67. The layer treats convention differences, not content errors in the source files.
Mixamo skeletonReady Player Me integrationVRoid exportRootMotion animationskeletal animation compatibilityanimation retargetingGLB bone fixThree.js character animationself-hosted 3D world characters
Browser 3D worlds stutter at scale: submission counts, light-triggered shader recompiles, main-thread parsing, shader compilation, and blank loading screens. This article breaks down one complete cleanup in five changes — geometry batching (dense-zone draw calls 3,064→837, −73%), a 12-resident light pool (light-change freeze 8,989 ms→0), GLB parsing in Workers (23/23), a 170 ms-per-frame warm-up budget (first-entry worst 386 ms, zero frames > 500 ms), and a full-scene placeholder field (1,071/1,071 coverage) — plus three reusable judgments: visible=false is not a cost metric, uncontrollable driver behavior should become a budgetable resource, and visuals and performance don't conflict. All metrics come from 54 re-runnable acceptance scripts in the repository.
draw call optimizationThree.js performancebrowser 3D stuttershader compilation freezeGLB Worker parsing3D performance budgetgeometry batchingWebGL draw callsself-hosted 3D world