Skip to content

Commit b992ded

Browse files
docs: lead the usage guide with the high-level api
Make nightshade-api the first thing to reach for when building a game. USAGE.md previously opened straight into the engine State and launch path and barely mentioned the api facade, so the concise procedural layer was hard to discover. Add a Start Here section covering the run shapes, defaults, verbs, a worked game, reads, and the command form, and point CLAUDE.md at the api for games while keeping the engine layer as the drop-down.
1 parent 148a34d commit b992ded

2 files changed

Lines changed: 211 additions & 56 deletions

File tree

CLAUDE.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Nightshade Engine
22

3-
Read `docs/USAGE.md` before writing or modifying engine code.
3+
For games, start with the high-level `nightshade-api` facade. Read `docs/SPEC_RUST_API.md` (the full signature catalog) and the "Start Here" section of `docs/USAGE.md`. The api games `apps/coin_dash` and `apps/coin_rush` and the `template_api/` template are the working references. Reach for the engine layer only when the facade stops covering what you need.
4+
5+
Read `docs/USAGE.md` before writing or modifying engine code (the `nightshade` crate layer).
46

57
## Architecture
68

@@ -9,7 +11,7 @@ Read `docs/USAGE.md` before writing or modifying engine code.
911
- Most systems run automatically via the frame schedule (`world.resources.schedules.frame`): physics, animation, navmesh, text sync, transforms, plus a single `RETAINED_UI` entry that runs the UI sub-schedule (`world.resources.schedules.retained_ui`). Don't call these manually.
1012
- Camera controllers are opt-in: call `fly_camera_system(world)` or `pan_orbit_camera_system(world)` in `run_systems`. `fly_camera_system` skips if the active camera has `PAN_ORBIT_CAMERA`.
1113
- Scenes load from glTF. Find entities by name after spawning (`world.core.find_entity_by_name`).
12-
- `apps/sandbox` is the go-to reference for idiomatic 3D games. Read it before writing a new app: state shell forwarding to system functions, own `freecs::ecs!` world, screen lifecycle in `systems/lifecycle.rs`, retained UI handles stored in resources, `theme.rs` for UI constants, prototype textures, level load/save. The `template/` crate is the same architecture in skeleton form.
14+
- `apps/sandbox` is the go-to reference for an idiomatic engine-level 3D game (when you have dropped below the `nightshade-api` facade). Read it before writing a new engine-layer app: state shell forwarding to system functions, own `freecs::ecs!` world, screen lifecycle in `systems/lifecycle.rs`, retained UI handles stored in resources, `theme.rs` for UI constants, prototype textures, level load/save. The `template/` crate is the same architecture in skeleton form.
1315

1416
## Querying
1517

docs/USAGE.md

Lines changed: 207 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,223 @@
22

33
Comprehensive API reference for the Nightshade game engine.
44

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

714
---
815

916
## Table of Contents
1017

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

64217
---
65218

66219
## Getting Started
67220

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

70223
### Cargo.toml
71224

0 commit comments

Comments
 (0)