Procedural generation in VRChat is incredibly difficult because you are fighting both Unity's runtime limitations and the constraints of the Udon virtual machine. True procedural generation relies on creating and modifying data on the fly, which conflicts directly with how VRChat optimizes worlds. This world seeks to reapproach procdeural effects in VRChat by utilizing a predefined grid of cells that procedurally reallocate themselves to great a similar effect to the end user. While I don't know how far this project will go I would like to document it here for others!
Obviously a project like this has several obvious, and several not so obvious challenges so as we run into them I will fill out this portion of the page. There are various ways to approach any of these issues and we will discuss the chosen options later on down the page.
Udon is a virtual machine running on top of Unity. It can take 200x to 1000x longer to execute code compared to native C#. Generating a world procedurally often requires heavy algorithms like noise generation or wave function collapse. Iterating through thousands of elements to calculate layouts in Udon will instantly drop the frame rate. You have to aggressively time-slice these calculations across many frames, which leads to massive load times for the player.
In a standard Unity game, you can spawn assets dynamically. In VRChat, VRCInstantiate is incredibly slow and causes severe frame spikes. You cannot generate a world by instantiating new objects on the fly. Instead, you have to use Object Pooling—pre-loading every possible wall, floor, and prop into the scene at build time and teleporting them into position when needed. This creates a hard ceiling on memory limits and heavily restricts the scale of the world.
Well-optimized VRChat worlds rely heavily on baked lightmaps to maintain VR framerates. You cannot bake lighting at runtime. If you generate a map procedurally, you are forced to rely on real-time lighting and shadows (which are expensive and often unfeasible for complex VR environments), complex shaders, or use flat-shaded materials.
Unity optimizes performance by static batching geometry at build time, merging meshes to drastically reduce draw calls. When you build a world dynamically out of modular, moving prefab pieces at runtime, you lose static batching. Every single wall and floor tile becomes a separate draw call. Unless you rely entirely on GPU instancing, the draw call count will skyrocket and cripple client performance.
In a multiplayer environment, everyone needs to see the exact same layout. Syncing a procedural world is complicated, especially for late-joiners. The late-joining client either needs to receive the base seed and locally calculate the identical world state (which can cause desyncs if the Udon logic isn't perfectly deterministic), or the instance master has to sync the position and state of every single pooled object. Doing the latter will quickly max out VRChat's network serialization limits.
If your procedural world requires NPCs or AI, they need a NavMesh to pathfind. Traditionally, Unity's NavMesh is baked entirely at edit-time. While VRChat now supports runtime NavMesh building via the AI Navigation package, executing a complete rebuild on a newly generated layout is computationally expensive and causes hitching.