# nightshade-api
A procedural high level API over the [nightshade](https://crates.io/crates/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:
```rust
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);
}
}
```
`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
```toml
[dependencies]
nightshade-api = "0.42.0"
```
## Two ways to run
Own the loop. Setup is code before the loop, game state is locals across iterations. Native only:
```rust
let mut app = open();
spawn_floor(&mut app.world, 20.0);
let mut score = 0;
while frame(&mut app) {
if let Some(coin) = clicked_entity(&app.world) {
despawn(&mut app.world, coin);
score += 1;
}
}
```
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:
```rust
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();
```
## 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.
| 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`, `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:
```rust
let ball = spawn_object(world, Object {
shape: Shape::Sphere,
position: vec3(0.0, 4.0, 0.0),
color: RED,
body: Body::Dynamic { mass: 2.0 },
..Object::default()
});
```
## Examples
Short programs that do a lot, in `examples/`. From the repo root:
```sh
just run-example physics_playground
```
| `spinning_cube` | The minimal program |
| `spinning_cube_portable` | The same program in the wasm-capable closure form |
| `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 |
| `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.
## 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`:
```rust
use nightshade_api::nightshade::prelude::*;
```
## Features
`default = ["audio", "physics", "gamepad", "picking", "navmesh"]`, each forwarding to the engine features of the same names.
## License
Dual-licensed under either of:
- MIT License ([LICENSE-MIT](https://github.com/matthewjberger/nightshade/blob/main/LICENSE-MIT) or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 ([LICENSE-APACHE](https://github.com/matthewjberger/nightshade/blob/main/LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
at your option.