nightshade-api 0.43.0

Procedural high level API for the nightshade game engine
Documentation
# 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.43.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();
```

`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:

```rust
fn main() -> Result<(), Box<dyn std::error::Error>> {
    run!(setup, handle_input, move_player, check_collisions)
}
```

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`, `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
```

| 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](https://trunkrs.dev), the same pipeline the engine's apps use:

```sh
just run-example-wasm collector
```

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.

## 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.