Inside the Engine
One frame, many times a second.
FloraForge is a from-scratch terrain engine written in Rust with the graphics API. There is no game-engine framework underneath — just a single : read input, simulate the world, draw it, repeat. This page is a tour of that loop and the systems hanging off it.
The Frame Loop
Everything happens inside one cycle
The window library (winit) runs in Poll mode: as soon as the
engine finishes a frame it immediately asks for the next one. Each lap of the loop
collects input, runs a single to advance the simulation, then a
single render() to draw it to the screen — and presents the result.
Defined in src/app/event_loop.rs and src/app/mod.rs.
The same loop drives the native desktop build and the in-browser WebAssembly build.
Inside one lap
What update() and render() actually do
A frame is two halves. Update is pure CPU work that moves the world
forward by the elapsed time dt. Render records a list of
drawing commands and hands them to the GPU. They are deliberately separated so the
simulation stays the same whether the machine draws at 30 or 300 fps.
Simulate update()
Runs on the CPU. Branches on the current screen; this is the "Playing" path.
- Measure time
Compute
dtsince the last frame and smooth the FPS readout with a rolling average. - Move the camera The camera controller turns held keys and mouse deltas into a new fly-camera position, then clamps it above the terrain.
- Advance the world clock Time of day ticks forward, which drives the sun direction and ambient light.
- Load chunks entering the camera's radius, drop ones that left, and collect terrain finished by background worker threads.
- Grow plants Plant lifecycle advances; chunks whose vegetation changed are reassembled.
- Sync to GPU New chunk meshes and plant instances are uploaded; per-frame uniforms (view-projection, camera, time), lighting, HUD and minimap are written.
Draw render()
Records GPU commands into one encoder, then submits and presents.
- Grab the next swapchain texture. This call blocks until the GPU is ready — that wait is how the engine measures whether it is GPU-bound.
- Open a render pass Clear the colour and depth buffers (or blit a pre-blurred background for the menu).
- Draw the scene, in order Each pass below appends draw calls. Terrain, plants and water are so off-screen chunks cost nothing.
- Overlay the UI
An
eguipass paints menus, the config panel and the plant editor on top of the 3D scene. - Submit & present The encoded commands go to the GPU queue and the finished frame is swapped to the screen.
src/app/benchmark.rs.
Screen state
The same loop, five modes
The loop doesn't only run the world. A small state machine decides what
update() and render() do each frame, so the menu, the plant
editor and the live world all share one code path.
StartMenu
Animated sky background with a blurred snapshot of the last frame behind the menu UI.
Loading
Builds the world one step per frame so the progress bar keeps animating.
Playing
The full simulate-and-draw path described above, with cursor capture for mouse-look.
Herbarium
A grid of your plant species, each rendered to a live thumbnail.
PlantEditor
An orbit camera around a single procedurally generated plant you can tune in real time.
Rather than freezing the window while the world generates, each phase runs on its
own frame and bumps the progress bar. Background threads generate chunk terrain in
parallel; the WaitForChunks phase polls until they're all in.
Architecture
Three layers, cleanly separated
The code that the loop calls into is split into three layers. The split keeps world generation testable and free of any graphics code, and keeps all GPU concerns in one place.
Chunk, terrain and biome generation, heightmaps, plant lifecycle and the world clock. No rendering, no GPU — just the rules of the world, which makes it easy to test in isolation.
Streams chunks in and out around the moving camera, dispatches generation to
worker threads, advances the clock, and tracks lifecycle changes. This is the
layer update() drives each frame.
All wgpu code: the device/surface context, per-frame and
per-material , the that builds terrain meshes, instanced
rendering, water, sky, HUD and the egui overlay.
See it running
The whole loop compiles to and runs in your browser over — the same Rust code as the desktop build.
Launch FloraForge Read the Source