Expand description
§nightshade-api
A procedural high level API over the nightshade engine. Write a full 3d scene or a small game as straight-line code with free functions and plain data. No trait to implement, no callbacks to wire up, no ECS knowledge required to get started.
A spinning cube:
use nightshade_api::prelude::*;
fn main() {
let mut app = open();
let cube = spawn_cube(&mut app.world, vec3(0.0, 0.5, 0.0));
while frame(&mut app) {
let step = delta_time(&app.world);
rotate(&mut app.world, cube, Vec3::y(), step);
}
}Add to Cargo.toml:
nightshade-api = "0.46"§What you get for free
prelude::open gives you a window with a sky, a sun with shadows, a
reference grid, an orbit camera focused on the origin, prototype textures
like "checkerboard", and escape to exit. Every program starts from a lit,
navigable scene. Override any of it with one call: prelude::set_background,
prelude::show_grid, prelude::fly_camera, prelude::set_sun.
§The two entry points
Own the loop (native only). Setup is ordinary code before the loop, state is ordinary locals across loop iterations:
let mut app = open();
let mut score = 0;
while frame(&mut app) {
score += 1;
}Or hand the engine the loop with run, which also works on
wasm. Setup returns your state, the update closure receives it back every
frame:
run(
|world| spawn_cube(world, vec3(0.0, 0.5, 0.0)),
|world, cube| {
let step = delta_time(world);
rotate(world, *cube, Vec3::y(), step);
},
)
.unwrap();run returns a Result, so a real main returns it. For several per-frame
jobs, the run! macro takes any number of update systems:
fn main() -> Result<(), Box<dyn std::error::Error>> {
run!(setup, handle_input, move_player, check_collisions)
}For immediate-mode UI, enable the egui feature, call
enable_egui once in setup, then draw from
your update closure by pulling the frame’s context with
egui_context. No extra closure: it
composes with run and run! as is.
egui is re-exported from the prelude.
run(
|world| { enable_egui(world); spawn_cube(world, vec3(0.0, 0.5, 0.0)) },
|world, cube| {
rotate(world, *cube, Vec3::y(), delta_time(world));
if let Some(ctx) = egui_context(world) {
egui::Window::new("Inspector").show(&ctx, |ui| ui.label(format!("{cube:?}")));
}
},
)
.unwrap();§Vocabulary
Two verbs carry the lifetime rules. spawn_ is retained: the thing exists
until you prelude::despawn it. draw_ is immediate: visible for
exactly one frame, redraw it every frame you want it on screen.
- Scene content:
prelude::spawn_cube,prelude::spawn_sphere,prelude::spawn_floor,prelude::spawn_model,prelude::spawn_object - Crowds:
prelude::spawn_objects,prelude::spawn_instanced - Tags:
prelude::tag,prelude::tagged,prelude::for_each_tagged - Looks:
prelude::set_color,prelude::set_metallic_roughness,prelude::set_emissive,prelude::set_texture,prelude::set_normal_texture - Placement:
prelude::set_position,prelude::rotate,prelude::set_scale,prelude::set_parent - Cameras:
prelude::orbit_camera,prelude::fly_camera,prelude::first_person,prelude::fixed_camera,prelude::set_field_of_view,prelude::set_orthographic - Input:
prelude::key_down,prelude::wasd,prelude::mouse_clicked,prelude::clicked_entity - Immediate drawing:
prelude::draw_cube,prelude::draw_sphere,prelude::draw_line - Text:
prelude::spawn_text,prelude::set_text,prelude::spawn_label - UI:
prelude::spawn_panel,prelude::panel_button,prelude::panel_label,prelude::button_clicked; plus the full widget set:prelude::panel_data_grid,prelude::panel_tree_view,prelude::panel_property_grid,prelude::panel_color_picker,prelude::panel_date_picker,prelude::panel_command_palette,prelude::panel_modal,prelude::panel_virtual_list - Animation:
prelude::play_animation,prelude::play_animation_named,prelude::blend_to_animation,prelude::set_animation_speed - Post-processing:
prelude::set_ssao,prelude::set_ssr,prelude::set_tonemap,prelude::set_color_grading - Live physics tuning:
prelude::set_friction,prelude::set_restitution,prelude::set_mass,prelude::set_gravity_scale - Layout containers:
prelude::panel_row,prelude::panel_grid,prelude::panel_scroll; world-space UI:prelude::spawn_world_panel - Animation extras:
prelude::add_animation_event,prelude::add_animation_layer,prelude::reach_to,prelude::aim_at - Prefabs and undo:
prelude::make_prefab,prelude::spawn_prefab,prelude::UndoStack
§Reading the scene back
The setters have readers, which is what a tool that edits a scene rather than
just building one needs. prelude::describe_entity gathers an entity’s
whole editable state, prelude::get_color and friends read one field,
prelude::scene_tree and prelude::children walk the hierarchy,
prelude::list_materials reads the shared material registry, and
prelude::bounds_of with prelude::frame_entities measure and frame a
selection. prelude::save_scene and prelude::load_scene round-trip the
whole world to bytes. Components are added, removed, and snapshotted for undo
by prelude::ComponentKind, the surface the standalone editor is built on.
§Commands
Every call also has a data form. prelude::Command is a serde enum with
one variant per function, prelude::submit_command runs one, and
prelude::submit_commands runs a batch where a later command can name an
entity an earlier one produced with prelude::Ref::Result, so one batch
builds and wires up a scene. The enum is the wire format a binding targets:
build Command values, read prelude::CommandReply back, with the json
schema from prelude::command_schema. The free functions stay the real
implementations and the dispatch forwards to them.
See the commands example and docs/COMMAND_API.md.
§Dropping down to the engine
Every function here takes the real engine prelude::World and bottoms
out in normal nightshade calls. Nothing is hidden behind a wrapper type,
so when a program outgrows the facade you replace one call site at a time.
The full engine is re-exported at nightshade, one path away:
use nightshade_api::nightshade::prelude::*;§Examples
The examples/ directory is the tour. Run one with
just run-example solar_system from the repo root, or
cargo run -r -p nightshade-api --example solar_system. Every example also
runs in the browser with just run-example-wasm solar_system, which serves
it through trunk.
Re-exports§
pub use nightshade;
Modules§
- prelude
- Everything in one import.