Auditing Assets in a Browser-Based 3D Virtual World: From 3.1 GB Down to 390 MB, and Why the Last 79.3 MB Waits
3D asset managementorphan asset cleanupGLB asset optimization3D virtual world deploymentglTF BIN buffersasset auditcross-world loading speedThree.js asset pipeline3D model slimmingself-hosted 3D world
Any 3D world that has been running and changing for years almost inevitably grows "garbage": models uploaded and never used, textures tried and dropped, binaries whose metadata changed without a rebuild. They never throw errors and never blank the screen — they just sit on the server, making every deployment package, every backup, and every cross-world load heavier than it should be.
This article walks through the asset audit we ran on our own browser-based 3D virtual world: how we found the orphan assets, how much we found, how much we removed — and why, for the remaining 79.3 MB, we computed the number and deliberately did not act on it yet. That last part is not a loose end; it is the point: producing the numbers and executing the cleanup are two operations with very different risk levels.
1. How orphan assets grow
The asset lifecycle of a 3D world differs from an ordinary web project. After a GLB model is uploaded, it typically goes through: upload → place it in the scene to try → adjust scale → replace → remove the scene reference. The problem is the last step: what gets removed is the reference, not the file.
Deleting a model from scene configuration is free; deleting a file from disk is risky — what if something else still references it? So the default behavior in most projects becomes "remove the reference, keep the file." Over time the disk accumulates files referenced by nothing — that is what we call orphan assets.
There is a second, sneakier kind: structural orphans. glTF-family assets separate "JSON metadata" from "BIN binary buffers," and animation data lives in the BIN. If an edit deletes an animation by changing only the JSON without rebuilding the BIN, the buffer segment no longer referenced by the JSON becomes orphaned bytes — the file still loads normally, but part of its data is never read by anyone. This kind of orphan does not live at the directory level; it lives inside the file, and directory-level scans cannot catch it.
2. The audit method: reference list versus disk list
The method itself is simple, two steps:
- Build the reference list. Walk every scene configuration, editor data store, and asset registry, and list every referenced resource.
- Build the disk list. Scan the asset directory for actual files and take the set difference against the reference list.
The difference splits into two cases: whole files with no reference (directory-level orphans), and unreferenced data segments inside referenced files (structural orphans, which require parsing the file's internal references).
The real barrier is not the code — it is whether you dare trust the difference. So before deleting anything, one more step: group the "pending deletion" list by type, size, and last-referenced time, and spot-check it by hand. A wrong orphan verdict means deleting a model still in use — and there is no cheap undo for that.
3. The numbers
Two tables cover what our audit found:
Table one: the scene asset library — cleaned.
| Item | Number |
|---|---|
| Orphan files | 159 |
| Orphan volume | 2.9 GB |
| Directory size change | 3.1 GB → 390 MB |
These were directory-level orphans: whole files with no reference, deleted after the manual spot-check described above. The directory went from 3.1 GB to 390 MB — a 92% reduction — while nothing visible in the world changed.
Table two: the character template library — quantified, not yet cleaned.
| Item | Number |
|---|---|
| Total library size | 205.5 MB |
| Orphan data inside it | 79.3 MB |
| Distribution | concentrated in 4 files |
| Worst single file | 93.4% of its bytes are orphans |
These are the structural orphans described earlier: caused by "deleting an animation by editing only the JSON, without rebuilding the BIN." The files load on every run, yet 79.3 MB of their buffers are referenced by no animation track at all.
4. Why the 79.3 MB waits
Three reasons we computed the number and did not delete yet:
One, this cleanup is not directory-level deletion. Directory-level orphans mean deleting files; structural orphans mean rebuilding them: extract the buffer segments the JSON still references, reassemble a BIN, then verify that every animation track survives. We have the plan ready, but it is surgery with write risk — one mismatched reference during the rebuild and we damage character templates that are still in use.
Two, the benefit is an estimate, not a measurement. Character templates are must-load resources in cross-world scenarios, so 79.3 MB of orphan data rides along with every cross-world load. After cleanup, we expect the cross-world first screen to drop from tens of seconds to about 1–2 seconds — note that this is an estimate; we have not measured the post-cleanup first-screen time, because the cleanup itself has not been executed. Writing that estimate as a completed fact would contradict our no-invented-numbers rule.
Three, caching amplifies operational risk. Our production model resources use 30-day immutable caching: if GLB contents change but the URL does not, returning visitors keep receiving the old file for up to a month. So asset surgery like this is best scheduled alongside a version release, not done ad hoc — which is also why it sits in the backlog rather than being executed on the spot.
One sentence for the ledger: 3.1 GB → 390 MB is finished work; the 79.3 MB is computed, planned, and not yet done. We publish both, because the whole value of an audit is a clear ledger — execution can wait its turn, but the books must not be fuzzy.
5. Does your project need an asset audit?
| If you see this | It is worth auditing |
|---|---|
| Deployment packages or backups grow month over month while world content stays flat | Likely directory-level orphans |
| Loading gets slower but item-by-item checks find no large files | Possible structural orphans (inside files) |
| Cross-world / cross-scene loads drag along a pile of "must-load" resources | Internal garbage in must-load resources gets amplified into every load |
| Multiple people uploaded assets with no deletion convention | There are orphans, guaranteed — earlier is cheaper |
Conversely, two cases can wait: a young project with a tiny asset library (audit cost exceeds benefit), or a team where every asset deletion goes through a unified cleanup flow (orphans should not exist in the first place).
6. Boundaries and unmeasured items
- The 79.3 MB cleanup has not been executed. The "cross-world first screen from tens of seconds to 1–2 seconds" figure is a projected benefit from the plan; a measured number will only exist after the cleanup is done and a real cross-world flow has been run.
- The scene-library cleanup results (159 files / 2.9 GB / 3.1 GB → 390 MB) come from our own acceptance records and are completed facts.
- The reference list in our audit covers our scene configurations, editor data, and asset registry. If your project has other reference sources — say, paths hardcoded in code — add them to the list before trusting the difference.
- Deletions were spot-checked by hand; "manual spot-check" means it is not a zero-risk operation. Do the same for your own pending-deletion list before acting on this article.
FAQ
Q: Why not prevent orphans at upload/delete time?
A: That direction works (prompt when a file loses its last reference, generate periodic pending-deletion reports), but only after you establish a single trusted source of reference truth. Our references come from more than one place — scene configurations, editor data, the registry — so we cleaned the stock first; prevention mechanisms need a clean baseline.
Q: Why is structural orphaning rarely discussed?
A: Because finding it requires parsing internal file structure; most "disk usage" tools only look at file sizes. That is also what makes it nasty: the file loads normally, everything works, and only load time and bandwidth pay the bill.
Q: Can it get leaner than 390 MB?
A: The asset directory is already fairly clean at this size. The parallel track we keep working is making the surviving assets smaller: GLB texture compression (−68%~−92%), variant texture stripping, and three-tier LOD (118 low-poly variants ≤100 faces). That is "shrink what stays" — complementary to this article's "find what nobody wants."
Q: Will the audit script ship with the repo?
A: The repository ships deployment docs and a set of acceptance scripts you can run yourself; the asset audit is an internal ops tool, and whether it ships is undecided. The method is fully described here — reference list versus disk list, difference plus manual spot-check.
Source & Repositories
The three mirrors are identical; the first two are faster inside China. The repos include deployment docs and a set of acceptance scripts you can run yourself to see the measured numbers.
- Gitee (fastest in China): https://gitee.com/miduoxinxijeji/miduo.git
- GitCode (China mirror): https://gitcode.com/qq_35054471/virtual-world
- GitHub: https://github.com/miduo100/3d-virtual-world
About Genesis
Genesis is a self-hosted 3D virtual world system built on Three.js + WebGL, helping individuals and businesses build their own 3D spaces. Accessible directly from a browser, compatible with both PC and mobile, it supports multiplayer online, federated teleportation, a shop system, and Agent integration—where an AI can enter your world as an embodied character. Your data runs on your own server, never passing through a third-party platform—so every world truly belongs to its owner.
Is your self-hosted 3D world getting heavier and slower? Genesis (a.k.a. the Genesis Virtual World CRM) is a Three.js 3D virtual world base layer that runs on your own server — the asset pipeline, performance governance, multi-client adaptation, and AI access layers are already built; asset hygiene is just part of its routine operations. Search "Genesis Virtual World CRM" to find the site with a walkable demo world.
About the name: Genesis in this article is the same self-hosted 3D virtual world product also called the Genesis Virtual World CRM. If "Genesis" does not find us, search "Genesis Virtual World CRM".