|
2 | 2 |
|
3 | 3 | Comprehensive API reference for the Nightshade game engine. |
4 | 4 |
|
5 | | -Most types and functions are available via `use nightshade::prelude::*`. Items that require explicit imports are noted with their full path. |
| 5 | +Two layers ship in this repo, and which one you start in matters: |
| 6 | + |
| 7 | +- **`nightshade-api`** is the high-level procedural facade. Free functions over the engine `World`, plain data, no trait to implement, no ECS knowledge required. **For a game, reach for this first.** It is far more concise than the engine layer and covers the whole procedural core of making things appear and behave. See [Start Here: The High-Level API](#start-here-the-high-level-api-nightshade-api) below, with the full catalog in `docs/SPEC_RUST_API.md` and the `api-*` chapters under `docs/book/src/`. |
| 8 | +- **`nightshade`** is the engine itself: the `State` trait, the ECS, the render graph, every subsystem. Everything after the high-level section documents this layer. You drop down to it one call at a time when the facade stops covering what you need. |
| 9 | + |
| 10 | +Every `nightshade-api` function bottoms out in an engine call and hands you the real `World`, so nothing is hidden and there is no migration cost. From an api program, reach the full engine with `use nightshade_api::nightshade::prelude::*;`. |
| 11 | + |
| 12 | +For the engine layer, most types and functions are available via `use nightshade::prelude::*`. Items that require explicit imports are noted with their full path. |
6 | 13 |
|
7 | 14 | --- |
8 | 15 |
|
9 | 16 | ## Table of Contents |
10 | 17 |
|
11 | | -1. [Getting Started](#getting-started) |
12 | | -2. [The State Trait](#the-state-trait) |
13 | | -3. [ECS & Entity Management](#ecs--entity-management) |
14 | | -4. [World Resources](#world-resources) |
15 | | -5. [3D Meshes & Scenes](#3d-meshes--scenes) |
16 | | -6. [Instanced Meshes](#instanced-meshes) |
17 | | -7. [Cameras](#cameras) |
18 | | -8. [Lighting](#lighting) |
19 | | -9. [Materials & Textures](#materials--textures) |
20 | | -10. [Shadows](#shadows) |
21 | | -11. [Grass](#grass-grass-feature) |
22 | | -12. [Terrain](#terrain-terrain-feature-implies-grass) |
23 | | -13. [Post-Processing](#post-processing) |
24 | | -14. [Custom Render Passes](#custom-render-passes) |
25 | | -15. [Input Handling](#input-handling) |
26 | | -16. [Physics](#physics) |
27 | | -17. [Audio](#audio) |
28 | | -18. [Skeletal Animation](#skeletal-animation) |
29 | | -19. [Inverse Kinematics](#inverse-kinematics) |
30 | | -20. [Morph Targets](#morph-targets) |
31 | | -21. [Particle Systems](#particle-systems) |
32 | | -22. [Cloth Simulation](#cloth-simulation) |
33 | | -23. [Tweens & Shake](#tweens--shake) |
34 | | -24. [Cutscenes](#cutscenes) |
35 | | -25. [Text Rendering](#text-rendering) |
36 | | -26. [UI: Retained Mode](#ui-retained-mode) |
37 | | -27. [UI: Docking & Tiles](#ui-docking--tiles) |
38 | | -28. [Scene Serialization](#scene-serialization) |
39 | | -29. [Procedural Generation](#procedural-generation) |
40 | | -30. [Pathfinding & Navigation](#pathfinding--navigation) |
41 | | -31. [Picking & Raycasting](#picking--raycasting) |
42 | | -32. [Debug Lines](#debug-lines) |
43 | | -33. [Atmosphere & Skybox](#atmosphere--skybox) |
44 | | -34. [Decals](#decals) |
45 | | -35. [Render Layers](#render-layers) |
46 | | -36. [Prefabs & GLTF Loading](#prefabs--gltf-loading) |
47 | | -37. [Entity Hierarchy](#entity-hierarchy) |
48 | | -38. [Entity GUIDs](#entity-guids) |
49 | | -39. [Event Bus](#event-bus) |
50 | | -40. [Event Stream](#event-stream) |
51 | | -41. [Multi-World Rendering](#multi-world-rendering) |
52 | | -42. [Steam Integration](#steam-integration) |
53 | | -43. [Hot Reload](#hot-reload) |
54 | | -44. [Developer Console](#developer-console-shell) |
55 | | -45. [LOD (Level of Detail)](#lod-level-of-detail) |
56 | | -46. [Asset Loading Queue](#asset-loading-queue) |
57 | | -47. [Scripting](#scripting) |
58 | | -48. [Game Development Patterns](#game-development-patterns) |
59 | | -49. [Common Non-Prelude Imports](#common-non-prelude-imports) |
60 | | -50. [Offscreen & Headless Rendering](#offscreen--headless-rendering) |
61 | | -51. [Platform Notes](#platform-notes) |
62 | | -52. [Visual Effects](#visual-effects) |
| 18 | +1. [Start Here: The High-Level API (nightshade-api)](#start-here-the-high-level-api-nightshade-api) |
| 19 | +2. [Getting Started](#getting-started) |
| 20 | +3. [The State Trait](#the-state-trait) |
| 21 | +4. [ECS & Entity Management](#ecs--entity-management) |
| 22 | +5. [World Resources](#world-resources) |
| 23 | +6. [3D Meshes & Scenes](#3d-meshes--scenes) |
| 24 | +7. [Instanced Meshes](#instanced-meshes) |
| 25 | +8. [Cameras](#cameras) |
| 26 | +9. [Lighting](#lighting) |
| 27 | +10. [Materials & Textures](#materials--textures) |
| 28 | +11. [Shadows](#shadows) |
| 29 | +12. [Grass](#grass-grass-feature) |
| 30 | +13. [Terrain](#terrain-terrain-feature-implies-grass) |
| 31 | +14. [Post-Processing](#post-processing) |
| 32 | +15. [Custom Render Passes](#custom-render-passes) |
| 33 | +16. [Input Handling](#input-handling) |
| 34 | +17. [Physics](#physics) |
| 35 | +18. [Audio](#audio) |
| 36 | +19. [Skeletal Animation](#skeletal-animation) |
| 37 | +20. [Inverse Kinematics](#inverse-kinematics) |
| 38 | +21. [Morph Targets](#morph-targets) |
| 39 | +22. [Particle Systems](#particle-systems) |
| 40 | +23. [Cloth Simulation](#cloth-simulation) |
| 41 | +24. [Tweens & Shake](#tweens--shake) |
| 42 | +25. [Cutscenes](#cutscenes) |
| 43 | +26. [Text Rendering](#text-rendering) |
| 44 | +27. [UI: Retained Mode](#ui-retained-mode) |
| 45 | +28. [UI: Docking & Tiles](#ui-docking--tiles) |
| 46 | +29. [Scene Serialization](#scene-serialization) |
| 47 | +30. [Procedural Generation](#procedural-generation) |
| 48 | +31. [Pathfinding & Navigation](#pathfinding--navigation) |
| 49 | +32. [Picking & Raycasting](#picking--raycasting) |
| 50 | +33. [Debug Lines](#debug-lines) |
| 51 | +34. [Atmosphere & Skybox](#atmosphere--skybox) |
| 52 | +35. [Decals](#decals) |
| 53 | +36. [Render Layers](#render-layers) |
| 54 | +37. [Prefabs & GLTF Loading](#prefabs--gltf-loading) |
| 55 | +38. [Entity Hierarchy](#entity-hierarchy) |
| 56 | +39. [Entity GUIDs](#entity-guids) |
| 57 | +40. [Event Bus](#event-bus) |
| 58 | +41. [Event Stream](#event-stream) |
| 59 | +42. [Multi-World Rendering](#multi-world-rendering) |
| 60 | +43. [Steam Integration](#steam-integration) |
| 61 | +44. [Hot Reload](#hot-reload) |
| 62 | +45. [Developer Console](#developer-console-shell) |
| 63 | +46. [LOD (Level of Detail)](#lod-level-of-detail) |
| 64 | +47. [Asset Loading Queue](#asset-loading-queue) |
| 65 | +48. [Scripting](#scripting) |
| 66 | +49. [Game Development Patterns](#game-development-patterns) |
| 67 | +50. [Common Non-Prelude Imports](#common-non-prelude-imports) |
| 68 | +51. [Offscreen & Headless Rendering](#offscreen--headless-rendering) |
| 69 | +52. [Platform Notes](#platform-notes) |
| 70 | +53. [Visual Effects](#visual-effects) |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Start Here: The High-Level API (nightshade-api) |
| 75 | + |
| 76 | +`nightshade-api` is a procedural layer over the engine. A whole scene or a small game reads as straight-line code: free functions, plain data, no trait, no callbacks, no ECS. Everything bottoms out in normal engine calls, so nothing is hidden and nothing is walled off. This is the first thing to reach for when building a game. The rest of this guide is the engine layer underneath, which you drop into when the facade stops covering what you need. |
| 77 | + |
| 78 | +The complete reference is `docs/SPEC_RUST_API.md` (the full signature catalog, written to be read once) and the `api-*` chapters under `docs/book/src/`. The serialized command form is `docs/COMMAND_API.md`. |
| 79 | + |
| 80 | +### Cargo.toml |
| 81 | + |
| 82 | +```toml |
| 83 | +[dependencies] |
| 84 | +# Inside this repo: |
| 85 | +nightshade-api = { path = "crates/nightshade-api" } |
| 86 | +# Outside the repo (versions in lockstep with the engine): |
| 87 | +nightshade-api = "0.46" |
| 88 | +``` |
| 89 | + |
| 90 | +Default features: `audio`, `physics`, `gamepad`, `picking`, `navmesh` (each forwards to the engine feature of the same name). Opt-in: `scripting`, `terrain`, `grass`, `egui`, `net`. Disable defaults with `default-features = false` and an explicit list. |
| 91 | + |
| 92 | +### What you get for free |
| 93 | + |
| 94 | +`open()` and `run()` start you in a working scene, not a black screen: a sky, a sun with shadows, a reference grid, an orbit camera pointed at the origin, prototype textures (`"checkerboard"`, `"gradient"`, `"uv_test"`), physics on, and escape to exit. Building a scene is choosing what to change. |
| 95 | + |
| 96 | +### Two ways to run |
| 97 | + |
| 98 | +Own the loop (native). Setup is statements before the loop, game state is plain locals across iterations: |
| 99 | + |
| 100 | +```rust |
| 101 | +use nightshade_api::prelude::*; |
| 102 | + |
| 103 | +fn main() { |
| 104 | + let mut app = open(); |
| 105 | + let cube = spawn_cube(&mut app.world, vec3(0.0, 0.5, 0.0)); |
| 106 | + while frame(&mut app) { |
| 107 | + rotate(&mut app.world, cube, Vec3::y(), delta_time(&app.world)); |
| 108 | + } |
| 109 | +} |
| 110 | +``` |
| 111 | + |
| 112 | +Hand the engine the loop (native and wasm). `setup` returns your state, `update` receives it back every frame: |
| 113 | + |
| 114 | +```rust |
| 115 | +fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 116 | + run( |
| 117 | + |world| spawn_cube(world, vec3(0.0, 0.5, 0.0)), |
| 118 | + |world, cube| rotate(world, *cube, Vec3::y(), delta_time(world)), |
| 119 | + ) |
| 120 | +} |
| 121 | +``` |
| 122 | + |
| 123 | +`run!` takes any number of update systems sharing one state: `run!(setup, handle_input, move_player, check_collisions)`. `run_scene(setup)` is a static scene with no update. `render_image(width, height, path, setup)` renders one frame to a PNG with no window. |
| 124 | + |
| 125 | +### The verbs |
| 126 | + |
| 127 | +- `spawn_` is retained until you `despawn` it. `draw_` lasts one frame, so call it every frame you want it visible. |
| 128 | +- `set_` writes, `get_`/noun-named functions read. Colors are `[f32; 4]` linear RGBA, positions are `Vec3` via `vec3(...)`. |
| 129 | + |
| 130 | +```rust |
| 131 | +spawn_cube / spawn_sphere / spawn_cylinder / spawn_cone / spawn_torus / spawn_plane |
| 132 | +spawn_floor(world, half_extent) // ground plane |
| 133 | +spawn_model(world, glb_bytes, position) // animated glb |
| 134 | +spawn_object(world, Object { shape, position, scale, color, body }) // shape + color + physics in one |
| 135 | +spawn_objects / spawn_instanced // crowds |
| 136 | + |
| 137 | +set_color / set_metallic_roughness / set_emissive / set_texture |
| 138 | +set_position / rotate / set_scale / set_parent |
| 139 | +position(world, entity) -> Vec3 |
| 140 | + |
| 141 | +orbit_camera / fly_camera / first_person / third_person_camera / fixed_camera |
| 142 | +point_light / spot_light / directional_light / area_light / set_sun |
| 143 | +set_background / set_bloom / set_ssao / set_fog / set_time_of_day |
| 144 | + |
| 145 | +key_down / key_pressed / wasd / mouse_clicked / clicked_entity / delta_time |
| 146 | +push / set_velocity / raycast / collisions / overlap_sphere // physics |
| 147 | +spawn_panel + panel_button / panel_slider / panel_label + button_clicked / slider_value // UI |
| 148 | +spawn_text / set_text / spawn_label |
| 149 | +play_animation_named / blend_to_animation_named // on a loaded model |
| 150 | +``` |
| 151 | + |
| 152 | +The `Object` struct (has `Default`) is the fastest way to spawn a physical, colored shape: |
| 153 | + |
| 154 | +```rust |
| 155 | +spawn_object(world, Object { |
| 156 | + shape: Shape::Cube, |
| 157 | + position: vec3(0.0, 5.0, 0.0), |
| 158 | + color: BLUE, |
| 159 | + body: Body::Dynamic { mass: 1.0 }, // None, Static, or Dynamic |
| 160 | + ..Object::default() |
| 161 | +}); |
| 162 | +``` |
| 163 | + |
| 164 | +### A small game |
| 165 | + |
| 166 | +```rust |
| 167 | +use nightshade_api::prelude::*; |
| 168 | + |
| 169 | +struct Game { player: Entity, score: Entity, points: u32 } |
| 170 | + |
| 171 | +fn main() { run!(setup, play).unwrap(); } |
| 172 | + |
| 173 | +fn setup(world: &mut World) -> Game { |
| 174 | + set_background(world, Background::Sunset); |
| 175 | + spawn_floor(world, 30.0); |
| 176 | + let player = spawn_object(world, Object { |
| 177 | + shape: Shape::Sphere, position: vec3(0.0, 0.5, 0.0), color: GOLD, ..Object::default() |
| 178 | + }); |
| 179 | + for index in 0..8 { |
| 180 | + let coin = spawn_torus(world, vec3((index as f32 - 4.0) * 3.0, 0.5, -6.0)); |
| 181 | + set_emissive(world, coin, [1.0, 0.8, 0.1], 4.0); |
| 182 | + tag(world, coin, "coin"); |
| 183 | + } |
| 184 | + let panel = spawn_panel(world, ScreenAnchor::TopLeft, 160.0, 40.0); |
| 185 | + let score = panel_label(world, panel, "score: 0"); |
| 186 | + Game { player, score, points: 0 } |
| 187 | +} |
| 188 | + |
| 189 | +fn play(world: &mut World, game: &mut Game) { |
| 190 | + let step = wasd(world) * 8.0 * delta_time(world); |
| 191 | + set_position(world, game.player, position(world, game.player) + step); |
| 192 | + let here = position(world, game.player); |
| 193 | + for coin in tagged(world, "coin") { |
| 194 | + if (position(world, coin) - here).norm() < 1.0 { |
| 195 | + despawn(world, coin); |
| 196 | + game.points += 1; |
| 197 | + set_text(world, game.score, &format!("score: {}", game.points)); |
| 198 | + } |
| 199 | + } |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +Working references: the examples in `crates/nightshade-api/examples` (run with `just run-example <name>`), the api games `apps/coin_dash` and `apps/coin_rush`, and the templates `template_api/` (native) and `template_api_leptos/` (web worker plus Leptos). |
| 204 | + |
| 205 | +### Reading state back |
| 206 | + |
| 207 | +Reads are direct and typed, never round-tripped: `position`, `velocity`, `slider_value`, `get_color`, `name`, `children`, `descendants`, `roots`, `scene_tree`, `bounds`. `describe_entity(world, entity)` returns the whole editable state of one entity. Events come from `drain_events(world)` (collisions, animation, navigation). |
| 208 | + |
| 209 | +### Command form (for FFI, scripts, network, replay) |
| 210 | + |
| 211 | +Every mutating call also exists as a `Command` enum variant (300-plus), so the engine can be driven by serialized data. `submit_command(world, &cmd)` and `submit_commands(world, &batch)` dispatch them, `Ref::Result(n)` names the entity an earlier command in the same batch produced so one batch builds and wires a whole scene. Native code just calls the free functions, which are the real implementations. Details in `docs/COMMAND_API.md`. |
| 212 | + |
| 213 | +### When to drop to the engine |
| 214 | + |
| 215 | +The facade deliberately does not cover custom render passes, multi-world rendering, or user-defined ECS components. For those, read the engine-layer sections below. `apps/sandbox` is the canonical engine-level game reference. Migrate one call site at a time with `use nightshade_api::nightshade::prelude::*;`, never all at once. |
63 | 216 |
|
64 | 217 | --- |
65 | 218 |
|
66 | 219 | ## Getting Started |
67 | 220 |
|
68 | | -Every Nightshade application implements the `State` trait and calls `launch()`. |
| 221 | +The engine layer (the `nightshade` crate). Every Nightshade application here implements the `State` trait and calls `launch()`. For most games, prefer the [high-level API](#start-here-the-high-level-api-nightshade-api) above and only reach for this when you need it. |
69 | 222 |
|
70 | 223 | ### Cargo.toml |
71 | 224 |
|
|
0 commit comments