Camera
PerspectiveCamera::portrait()
Real glTF, real PBR, named presets instead of magic numbers.
use scena::{Assets, EnvironmentPreset, Scene};
let assets = Assets::new();
let model = assets.load_scene("machine.glb").await?;
let env = assets
.load_environment_preset(EnvironmentPreset::Studio)
.await?;
let mut scene = Scene::new();
scene.instantiate(&model)?;
scene.add_studio_lighting()?;
renderer.set_environment(env);
renderer.render(&scene)?;
Named PBR presets that produce credible materials under your chosen environment.
Rendered live in your browser. Matte through glass use MaterialDesc::*; satin, leather, and rubber use source-backed Assets::material_presets(). Full physical glass remains capability-gated until its release proof is complete.
glTF or GLB. Materials, textures, and animation clips flow through the asset pipeline.
let asset = assets.load_scene("watch.glb").await?;
let mut scene = Scene::new();
let import = scene.instantiate(&asset)?;
let bounds = import.bounds_world(&scene).ok_or("no bounds")?;
scene.add_studio_lighting()?;
scene.add_grid_floor(&assets, GridFloorOptions::new().under_bounds(bounds))?;
<scena-viewer src="watch.glb"
environment="studio"
camera-controls
auto-rotate>
</scena-viewer>
Use Rust when you own the app. Use the custom element when you want a drop-in browser viewer.
Authored connectors in your glTF. scena does the math.
let drive = scene.instantiate(&drive_part)?;
let load = scene.instantiate(&load_part)?;
scene.mate(&drive, "shaft", &load, "hub")?;
No coordinates. No transform math. Two named connectors and one call.
Most renderers make you write radians, lumens, EV. scena ships names. The numbers are still there when you need them.
Camera
PerspectiveCamera::portrait()
Lighting
DirectionalLight::key_light()
Environment
EnvironmentPreset::Studio
Background
Background::DarkStudio
Exposure
AutoExposureConfig::product_studio()
Materials
MaterialDesc::chrome()
Twelve material presets. Four camera lenses. Named lights, backgrounds, exposure scenarios, and environments. Every name in docs.rs/scena.
Native via wgpu. WebGL2 and WebGPU in the browser. One library, one API.
Renderer::from_surface_async(surface).await?
Render PNGs without a window, on CI, in tests, and in generated docs.
headless_gltf_viewer("model.glb").render_png_bytes().await?
Three lines of HTML with model-viewer-style browser ergonomics.
<scena-viewer src="model.glb" environment="studio" camera-controls>
Capability reporting per backend and source-enforced contracts in CI.
cargo run -p xtask -- doctor --full
Typed scene-graph handles, explicit prepare / render lifecycle, capability matrix per backend, reference-image regression API, and a doctor that pins API contracts in CI.
Native, headless, WebGL2, WebGPU. One library.