Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Quick Reference

Quick lookup for common Nightshade API functions and types.

World

Entity Management

#![allow(unused)]
fn main() {
let entities = world.spawn_entities(flags, count);
let entity = world.spawn_entities(LOCAL_TRANSFORM | RENDER_MESH, 1)[0];

world.despawn_entities(&[entity]);

for entity in world.core.query_entities(LOCAL_TRANSFORM | RENDER_MESH) {
    let transform = world.core.get_local_transform(entity);
}
}

Component Access

#![allow(unused)]
fn main() {
world.core.get_local_transform(entity) -> Option<&LocalTransform>
world.core.get_global_transform(entity) -> Option<&GlobalTransform>
world.core.get_render_mesh(entity) -> Option<&RenderMesh>
world.core.get_material_ref(entity) -> Option<&MaterialRef>
world.core.get_camera(entity) -> Option<&Camera>
world.core.get_rigid_body(entity) -> Option<&RigidBodyComponent>
world.core.get_collider(entity) -> Option<&ColliderComponent>
world.core.get_animation_player(entity) -> Option<&AnimationPlayer>
world.core.get_parent(entity) -> Option<&Parent>
world.core.get_visibility(entity) -> Option<&Visibility>

world.core.get_local_transform_mut(entity) -> Option<&mut LocalTransform>
world.core.get_rigid_body_mut(entity) -> Option<&mut RigidBodyComponent>

world.core.set_local_transform(entity, LocalTransform { ... })
world.core.set_light(entity, Light { ... })

set_material_with_textures(world, entity, Material { ... })
}

Resources

#![allow(unused)]
fn main() {
world.resources.window.timing.delta_time
world.resources.window.timing.frames_per_second
world.resources.window.timing.uptime_milliseconds
world.resources.input.keyboard
world.resources.input.mouse
world.resources.graphics.show_cursor
world.set_cursor_visible(bool)
world.set_cursor_locked(bool)
world.resources.active_camera
world.resources.graphics.ambient_light
world.resources.physics.gravity
}

Component Flags

#![allow(unused)]
fn main() {
ANIMATION_PLAYER
NAME
LOCAL_TRANSFORM
GLOBAL_TRANSFORM
LOCAL_TRANSFORM_DIRTY
PARENT
IGNORE_PARENT_SCALE
AUDIO_SOURCE
AUDIO_LISTENER
CAMERA
PAN_ORBIT_CAMERA
LIGHT
LINES
VISIBILITY
DECAL
RENDER_MESH
MATERIAL_REF
RENDER_LAYER
SPRITE
SPRITE_ANIMATOR
TEXT
TEXT_CHARACTER_COLORS
TEXT_CHARACTER_BACKGROUND_COLORS
BOUNDING_VOLUME
HOVERED
ROTATION
CASTS_SHADOW
RIGID_BODY
COLLIDER
CHARACTER_CONTROLLER
COLLISION_LISTENER
PHYSICS_INTERPOLATION
INSTANCED_MESH
PARTICLE_EMITTER
PREFAB_SOURCE
PREFAB_INSTANCE
SCRIPT
SKIN
JOINT
MORPH_WEIGHTS
NAVMESH_AGENT
LATTICE
LATTICE_INFLUENCED
WATER
GRASS_REGION
GRASS_INTERACTOR
TWEEN
}

Transform

#![allow(unused)]
fn main() {
LocalTransform {
    translation: Vec3,
    rotation: nalgebra_glm::Quat,
    scale: Vec3,
}

LocalTransform::default()

LocalTransform {
    translation: Vec3::new(x, y, z),
    rotation: nalgebra_glm::quat_angle_axis(angle, &axis),
    scale: Vec3::new(1.0, 1.0, 1.0),
}
}

Camera

#![allow(unused)]
fn main() {
Camera {
    projection: Projection,
    smoothing: Option<Smoothing>,
}

PerspectiveCamera {
    aspect_ratio: Option<f32>,
    y_fov_rad: f32,
    z_far: Option<f32>,
    z_near: f32,
}

OrthographicCamera {
    x_mag: f32,
    y_mag: f32,
    z_far: f32,
    z_near: f32,
}

spawn_camera(world, position: Vec3, name: String) -> Entity
spawn_pan_orbit_camera(world, focus: Vec3, radius: f32, yaw: f32, pitch: f32, name: String) -> Entity
spawn_ortho_camera(world, position: Vec2) -> Entity
}

Primitives

#![allow(unused)]
fn main() {
spawn_cube_at(world, position: Vec3) -> Entity
spawn_sphere_at(world, position: Vec3) -> Entity
spawn_plane_at(world, position: Vec3) -> Entity
spawn_cylinder_at(world, position: Vec3) -> Entity
spawn_cone_at(world, position: Vec3) -> Entity
spawn_torus_at(world, position: Vec3) -> Entity
spawn_mesh_at(world, mesh_name: &str, position: Vec3, scale: Vec3) -> Entity
spawn_water_plane_at(world, position: Vec3) -> Entity
}

Model Loading

#![allow(unused)]
fn main() {
let result = import_gltf_from_bytes(model_data).unwrap();
let prefab = result.prefabs.first().unwrap();
let entity = spawn_prefab_with_animations(world, prefab, &result.animations, Vec3::zeros());

for entity in entities {
    if let Some(transform) = world.core.get_local_transform_mut(entity) {
        transform.scale = Vec3::new(0.01, 0.01, 0.01);
    }
}
}

Materials

#![allow(unused)]
fn main() {
Material {
    base_color: [f32; 4],
    emissive_factor: [f32; 3],
    alpha_mode: AlphaMode,
    alpha_cutoff: f32,
    base_texture: Option<String>,
    base_texture_uv_set: u32,
    emissive_texture: Option<String>,
    emissive_texture_uv_set: u32,
    normal_texture: Option<String>,
    normal_texture_uv_set: u32,
    normal_scale: f32,
    normal_map_flip_y: bool,
    normal_map_two_component: bool,
    metallic_roughness_texture: Option<String>,
    metallic_roughness_texture_uv_set: u32,
    occlusion_texture: Option<String>,
    occlusion_texture_uv_set: u32,
    occlusion_strength: f32,
    roughness: f32,
    metallic: f32,
    unlit: bool,
    double_sided: bool,
    uv_scale: [f32; 2],
    transmission_factor: f32,
    transmission_texture: Option<String>,
    transmission_texture_uv_set: u32,
    thickness: f32,
    thickness_texture: Option<String>,
    thickness_texture_uv_set: u32,
    attenuation_color: [f32; 3],
    attenuation_distance: f32,
    ior: f32,
    specular_factor: f32,
    specular_color_factor: [f32; 3],
    specular_texture: Option<String>,
    specular_texture_uv_set: u32,
    specular_color_texture: Option<String>,
    specular_color_texture_uv_set: u32,
    emissive_strength: f32,
}
}

Lighting

#![allow(unused)]
fn main() {
spawn_sun(world) -> Entity
spawn_sun_without_shadows(world) -> Entity

Light {
    light_type: LightType,
    color: Vec3,
    intensity: f32,
    range: f32,
    inner_cone_angle: f32,
    outer_cone_angle: f32,
    cast_shadows: bool,
    shadow_bias: f32,
}
}

Physics

#![allow(unused)]
fn main() {
world.core.set_rigid_body(entity, RigidBodyComponent::new_dynamic())
world.core.set_collider(entity, ColliderComponent::new_cuboid(hx, hy, hz))

RigidBodyComponent::new_dynamic()
RigidBodyComponent::new_static()
RigidBodyComponent::new_kinematic()

ColliderComponent::new_cuboid(hx: f32, hy: f32, hz: f32)
ColliderComponent::new_ball(radius: f32)
ColliderComponent::new_capsule(half_height: f32, radius: f32)
ColliderComponent::new_cylinder(half_height: f32, radius: f32)
ColliderComponent::new_cone(half_height: f32, radius: f32)

spawn_static_physics_cube_with_material(world, position, size, material)
spawn_dynamic_physics_cube_with_material(world, position, size, mass, material)
spawn_dynamic_physics_sphere_with_material(world, position, radius, mass, material)
spawn_dynamic_physics_cylinder_with_material(world, position, half_height, radius, mass, material)

run_physics_systems(world)
sync_transforms_from_physics_system(world)
sync_transforms_to_physics_system(world)
initialize_physics_bodies_system(world)
physics_interpolation_system(world)
character_controller_system(world)
character_controller_input_system(world)
}

Joints

#![allow(unused)]
fn main() {
create_fixed_joint(world, parent, child, FixedJoint::new()
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
create_revolute_joint(world, parent, child, RevoluteJoint::new(axis)
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
create_prismatic_joint(world, parent, child, PrismaticJoint::new(axis)
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
create_spherical_joint(world, parent, child, SphericalJoint::new()
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
create_rope_joint(world, parent, child, RopeJoint::new(max_distance)
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
create_spring_joint(world, parent, child, SpringJoint::new(rest_length, stiffness, damping)
    .with_local_anchor1(anchor1).with_local_anchor2(anchor2)) -> Option<JointHandle>
}

Animation

#![allow(unused)]
fn main() {
if let Some(player) = world.core.get_animation_player_mut(entity) {
    player.play(clip_index);
    player.blend_to(clip_index, duration);
    player.stop();
    player.pause();
    player.resume();
    player.looping = true;
    player.speed = 1.0;
    player.time = 0.0;
    player.playing
    player.current_clip
}

update_animation_players(world, dt: f32)
}

Audio

Requires the audio feature.

#![allow(unused)]
fn main() {
let data = load_sound_from_bytes(include_bytes!("sound.ogg")).unwrap();
let data = load_sound_from_cursor(cursor_data).unwrap();

world.resources.audio.load_sound("name", data);
world.resources.audio.stop_sound(entity);

let source = world.spawn_entities(AUDIO_SOURCE | LOCAL_TRANSFORM | GLOBAL_TRANSFORM, 1)[0];
world.core.set_audio_source(source, AudioSource::new("name")
    .with_spatial(true)
    .with_looping(true)
    .with_reverb(true)
    .with_volume(0.8)
    .playing(),
);
}

Input

#![allow(unused)]
fn main() {
world.resources.input.keyboard.is_key_pressed(KeyCode::KeyW) -> bool

world.resources.input.mouse.position -> Vec2
world.resources.input.mouse.position_delta -> Vec2
world.resources.input.mouse.wheel_delta -> Vec2
world.resources.input.mouse.state.contains(MouseState::LEFT_CLICKED) -> bool
world.resources.input.mouse.state.contains(MouseState::RIGHT_CLICKED) -> bool
world.resources.input.mouse.state.contains(MouseState::LEFT_JUST_PRESSED) -> bool

world.resources.graphics.show_cursor = false;
world.set_cursor_visible(false);
world.set_cursor_locked(true);

query_active_gamepad(world) -> Option<gilrs::Gamepad<'_>>
}

Screen-Space Text

#![allow(unused)]
fn main() {
spawn_ui_text(world, text: impl Into<String>, position: Vec2) -> Entity
spawn_ui_text_with_properties(world, text: impl Into<String>, position: Vec2, properties: TextProperties) -> Entity

TextProperties {
    font_size: f32,
    color: Vec4,
    alignment: TextAlignment,
    vertical_alignment: VerticalAlignment,
    line_height: f32,
    letter_spacing: f32,
    outline_width: f32,
    outline_color: Vec4,
    smoothing: f32,
    monospace_width: Option<f32>,
    anchor_character: Option<usize>,
}

TextAlignment::Left | Center | Right
VerticalAlignment::Top | Middle | Bottom | Baseline
}

Particles

#![allow(unused)]
fn main() {
ParticleEmitter {
    emitter_type: EmitterType,
    shape: EmitterShape,
    position: Vec3,
    direction: Vec3,
    spawn_rate: f32,
    burst_count: u32,
    particle_lifetime_min: f32,
    particle_lifetime_max: f32,
    initial_velocity_min: f32,
    initial_velocity_max: f32,
    velocity_spread: f32,
    gravity: Vec3,
    drag: f32,
    size_start: f32,
    size_end: f32,
    color_gradient: ColorGradient,
    emissive_strength: f32,
    turbulence_strength: f32,
    turbulence_frequency: f32,
    enabled: bool,
}
}

Requires the navmesh feature.

#![allow(unused)]
fn main() {
generate_navmesh_recast(vertices: &[[f32; 3]], indices: &[[u32; 3]], config: &RecastNavMeshConfig) -> Option<NavMeshWorld>

spawn_navmesh_agent(world, position: Vec3, radius: f32, height: f32) -> Entity
set_agent_destination(world, entity: Entity, destination: Vec3)
set_agent_speed(world, entity: Entity, speed: f32)
stop_agent(world, entity: Entity)
get_agent_state(world, entity: Entity) -> Option<NavMeshAgentState>
get_agent_path_length(world, entity: Entity) -> Option<f32>

find_closest_point_on_navmesh(navmesh: &NavMeshWorld, point: Vec3) -> Option<Vec3>
sample_navmesh_height(navmesh: &NavMeshWorld, x: f32, z: f32) -> Option<f32>
set_navmesh_debug_draw(world, enabled: bool)
clear_navmesh(world)

run_navmesh_systems(world, delta_time: f32)
}

Math (nalgebra_glm)

#![allow(unused)]
fn main() {
Vec2::new(x, y)
Vec3::new(x, y, z)
Vec4::new(x, y, z, w)
Vec3::zeros()
Vec3::x()
Vec3::y()
Vec3::z()

vec.normalize()
vec.magnitude()
vec.dot(&other)
vec.cross(&other)

nalgebra_glm::quat_identity()
nalgebra_glm::quat_angle_axis(angle: f32, axis: &Vec3) -> Quat
nalgebra_glm::quat_slerp(from: &Quat, to: &Quat, t: f32) -> Quat

nalgebra_glm::lerp(from: &Vec3, to: &Vec3, t: f32) -> Vec3
}

State Trait

#![allow(unused)]
fn main() {
trait State {
    fn title(&self) -> &str { "Nightshade" }
    fn icon_bytes(&self) -> Option<&'static [u8]> { ... }
    fn initialize(&mut self, world: &mut World) {}
    fn run_systems(&mut self, world: &mut World) {}
    fn ui(&mut self, world: &mut World, ctx: &egui::Context) {}
    fn secondary_ui(&mut self, world: &mut World, window_index: usize, ctx: &egui::Context) {}
    fn on_keyboard_input(&mut self, world: &mut World, key_code: KeyCode, key_state: ElementState) {}
    fn on_mouse_input(&mut self, world: &mut World, state: ElementState, button: MouseButton) {}
    fn on_gamepad_event(&mut self, world: &mut World, event: gilrs::Event) {}
    fn handle_event(&mut self, world: &mut World, message: &Message) {}
    fn on_dropped_file(&mut self, world: &mut World, path: &Path) {}
    fn on_dropped_file_data(&mut self, world: &mut World, name: &str, data: &[u8]) {}
    fn on_hovered_file(&mut self, world: &mut World, path: &Path) {}
    fn on_hovered_file_cancelled(&mut self, world: &mut World) {}
    fn configure_render_graph(&mut self, graph: &mut RenderGraph<World>, device: &wgpu::Device, surface_format: wgpu::TextureFormat, resources: RenderResources) {}
    fn update_render_graph(&mut self, graph: &mut RenderGraph<World>, world: &World) {}
    fn pre_render(&mut self, renderer: &mut dyn Render, world: &mut World) {}
    fn next_state(&mut self, world: &mut World) -> Option<Box<dyn State>> { None }
    fn handle_mcp_command(&mut self, world: &mut World, command: &McpCommand) -> Option<McpResponse> { None }
    fn after_mcp_command(&mut self, world: &mut World, command: &McpCommand, response: &McpResponse) {}
}
}

Audio Analyzer (fft feature)

#![allow(unused)]
fn main() {
let mut analyzer = AudioAnalyzer::new();
analyzer.load_samples(samples, sample_rate);

analyzer.analyze_at_time(time_seconds);

analyzer.sub_bass
analyzer.bass
analyzer.low_mids
analyzer.mids
analyzer.high_mids
analyzer.highs

analyzer.smoothed_bass
analyzer.smoothed_mids

analyzer.onset_detected
analyzer.kick_decay
analyzer.snare_decay
analyzer.hat_decay

analyzer.estimated_bpm
analyzer.beat_phase
analyzer.beat_confidence

analyzer.is_building
analyzer.is_dropping
analyzer.is_breakdown
analyzer.build_intensity
analyzer.drop_intensity

analyzer.spectral_centroid
analyzer.spectral_flatness
analyzer.spectral_flux
analyzer.intensity
}

Effects Pass

#![allow(unused)]
fn main() {
use nightshade::render::wgpu::passes::postprocess::effects::*;

let effects_state = create_effects_state();

if let Ok(mut state) = effects_state.write() {
    state.uniforms.chromatic_aberration = 0.02;
    state.uniforms.vignette = 0.3;
    state.uniforms.glitch_intensity = 0.5;
    state.uniforms.wave_distortion = 0.2;
    state.uniforms.crt_scanlines = 0.3;
    state.uniforms.film_grain = 0.1;
    state.uniforms.hue_rotation = 0.5;
    state.uniforms.saturation = 1.2;
    state.uniforms.color_grade_mode = ColorGradeMode::Cyberpunk as f32;
    state.uniforms.raymarch_mode = RaymarchMode::Tunnel as f32;
    state.uniforms.raymarch_blend = 0.5;
    state.enabled = true;
}
}

Debug Lines

#![allow(unused)]
fn main() {
let lines_entity = world.spawn_entities(LOCAL_TRANSFORM | LINES, 1)[0];

world.core.set_lines(lines_entity, Lines {
    lines: vec![
        Line { start: Vec3::zeros(), end: Vec3::new(1.0, 0.0, 0.0), color: Vec4::new(1.0, 0.0, 0.0, 1.0) },
        Line { start: Vec3::zeros(), end: Vec3::new(0.0, 1.0, 0.0), color: Vec4::new(0.0, 1.0, 0.0, 1.0) },
        Line { start: Vec3::zeros(), end: Vec3::new(0.0, 0.0, 1.0), color: Vec4::new(0.0, 0.0, 1.0, 1.0) },
    ],
    version: 0,
});
}

World Commands

#![allow(unused)]
fn main() {
world.queue_command(WorldCommand::LoadTexture {
    name: "my_texture".to_string(),
    rgba_data: texture_bytes,
    width: 256,
    height: 256,
});

world.queue_command(WorldCommand::DespawnRecursive { entity });
world.queue_command(WorldCommand::LoadHdrSkybox { hdr_data });
world.queue_command(WorldCommand::CaptureScreenshot { path: None });

despawn_recursive_immediate(world, entity);
}

Running

fn main() -> Result<(), Box<dyn std::error::Error>> {
    nightshade::launch(MyGame::default())
}