scenix
Modular Rust-native 3D scenes for native and WASM apps.
scenix 1.7.0 is the current stable release. It adds the optional
scenix-particles crate — deterministic CPU particle systems with seeded
emitters, lifetime modifiers, flipbook support, and an instanced billboard GPU
draw path plus optional compute simulation — wired through the scene graph,
materials, textures, renderer, browser capability notes, and facade feature
flags. v1.6.0's typed shader graphs, node materials, and post-node effect
language remain the shading backbone, and v1.5.0's cross-platform
controls, input stack, selection/transform primitives, reusable gizmos,
inspector snapshots, optional egui rendering, and on-demand GPU picking remain
the interaction backbone, and CPU authoring stays lightweight by default while
GPU, browser, and UI paths remain opt-in.
Install
Most applications start with the facade crate:
[]
= "1"
Enable optional systems only when needed:
[]
= { = "1", = ["loader"] }
= { = "1", = ["renderer", "post"] }
= { = "1", = ["animato"] }
= { = "1", = ["nodes"] }
= { = "1", = ["wasm"] }
= { = "1", = ["interaction"] }
= { = "1", = ["editor", "egui"] }
Focused crates can be used directly:
[]
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
= "1"
For no_std CPU authoring:
[]
= { = "1", = false, = ["libm"] }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
= { = "1", = false }
scenix-loader, scenix-renderer, scenix-post, scenix-animato, and
scenix-wasm are optional std paths. scenix-animato targets Animato
1.7.2. scenix-nodes is a no_std-capable CPU crate; its renderer, post
stack, and browser preflight integrations are std/wasm32 features of their
host crates.
Feature Flags
| Feature | Default | Description |
|---|---|---|
std |
yes | Standard-library support for CPU crates. |
scene, camera, mesh, material, light, texture |
yes | CPU authoring crates. |
raycaster, helpers |
yes | BVH picking and debug line helper data. |
interaction |
no | Convenience bundle for scene, camera, raycaster, and helpers. |
editor |
no | Inspector snapshots and editor-facing selection/transform data. |
egui |
no | Read-only egui inspector adapter; the host owns its window/render loop. |
loader |
no | Asset packages, asset manager, glTF/GLB extension metadata, OBJ/MTL, STL, image, KTX2, HDR/EXR loading, and exporters. |
renderer |
no | wgpu renderer with surface/headless targets. |
post |
no | Full-screen post-processing stack; use with renderer. |
nodes |
no | Typed shader graphs, node materials, and post node effects with WGSL/GLSL backends under the scenix-nodes crate; enables node-material rendering in renderer and browser preflight in wasm when those features are on. |
particles |
no | Deterministic CPU particle systems under the scenix-particles crate; enables the billboard GPU path (with optional compute simulation) in renderer and browser fallback plans in wasm when those features are on. |
animato |
no | Animato bridge: procedural tween/spring tracks and the clip-based Animation Runtime (clips, actions, mixer, loop modes, crossfade, additive blending, markers/events, light/morph targets, retargeting, CPU skinning). Targets Animato 1.7.2. |
wasm |
no | Browser canvas wrapper with WebGPU first, WebGL2 full fallback, WebGL1 reduced fallback, and generated demo scene. |
serde |
no | Serialization support where the focused crate supports it. |
Quick Start
Controls and interaction
use ;
let mut input = new;
input.on_pointer_down;
input.on_pointer_move;
input.on_scroll;
let mut controls = new;
let mut camera = default;
controls.update_from_input;
controls.apply_to_perspective;
input.end_frame;
InputState also accepts fixed-capacity touch contacts, two-finger gestures,
four standard gamepads, and pointer-lock relative motion without allocating in
the event/control hot path.
Scene authoring and animation
use BTreeMap;
use ;
#
Headless Rendering
use ;
# async
Loading Assets
use ;
# async
Animation Runtime
The v1.4.0 AnimationMixer plays clip-based animation on top of Animato:
use ;
let mut scene = new;
let node = scene.add;
let clip = empty.with_channel;
let mut mixer = new;
let clip_index = mixer.add_clip;
let action = mixer.add_action;
mixer.action_mut.unwrap.set_loop_mode;
mixer.action_mut.unwrap.play;
// each frame:
// mixer.tick(dt, &mut scene, &mut cameras, &mut materials,
// &mut lights, &mut skeletons, &mut morphs)
Shader nodes and node materials
v1.6.0 adds the optional scenix-nodes crate. Describe shading as a typed
graph, validate it without a GPU, and generate WGSL (renderer contract) or
GLSL ES 3.00 (WebGL tooling) from the same graph:
use ;
// Base color pulses over time, then feeds a Lambert lighting term.
let mut graph = new;
let base = graph.push;
let time = graph.push;
let pulse = graph.add;
let lit = graph.chain;
graph.add_fragment_output;
let material = new;
assert!;
assert!;
let wgsl = generate_material_wgsl.unwrap;
// wgsl.source() matches the renderer bind contract:
// group 0 frame, group 1 object, group 2 material, group 3 lights.
With the renderer feature, Renderer::register_node_material(id, &material)
shades draws through the generated module; graphs that cannot resolve carry a
specific NodeDiagnostic instead of crashing. With the wasm feature,
scenix_wasm::compile_node_material_glsl(json) runs the same preflight in the
browser before anything is uploaded.
Particles
use ;
let emitter = new
.with_rate
.with_lifetime
.with_size
.with_speed
.at
.toward
.with_shape
.with_modifier
.with_modifier
.with_modifier
.with_modifier;
// One deterministic CPU system drives the entire loop.
let mut system = new;
let batch = system.update;
assert!;
// With `renderer` + `particles`, `Renderer::register_particles` +
// `Renderer::update_particles` draw the batch as camera-facing billboards;
// `register_particle_compute` moves the whole simulation onto the GPU.
Raycasting
use BTreeMap;
use ;
let mesh_id = new;
let material_id = new;
let meshes = from;
let mut scene = new;
scene.add;
scene.update_world_transforms;
let camera = new
.position
.target;
let ray = from_camera_ndc;
let mut raycaster = new;
raycaster.build_bvh.unwrap;
assert!;
Workspace
| Crate | Role |
|---|---|
scenix |
Facade crate with stable v1 feature flags. |
scenix-math |
no_std vectors, matrices, quaternions, transforms, rays, and bounds. |
scenix-core |
IDs, colors, errors, and shared traits. |
scenix-input |
Pointer, keyboard, touch, gesture, gamepad, pointer-lock, and viewport state. |
scenix-scene |
Scene graph plus editor metadata, layers, snapping, and selection state. |
scenix-camera |
Cameras plus orbit, fly, arcball, trackball, map, first-person, and pointer-lock controls. |
scenix-mesh |
Geometry buffers, primitives, instancing, batching, and morph targets. |
scenix-material |
GPU-free material descriptions and pipeline keys. |
scenix-nodes |
Optional typed shader graphs, node materials, and post node effects with WGSL/GLSL codegen. |
scenix-particles |
Optional deterministic CPU particle systems with emitter/curve modules and GPU billboard/compute integration. |
scenix-light |
Lights, shadow settings, and light probes. |
scenix-texture |
CPU textures, samplers, atlases, video updates, and mipmaps. |
scenix-loader |
Optional CPU asset packages, asset manager, importers, exporters, diagnostics, and cache. |
scenix-renderer |
Optional wgpu renderer with on-demand ID/normal/depth editor picking. |
scenix-post |
Optional wgpu post-processing effects. |
scenix-raycaster |
BVH ray picking, marquee selection, drag planes, and transform interactions. |
scenix-helpers |
Debug lines, reusable gizmos, selection visuals, snap grids, and optional egui. |
scenix-animato |
Optional Animato bridge. |
scenix-wasm |
Optional browser canvas wrapper with WebGPU and WebGL paths. |
Examples
The facade crate registers the example set from ARCHITECTURE.md:
The browser example lives in examples/wasm_viewer:
Website
The static website is a standalone Leptos CSR app in website/. It is intentionally outside the main workspace so website dependencies do not affect normal library users.
GitHub Pages deployment is handled by .github/workflows/pages.yml, which builds website/dist with Trunk and deploys it at /scenix/. The demo uses scenix-wasm: it tries WebGPU where safe, falls back to a WebGL2 renderer with the same generated scene/material/light controls when WebGPU is unavailable, uses reduced WebGL1 only as a last GPU path, and only uses the Canvas2D preview when both GPU paths are unavailable.
Development Checks
SCENIX_RUN_GPU_TESTS=1 WGPU_BACKEND=vulkan
RUSTDOCFLAGS="-D warnings"
Documentation
- Developer docs
- Architecture
- Roadmap
- Changelog
- Getting started
- Installation
- Quick start
- Concepts
- Guides
- API reference
- Examples
- Recipes
- Performance
- Deployment
- Migration
- Reference
- v1.5.0 release notes
- v1.4.0 release notes
- v1.3.0 release notes
Known Limitations
- The renderer now uploads material textures, light data, environment descriptors, and render targets through real GPU resources. Advanced physical shading is a pragmatic realtime path, not an offline film renderer.
- Loader APIs produce CPU-side scenix data;
RendererAssetExtis a convenience bridge that still uploads into renderer-owned GPU resources explicitly. - Draco and meshopt compressed glTF assets currently produce explicit diagnostics unless preprocessed by an external converter.
- WebGL2 is the full browser fallback for the generated renderer scene when WebGPU is unavailable. WebGL1 remains a reduced last-resort fallback for older browsers.
- The website demo does not vendor large model assets.
- GPU tests require a Vulkan-capable device or Mesa lavapipe.
License
Licensed under either of:
- Apache License, Version 2.0
- MIT license