Project Structure
How the Renzora engine repository is organized — one Cargo workspace, ~187 crates auto-included by globs, and the "one binary, editor-as-removable-cdylib" layout.
Renzora is a single large Cargo workspace built on Bevy 0.20, where almost every feature is its own crate that registers a Bevy Plugin. The defining structural fact is one engine binary (renzora) that is always runtime-shaped; the editor ships as a removable cdylib bundle beside it. This page maps the repository so you can find your way around the source.
Repository layout
engine/
├── Cargo.toml # Workspace root + the renzora_app package ([[bin]] renzora)
├── Cargo.lock
├── build.rs # Windows icon/version resource, build hash, zstd link
├── src/
│ └── main.rs # The single binary entry point (editor / runtime / server)
├── crates/ # ~164 top-level crates (flat — no category subfolders)
│ ├── renzora/ # The SDK / contracts crate → ships as renzora.dll
│ ├── renzora_runtime/ # Shared engine library every binary links
│ ├── renzora_engine/ # Editor-free game core (VFS, scene IO, autoload)
│ ├── renzora_editor/ # The editor BUNDLE cdylib (links ~50 editor crates)
│ ├── renzora_editor_framework/ # Editor SDK implementation (rlib-only)
│ ├── renzora_native_plugin/ # scans, rebuilds and loads plugins/
│ ├── renzora_plugin_build/ # the rustc driver a plugin is compiled with
│ ├── renzora_<feature>/ # one crate per feature (physics, scripting, ember, …)
│ │ └── editor/ # optional editor-only half (= renzora_<feature>_editor)
│ ├── renzora_<effect>/ # one crate per post-process effect (bloom, crt, …)
│ ├── bevy_hanabi/ bevy_hui/ bevy_firefly/ bevy_silk/ vleue_navigator/
│ ├── bevy_gaussian_splatting/ bevy_args/ bevy_interleave*/ polyanya/ bvh2d/
│ └── bevy_oxr/ # vendored — its OWN nested workspace (not globbed in)
├── docker/ # Dockerfile + build/add/remove/upx shell scripts
├── .cargo/
│ └── config.toml # cargo aliases (cargo renzora, cargo runtime, …)
├── templates/ # android / ios / web PACKAGING templates (not scaffolds)
├── disabled/ # crates parked OUTSIDE the workspace (won't build)
├── assets/ # engine default assets + test scripts
├── dist/ # build output (arch-suffixed dirs)
└── docs/ # in-repo engine docs (markdown)
There is no
Makefile.toml/cargo-make and no_legacy_src/, but there is anxtask/crate (behind thecargo renzoraalias) for native builds and arust-toolchain.tomlthat pins the Rust version for them. The container's Rust version (1.97.1) lives indocker/base/Dockerfile, kept in lockstep withrust-toolchain.toml; common tasks run through therenzoraCLI or the cargo aliases in.cargo/config.toml(see Building from Source).
The workspace member globs
The root Cargo.toml auto-includes members with globs, so adding a new plugin only requires creating its directory — there is no manual members list to edit:
[workspace]
resolver = "2"
members = [
".", # renzora_app — the binary
"crates/renzora", # the SDK / contracts crate
"crates/renzora_*", # every renzora_* feature/effect crate
"crates/renzora_*/editor", # nested editor halves of dual-mode crates
# Vendored Bevy ecosystem crates, listed explicitly (NOT via a bevy_* glob)
# so bevy_oxr — its own nested workspace — is not accidentally pulled in.
"crates/bevy_args",
"crates/bevy_firefly",
"crates/bevy_gaussian_splatting",
"crates/bevy_interleave",
"crates/bevy_interleave_interface",
"crates/bevy_interleave_macros",
"crates/bevy_hanabi",
"crates/bevy_hui",
"crates/bevy_silk",
"crates/vleue_navigator",
# vleue_navigator's pathfinding deps, vendored to bump their glam to 0.33
# (Bevy 0.20's).
"crates/polyanya",
"crates/bvh2d",
]
A few consequences worth knowing:
- The glob keys on the
renzora_prefix.crates/mcp_server_pluginandcrates/websocket_pluginexist on disk but lack that prefix, so they fall outside every glob and are not workspace members (they also depend on a../editor_plugin_apicrate that no longer exists). They are orphaned, not part of the build. crates/bevy_oxris deliberately not globbed — it is its own nested vendored workspace (containingbevy_openxr,bevy_webxr,bevy_xr,bevy_xr_utils).- Crates under
disabled/(currentlydisabled/renzora_vr_editor) sit outsidecrates/, so they never enter the workspace.
Counting it up: ~164 top-level directories under crates/ plus 23 nested editor/ subcrates → ~187 workspace crates in total.
The core crate layers
A handful of crates form the engine's spine. Everything else is a plugin that plugs into them.
| Crate | Crate type | Role |
|---|---|---|
renzora | rlib (shared through renzora_dylib) | The contract crate. Houses the add! / plugin! macros, PluginScope, the post-process framework, GI contract types, the audio/net/script boundary types, and (under the editor feature) the editor contract registries. |
renzora_runtime | rlib | Shared engine library every binary links (init_app, add_default_rendering, add_headless_rendering, add_engine_plugins). |
renzora_engine | rlib | The editor-free game core — VFS, custom asset reader, scene IO, autoload, crash reporting. |
renzora_editor | dylib + rlib | The editor image — statically links ~50 editor-only crates and the dual-mode /editor subcrates, and exports a single renzora_editor_install entry point. Present beside the binary → the binary is the editor; absent → the same binary is the game. |
renzora_editor_framework | rlib | The editor SDK implementation (the boundary-crossing contract types were folded into the contract crate, so this emits no dll). |
renzora_native_plugin | rlib | Scans plugins/, rebuilds what is stale, loads the rest. |
renzora_plugin_build | rlib | The compiler driver — reads the SDK manifest and invokes rustc directly. |
renzora_dylibandrenzora_ember_dylibhold no code of their own. They exist so the host binary, the dlopen'd editor image and every installed plugin share one compiled copy ofrenzoraandrenzora_ember— one translation table, one Console buffer, one theme palette — and matchingTypeIds across the dynamic-linking boundary.bevyis shared the same way viabevy_dylib(dynamic_linking+prefer-dynamic).
One binary, not three
There is exactly one [[bin]] in the whole workspace: renzora_app → src/main.rs, named renzora. It is the engine — editor, runtime, and dedicated server in one — chosen at runtime:
- The default windowed launch is the editor if
renzora_editor.{dll,so,dylib}is present beside the exe, otherwise the shipped game. --no-editor(orRENZORA_NO_EDITOR) forces the game even when the bundle is present.--serverruns a headless dedicated server;--hostruns a windowed listen server.
There is no editor compile-time feature and no separate editor or server binary. Delete the bundle file and the same binary becomes the shipped game. See Core Concepts for the full model.
Dual-mode crates and /editor subcrates
Because a plugin's scope is exact (Editor or Runtime, never both — see below), a feature that needs to run in both places is physically split into two crates:
crates/renzora_physics/ # lean runtime crate (package: renzora_physics)
crates/renzora_physics/editor/ # editor-only half (package: renzora_physics_editor)
The runtime crate is statically linked / registered everywhere; the nested editor/ subcrate (renzora_<name>_editor) is linked only by the editor bundle. There are 23 such editor/ subcrates today:
antialiasing, atmosphere, auto_exposure, bloom_effect, clouds, distance_fog, dof, ember, engine, environment_map, lighting, motion_blur, navmesh, night_stars, oit, physics, scripting, skybox, ssao, ssr, tonemapping, volumetric_fog, water.
Some editor-only features (e.g. renzora_hierarchy, renzora_inspector, renzora_blueprint_editor) are standalone top-level crates rather than /editor subcrates — they have no runtime half at all.
Two kinds of plugin
| Kind | Lives in | Crate type | Compiled | Ships in |
|---|---|---|---|---|
| Workspace | crates/renzora_<name>/ | rlib + renzora::add! | with the engine, statically | the engine binary |
| Native | plugins/<name>/ | dylib + renzora::plugin! | on the installing machine, against the staged SDK | the editor, as source |
Both are ordinary Bevy plugins with the real &mut World and the real
Transform. There is no FFI in either.
A workspace plugin's add! line is read as text at build time by a generator
that writes the committed crates/renzora_{runtime,editor}/src/plugins.rs lists
— there is no runtime registry, just a linker symbol in a generated
add_plugins call.
A native plugin ships as source and is compiled where it is installed, which is what removes the environment-matching problem entirely: the plugin is always built against the engine sitting right beside it, and when that engine moves, its content-hash stamp stops matching and it quietly rebuilds.
The older dlopen feature and its plugin_create / plugin_scope /
plugin_bevy_hash exports are gone, along with the dynamic_plugin_loader
crate that checked them, and so is the C ABI that briefly replaced them. See
Building Plugins and
Native Plugins.
Where the code actually lives
Two directories hold nearly all of it, and the split is the plugin table above:
| Directory | Contents |
|---|---|
crates/ | 114 renzora_* crates plus the vendored Bevy forks (bevy_hanabi, bevy_hui, bevy_firefly, bevy_silk, bevy_oxr, bevy_gaussian_splatting with its bevy_args and bevy_interleave* dependencies, and vleue_navigator with polyanya and bvh2d). Most were ported to Bevy 0.20 here, ahead of upstream releases. Broadly: the contract crate and plugin machinery, the engine runtime, the editor framework and its panels, the render passes and lighting, gameplay simulation, and asset/scene/import. |
plugins/ | Installed plugins, most of them post-process effects. Empty in a fresh checkout: plugins are distributed through the marketplace and built where they land. |
Those counts move every release; treat them as a sense of scale, not an
inventory. The direction of travel is out of crates/ and into plugins/: an
optional feature belongs in a plugin the marketplace can install, so the static
binary carries only what a game genuinely cannot boot without.
A few naming notes that trip people up reading the tree:
- The UI/markup system is
renzora_ember. The formerrenzora_huicrate was merged into ember and deleted; the still-vendoredbevy_huiis used only as the.htmlparser. renzora_postprocessis the shader-file effects behind the Post Process component. The render phases those effects run in arerenzora::postprocess, inrenzora.dll.renzora_gaugesand thevello-based vector renderer were removed; gauges are now anrenzora_emberWGSL widget.renzora_dreamis a live post-process effect, not editor tooling.
Adding a new crate
Thanks to the globs, adding a feature is mostly creating a directory:
# 1. Create the crate. The crates/renzora_* glob picks it up automatically —
# no edit to the workspace members list is needed.
cargo new --lib crates/renzora_myfeature
# 2. (Optional) for an editor-only half, add a nested subcrate.
# This becomes the package `renzora_myfeature_editor`, matched by
# the crates/renzora_*/editor glob and linked only by the editor bundle.
cargo new --lib crates/renzora_myfeature/editor
Then in the crate's lib.rs, register a Bevy Plugin with the engine:
use bevy::prelude::*;
#[derive(Default)]
pub struct MyFeaturePlugin;
impl Plugin for MyFeaturePlugin {
fn build(&self, app: &mut App) {
// add_systems, register_type, insert_resource, …
}
}
// Runtime scope by default; use add!(_, Editor) for an editor-only plugin.
renzora::add!(MyFeaturePlugin);
Wiring it in:
- A runtime crate is added as a dependency of
renzora_runtime; an editor-only crate is added torenzora_editor. Therenzora add <name> [--editor]helper does that wiring for you, and the build generator writes theadd_pluginscall from youradd!line. - An installed plugin needs no wiring here at all: it lives outside this repository, ships as source, and the loader compiles it against the staged SDK. See Native Plugins.
Use
use renzora::*;(oruse renzora::Inspectable;). There is norenzora::preludemodule.Inspectable,AppEditorExt, and the#[field(...)]/#[inspectable(...)]attributes are behindrenzora'seditorfeature, so an inspector-aware crate must depend onrenzora = { ..., features = ["editor"] }.
What's next?
- Building from Source —
cargo renzora, the cargo aliases, and the output layout - Core Concepts — ECS, plugins, and the one-binary model
- Building Plugins — write an in-workspace plugin