Contributing Guide
Renzora is open source and welcomes contributions — this guide covers the workflow, code style, and CI checks your pull request has to pass.
Code of conduct
Be respectful, constructive, and collaborative. Harassment, trolling, and unconstructive negativity are not tolerated. We're building something together — treat others the way you'd want to be treated.
Getting started
- Fork the engine repo on GitHub.
- Clone your fork and check out a branch from
main. - Make your changes, following the guidelines below.
- Run the checks locally —
cargo clippy --profile distand the tests for the crates you touched. - Push to your fork and open a pull request against
main.
git clone https://github.com/YOUR_USERNAME/engine.git
cd engine
git checkout -b fix-spotlight-shadow
cargo renzora # build, stage dist/, and launch the editor
# make changes...
cargo fmt
cargo clippy --profile dist # the CI lint gate, natively
cargo test --profile dist -p renzora_physics
git commit -m "fix(lighting): update spotlight shadow when range changes"
git push origin fix-spotlight-shadow
If you're looking for a first contribution, check for issues labeled good first issue or help wanted.
Using AI
You're welcome to use an AI assistant — we don't review AI-assisted PRs any
differently. In exchange, you audit every line you submit, you prove it works
with tests, and you name the model and version in an Assisted-by: commit
trailer. The full terms are on the AI Policy page; read it before
opening your first AI-assisted PR.
Development setup
The full build story — the one-binary / editor-as-removable-cdylib model and the cross-compile images — is documented in Building from a Checkout. The short version:
cargo renzora # build the workspace and run the EDITOR
cargo renzora dist # build and stage without launching
cargo check --profile dist # fast gate while editing
cargo clippy --profile dist # reproduces the CI lint job
cargo test --profile dist -p <crate> # per-crate tests, natively
renzora test # the full suite, exactly as CI runs it (container)
Always pass
--profile dist. A bare cargo command defaults to thedevprofile and creates a second full set of artefacts undertarget/debug/; this workspace is far too large for two of them, and a full disk surfaces as bogus compile errors in crates you never touched rather than as a disk error.
You do not need Docker to develop on Renzora. Docker is a cross-compiler — it builds export templates for platforms you don't own — and a way to reproduce CI exactly. It is not the install path. Nothing is
dlopen'd against Bevy any more: in-workspace plugins are statically linkedrlibs wired in by a build-time generator, and standalone plugins are C-ABI cdylibs that link no Bevy at all, so neither needs a canonical build environment. The editor is the removablerenzora_editorcdylib bundle that the binary dlopens from beside itself; there is noeditorcompile-time feature — the only build features on therenzorabinary areruntime(default) andwasm.
Toolchain
- You need Git and rustup.
rust-toolchain.tomlpins the Rust version and rustup selects it automatically; the project does not require nightly. You will also need your platform's usual native build dependencies — a C/C++ toolchain, and on Linux the X11/Wayland/ALSA/udev dev headers (the list mirrorsdocker/base/Dockerfile). - The Rust version is pinned in two lockstep files:
rust-toolchain.toml(native) anddocker/base/Dockerfile(FROM rust:1.95.0-bookworm, container). A bump must edit both. - Docker is needed for two things only: cross-compiling export templates (
renzora build <platform>) and reproducing CI exactly (renzora check/renzora test). - Linux uses
moldand Windows usesrust-lld(MSVClink.exehits the 65535-object limit)..cargo/config.tomlsets that up for native builds as well as the container, so a native link succeeds. cargo test --profile dist -p <crate>links and runs natively, including on Windows, and it is the fastest way to iterate.cargo test --workspaceis the one that doesn't: it builds example targets, and two vendored XR crates have examples that never got a Bevy 0.19 rename. CI never hits this because it excludes those crates — test per-crate, or userenzora test.
Heads-up: hardware ray-traced GI ships via the optional
renzora_solariplugin (Bevy Solari), enabled by thebevy_solariBevy feature in the workspaceCargo.tomland activated at runtime only on RT-capable GPUs — see Solari ray-traced GI. There is still no--features solaribuild flag; Solari is a drop-in plugin, not a build variant. Lumen's separateLumenQuality::Hwrttier remains an unimplemented placeholder and renders nothing.
What to contribute
| Area | How |
|---|---|
| Bug fixes | Browse the issue tracker. |
| Documentation | Edit the markdown under docs/r1-alpha7/ in the engine repo; pushing to main auto-publishes it to this site. Older docs/r1-alpha* directories are frozen releases — leave them alone. |
| Editor panels | Register a native bevy_ui panel with the App extension APIs register_shell_panel(id, title, icon, category) + register_panel_content(id, scroll, build_fn). See Editor Panels. |
| Scripting functions | Declare them from the owning domain crate via the ScriptExtension trait, so every language backend builds them. Engine-wide primitives live in the language plugin's register_api() (plugins/lua). |
| Post-process effects | Annotate a settings struct with #[renzora_macros::post_process(...)] and renzora::add! the plugin. See Post-Processing. |
| Plugins | Declare with renzora::add!(MyPlugin) — a build-time generator reads that line as text and writes the committed static plugin lists, so keep it on one line at the top level. See Building Plugins. |
| Export targets | Improve a platform lane in docker/build-all.sh. |
The editor has no
EditorPaneltrait you "implement and register" — panels are plain bevy_ui content functions registered through the twoAppextension methods above. Anything claiming an eguiEditorPaneltrait is stale (egui was fully removed).
Code style
Formatting
Use default rustfmt. Run cargo fmt before committing, and don't hand-format in ways that conflict with it.
Naming
- Types:
PascalCase—BlueprintGraph,ScriptComponent,LumenLighting,DockTree. - Functions / variables:
snake_case—spawn_entity,handle_input. - Constants:
SCREAMING_SNAKE_CASE. - Modules:
snake_case, matching the file name.
General conventions
- Follow existing patterns in the module you're touching.
- Use Bevy's ECS idioms — systems, components, resources, events.
- Prefer
///doc comments on public items and//!at the top of a module. - Avoid
unwrap()in production code paths; use proper error handling orexpect()with a message. - Keep changes minimal — don't refactor unrelated code or reformat files you didn't change.
Testing
Tests live in #[cfg(test)] mod tests blocks alongside the code. Iterate per-crate natively, then reproduce CI in the container before you submit:
cargo test --profile dist -p renzora_physics # natively, fast
renzora test # the full suite, exactly as CI runs it
renzora test --package renzora_net # one crate, in the container
Focus on logic, serialization round-trips, and edge cases:
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn blueprint_graph_roundtrips() {
let original = sample_graph();
let serialized = ron::to_string(&original).unwrap();
let restored: BlueprintGraph = ron::from_str(&serialized).unwrap();
assert_eq!(original, restored);
}
}
What's worth a test: new data structures (serialize/deserialize round-trips), new algorithms (correctness + edge cases), and new components (registration and defaults). Cross-crate tests go in crates/<crate>/tests/*.rs — renzora_plugin/tests/abi_order.rs pins the C-ABI interface layout, renzora_bsn/tests/raw_roundtrip.rs round-trips the scene format, renzora_ember/tests/parse_templates.rs proves every shipped UI template parses without a GPU, and renzora_net/tests/round_trip.rs covers the wire codec.
Continuous integration
CI runs on every push and pull request to main (.github/workflows/test.yml). Both jobs run inside the shared base image ghcr.io/renzora/base:latest, so the runner needs nothing installed — rustc 1.95 and the Linux dev libs are baked into the base (the per-platform cross toolchains aren't needed to test first-party crates).
CI invokes
cargo testandcargo clippyinside the image. Therenzora test/renzora checkCLI commands wrap those same cargo invocations in the container, so they reproduce CI locally — run those, not a nativecargo.
Each job runs this inside the image (reproduce with renzora test / renzora check):
# Test job — first-party crates only; the vendored Bevy-ecosystem crates are excluded
cargo test --workspace \
--exclude bevy_gauge --exclude bevy_hanabi --exclude bevy_mod_outline \
--exclude bevy_silk --exclude vleue_navigator \
--exclude bevy_mod_openxr --exclude bevy_mod_xr --exclude bevy_xr_utils
# Clippy job — warnings are denied
cargo clippy --workspace --no-deps \
--exclude bevy_gauge --exclude bevy_hanabi --exclude bevy_mod_outline \
--exclude bevy_silk --exclude vleue_navigator \
--exclude bevy_mod_openxr --exclude bevy_mod_xr --exclude bevy_xr_utils \
-- -D warnings \
-A clippy::too_many_arguments \
-A clippy::type_complexity
The vendored crates (bevy_*, vleue_navigator) are third-party code copied into the tree — they still build as dependencies, but their own test suites are skipped to avoid re-testing upstream. too_many_arguments and type_complexity are allowed because they're inherent to Bevy systems and queries. New first-party crates are covered automatically via --workspace.
Pull requests
- Open an issue first for non-trivial changes so the approach can be discussed.
- One concern per PR — don't mix a bug fix with a feature or a refactor.
- Branch from
mainwith a descriptive name (fix-spotlight-shadow,add-cylinder-collider). - Write tests for new functionality when the module already has coverage.
- Update documentation — the markdown under
docs/r1-alpha7/in the engine repo — when you change public APIs or add features. New pages also need an entry indocs/r1-alpha7/_sidebar.json. - During review, push additional commits — don't force-push mid-review.
PR checklist
- [ ]
cargo fmtapplied, no unrelated formatting changes - [ ]
cargo clippy --profile dist(orrenzora check) is clean — warnings are denied in CI - [ ] Tests pass for the crates you touched (
cargo test --profile dist -p <crate>, orrenzora test) - [ ] Docs updated under
docs/r1-alpha7/if behavior or APIs changed - [ ] New tests added where applicable
- [ ] Branch is up to date with
main - [ ] AI-assisted work is audited and disclosed with an
Assisted-by:trailer (AI Policy)
Commit messages
This repo uses Conventional Commits:
type(scope): subject— types arefeat,fix,docs,refactor,chore,ci,security; the scope is optional.- Imperative mood, under ~72 characters, no trailing period.
- Say what changed and why.
feat(scripting): camera field of view
fix(import): harden the folder-import walk and unify the queue path
refactor(audio): delete kira; renzora_audio becomes the API and nothing else
docs(r1-alpha7): audio is a plugin, not a library the engine links
Reporting issues
Search existing issues first to avoid duplicates. For a bug report, include:
- Steps to reproduce, expected vs actual behavior.
- Environment — OS, GPU, and
rustc --version. - Run mode — editor (
renzora-editor), shipped game (renzora), or the runtime launched with--server(headless),--host(listen server), or--vr. There is no--no-editorflag any more: the runtime binary can never become the editor. Note also that the only build features areruntime(default) andwasm; there is noeditorfeature to report. - Crash logs — the editor writes
~/.renzora/crashes/last_crash.txt(plus a native dialog); the shipped game silently appendscrash.logbeside the executable. Attach the relevant one.
License
The engine is dual-licensed under MIT OR Apache-2.0 (LICENSE-MIT and LICENSE-APACHE at the repo root). By contributing, you agree your contributions are licensed under the same terms, without additional conditions.
What's next?
- AI Policy — using AI assistants, auditing, testing, and disclosure
- Building from Source — the full build, aliases, and Docker cross-compile flow
- Architecture — the one-binary, editor-as-removable-cdylib model
- Building Plugins — extend the engine with
renzora::add!