nightshade-api
A procedural high level API over the nightshade engine. Write full 3d scenes and small games as straight-line code: free functions, plain data, no trait to implement, no callbacks to wire up.
The engine's own hello world is a State impl with a camera, a sun, and dirty-flagged transform math. Here it is through this crate:
use *;
open() gives you a lit, navigable scene before your first line runs: procedural sky, sun with shadows, reference grid, orbit camera focused on the origin, prototype textures, and escape to exit. Every knob is one call to change.
Getting Started
[]
= "0.53.0"
Two ways to run
Own the loop. Setup is code before the loop, game state is locals across iterations. Native only:
let mut app = open;
spawn_floor;
let mut score = 0;
while frame
Or hand the engine the loop with run, which also works on wasm. Setup returns your state and the update closure receives it back every frame:
run
.unwrap;
run returns a Result, so a real main returns it rather than unwrapping. For more than one per-frame job, the run! macro takes any number of update systems, run in order over the state setup returns:
Each system is a fn(&mut World, &mut Data) or a non-capturing closure of that shape.
Vocabulary
Two verbs carry the lifetime rules. spawn_ is retained and lives until you despawn it. draw_ is immediate and visible for exactly one frame.
| Area | Calls |
|---|---|
| Scene | spawn_cube, spawn_sphere, spawn_floor, spawn_model, spawn_object, set_visible |
| Batches | spawn_objects (shared material), spawn_instanced (one draw call) |
| Tags | tag, untag, has_tag, tagged, for_each_tagged, for_each_with_position |
| Looks | set_color, set_metallic_roughness, set_emissive, set_texture, load_texture, spawn_decal |
| Placement | set_position, rotate, set_scale, set_parent, position |
| Animation | animate_position, animate_scale, animate_color, shake_camera |
| Effects | emit_fire, emit_smoke, emit_burst, spawn_cloth_sheet |
| Cameras | orbit_camera, fly_camera, first_person, fixed_camera, look_at |
| Environment | set_background, set_clear_color, show_grid, set_fog, set_bloom, set_time_of_day, set_exposure, set_depth_of_field |
| Lights | point_light, spot_light, set_sun |
| Input | key_down, key_pressed, wasd, axis, mouse_clicked, mouse_position |
| Picking | clicked_entity, entity_under_cursor, cursor_on_ground |
| Physics | Body::Dynamic on spawn_object, push, set_velocity, raycast, collisions |
| Joints | attach_fixed, attach_hinge, attach_spring, attach_rope |
| Navigation | bake_navmesh, spawn_walker, walk_to, set_walk_speed, stop_walking |
| Immediate | draw_cube, draw_sphere, draw_line, draw_text_3d |
| Text | spawn_text, set_text, spawn_label |
| Audio | load_sound, play_sound, play_sound_at, play_sound_looping, set_volume |
spawn_object covers the loaded case in one struct literal:
let ball = spawn_object;
Examples
Short programs that do a lot, in examples/. From the repo root:
| Example | Shows |
|---|---|
spinning_cube |
The minimal program |
gallery |
Primitives, a metallic and roughness sweep, emissive, textures |
solar_system |
Orbital motion, parenting, emissive sun, bloom |
physics_playground |
A block tower, projectiles, click interaction, HUD text |
fps_walk |
First person walking with collision in fifteen lines |
collector |
A complete walk and collect game with a win condition |
juice |
Tweens, easing, particle bursts, and camera shake |
poster |
Rendering a composed scene straight to a png, no window |
model_viewer |
Animated glb loading (pass a path, defaults to the fox) |
hud |
Anchored screen text, live fps, runtime setting toggles |
day_night |
Time of day, fog, point lights, a procedural skyline |
parity |
The same workload api-spelled and longhand-spelled, timed |
Set NIGHTSHADE_API_FRAMES=120 to exit after a frame budget, which is what just test-examples uses to smoke test every example against the real renderer.
Running on the web
Every example also runs in the browser. Serve one with trunk, the same pipeline the engine's apps use:
That relies on the index.html and Trunk.toml in this crate (the canvas page plus the wasm build settings), so a project of your own needs an equivalent pair next to its Cargo.toml. Because the browser owns the loop, the examples use the portable run(setup, update) form rather than the native open()/frame() loop. poster is the one with a split: it writes a png natively and renders the same scene to the canvas on the web.
For an interactive take on the web build, apps/playground runs the engine in a worker on an OffscreenCanvas and lets you write rhai against the live scene, with hot reload, a built-in example gallery, and a console for log(...) output and errors. It is the scripting counterpart to the native examples and embeds a single pinned example through URL params for docs.
Dropping down to the engine
Every function takes the engine's World and bottoms out in normal nightshade calls. When a program outgrows the facade, replace one call site at a time. The full engine is re-exported at nightshade_api::nightshade:
use *;
Features
default = ["engine", "audio", "physics", "gamepad", "picking", "navmesh"]. The engine feature is the whole facade over the nightshade engine; the rest forward to the engine features of the same names. Optional extras: scripting, terrain, grass, net, egui, protocol.
Two features cover browser apps where the engine runs in a web worker on an OffscreenCanvas:
offscreenis the worker side.nightshade_api::offscreen::WorkerHostPluginhosts the composedAppinside the worker: it installs a custom runner owning the canvas, the render loop, and the page conversation (input injection, resize, picking, stats), generic over the app'sWorkerProtocolmessage pair with binary attachments and aWorkerOutboxreply resource.run_offscreen(config, scene, setup, tick, on_custom)remains the closure form over JSON values.leptosis the page side,nightshade_api::web: a Leptos (CSR) component library (panels, forms, menus, tables, trees, a command palette, keybindings, a code editor, a status bar, docking, themes) plus a worker-backedEngineViewportwith reactive engine state, created withuse_engine(JSON messages) oruse_engine_typed(the app's protocol), and the browser file plumbing (downloads, pickers, drag and drop, pointer lock). It is engine-free, so a page crate usesdefault-features = false, features = ["leptos"]and never compiles the engine.
The nightshade-template-leptos and nightshade-api-template-leptos repos are the working references for the web architecture.
License
Dual-licensed under either of:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.