Experimental Rust Projects: Learning Performance by Building Worlds

By Raymund Zyron Abella /

From an isometric island builder to streamed voxel terrain and a 10,000-particle WASM stress test, these experiments made systems performance visible and interactive.

In this article

My experimental Rust projects started with a simple question: what kinds of browser experiences become possible when the simulation is allowed to do more work?

Instead of answering through isolated benchmarks, I built interactive systems: an isometric island builder, procedural voxel worlds, physics experiments, rendering studies, and SpeedDemon, a 10,000-particle stress test compiled to WebAssembly. Each project put performance pressure somewhere different.

Beginning With a World You Can Touch

Private Island Builder is a small isometric voxel sandbox. The player moves through a fixed-angle world, chooses grass, sand, or stone, places blocks, and removes them again. Its scope is modest, but it established the pattern that shaped the later experiments: performance work is more meaningful when a person can interact with the result.

The project also made Rust feel concrete. Ownership and data layout were no longer language exercises; they affected how world state, input, rendering, and block edits moved through the frame.

Compiling the same project for desktop and WebAssembly introduced another useful constraint. Browser delivery changes startup, asset loading, input, and deployment, but the simulation core can remain disciplined and portable.

Procedural Terrain Changed the Scale

The Procedural Voxel Explorer moved from editing a small island to generating a world while the camera travels through it. Multi-octave noise creates terrain and caves, nearby chunks are generated, distant chunks are removed, and voxel edits require affected geometry and collision data to be updated.

Rust, Bevy, and Rapier each had a clear role. Bevy organized systems and entities, Rapier handled physical interactions, and Rust made the hot paths explicit: noise sampling, chunk meshing, allocation, edit tracking, and collider replacement.

The first prototype was not finished, and that was useful. It exposed where a visually convincing demo can still have an unstable architecture. The next iteration treated chunk boundaries, dirty regions, and persistent edits as first-class problems instead of details to solve later.

WebAssembly Was a Delivery Target, Not a Gimmick

These projects were meant to run in a browser because friction changes whether an experiment gets experienced. A native executable can be faster, but a link is easier to open, share, and test.

WebAssembly made it possible to keep the simulation core in Rust while using the browser as the distribution surface. It also made the boundary visible. Pointer lock, canvas sizing, asset paths, cross-origin isolation, and static hosting are part of the product even when the interesting code lives inside a compiled module.

That boundary taught me to think about performance as a full pipeline. A fast update loop does not help if the build is difficult to deploy, the initial payload is excessive, or the controls do not make sense in a browser.

SpeedDemon Turned the Experiment Into a Measurement

SpeedDemon stripped the scene down to 10,000 moving balls. The simulation uses Verlet integration, boundary constraints, mouse repulsion, and a spatial grid that limits collision checks to nearby cells. A live FPS graph makes the cost visible as particles are added or removed.

The important optimization is not a clever microbenchmark. It is the change in problem shape. Comparing every particle with every other particle grows too quickly. Rebuilding a spatial grid each frame costs work, but it transforms collision detection into local neighborhood queries.

That tradeoff is easier to understand when it is animated. Toggle the grid, increase the particle count, interact with the field, and the data structure becomes visible behavior.

What Rust Forced Me to Notice

Rust makes certain costs difficult to ignore. Data ownership, allocation, mutation, and synchronization have to be designed rather than left ambiguous. That can slow down the first version, but it produces useful questions early:

  • Which system owns an edit?
  • What data must persist when a chunk unloads?
  • Which values are recreated every frame?
  • Can a broad search become a local query?
  • Does this abstraction disappear in release builds?

Those questions improved the JavaScript and Three.js experiments around the Rust work too. The language was not only a faster implementation option; it trained a more explicit way of thinking about real-time systems.

Experiments Are Allowed to Be Incomplete

Not every project in this series became a finished product. Some were prototypes, some were stress tests, and some existed to answer one technical question. That is the point of an experimental archive.

The standard is not commercial completeness. The standard is whether the experiment creates evidence. The island builder proved a Rust game loop could become an approachable browser toy. The voxel projects exposed the architecture of streamed worlds. SpeedDemon demonstrated why spatial partitioning matters under load.

Together, they form a progression from building an object, to streaming a world, to measuring the machinery underneath it.

Where I Would Take the Work Next

The next useful step is less about adding particles and more about deeper instrumentation: frame-time breakdowns, allocation tracking, chunk-generation budgets, deterministic replays, and comparisons between native and WASM builds under the same workload.

I would also keep pushing the interaction design. Technical experiments become more memorable when users can disturb, build, destroy, and navigate the system instead of only watching a number.

Rust gave these projects speed, but the larger lesson was about structure. Performance becomes understandable when an experiment turns invisible computation into something you can move through.

More articles

Browse all engineering articles