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

Troubleshooting

Things that go wrong and how to fix them.

Compilation Errors

"feature X is not enabled"

A feature you depend on is missing from Cargo.toml. Add it to the feature list:

nightshade = { git = "...", features = ["engine", "wgpu", "physics", "audio"] }

See Feature Flags for the full set.

"cannot find function spawn_cube_at"

The free function is in the prelude. Import it:

#![allow(unused)]
fn main() {
use nightshade::prelude::*;
}

"the trait State is not implemented"

Your game struct is missing one of the required State methods. The minimum is initialize and run_systems:

#![allow(unused)]
fn main() {
impl State for MyGame {
    fn initialize(&mut self, world: &mut World) {
        world.resources.window.title = "My Game".to_string();
    }
    fn run_systems(&mut self, world: &mut World) {}
}
}

"nalgebra_glm vs glam conflict"

The engine uses nalgebra_glm everywhere. Mixing in glam produces type mismatches:

#![allow(unused)]
fn main() {
// Correct
use nalgebra_glm::Vec3;

// Wrong, glam::Vec3 is a different type
use glam::Vec3;
}

Runtime Errors

"No suitable adapter found"

The GPU does not expose any backend wgpu can talk to.

Windows:

  • Update GPU drivers
  • Install the Vulkan Runtime from https://vulkan.lunarg.com/
  • Try forcing DX12 with WGPU_BACKEND=dx12 ./game.exe

Linux:

  • Install Vulkan drivers, for example sudo apt install mesa-vulkan-drivers
  • Verify with vulkaninfo

macOS:

  • macOS 10.13 or later is required for Metal
  • Check System Report > Graphics for Metal capability

"Entity not found"

You are reading or writing through a handle for an entity that was despawned or never existed. Check before using:

#![allow(unused)]
fn main() {
if world.has_entity(entity) {
    if let Some(transform) = world.core.get_local_transform(entity) {
        // Safe to use
    }
}
}

"Texture not found"

The path does not resolve to a file. Use relative paths under the asset directory rather than absolute paths:

#![allow(unused)]
fn main() {
import_gltf_from_path(std::path::Path::new("assets/models/character.glb"));  // Correct
import_gltf_from_path(std::path::Path::new("/home/user/game/assets/models/character.glb"));  // Avoid absolute paths
}

Physics objects fall through floor

A few common causes.

  1. No collider on the floor:
#![allow(unused)]
fn main() {
world.core.set_collider(floor, ColliderComponent::new_cuboid(50.0, 0.5, 50.0));
}
  1. Objects spawned overlapping the floor:
#![allow(unused)]
fn main() {
// Spawn above the floor, not at y=0
transform.translation = Vec3::new(0.0, 2.0, 0.0);
}
  1. High velocity causing tunneling between simulation steps:
#![allow(unused)]
fn main() {
let mut body = RigidBodyComponent::new_dynamic();
body.ccd_enabled = true;
world.core.set_rigid_body(entity, body);
}

Animation not playing

  1. Animation name does not match anything on the clip:
#![allow(unused)]
fn main() {
if let Some(player) = world.core.get_animation_player_mut(entity) {
    for name in player.available_animations() {
        println!("Animation: {}", name);
    }
}
}
  1. The update is not being called:
#![allow(unused)]
fn main() {
fn run_systems(&mut self, world: &mut World) {
    update_animation_players(world, dt);
}
}
  1. The AnimationPlayer lives on a child entity, not the model root:
#![allow(unused)]
fn main() {
for child in world.resources.children_cache.get(&model_root).cloned().unwrap_or_default() {
    if let Some(player) = world.core.get_animation_player_mut(child) {
        player.play("idle");
    }
}
}

No audio output

  1. No AudioSource entity has been spawned:
#![allow(unused)]
fn main() {
let sound = world.spawn_entities(AUDIO_SOURCE | LOCAL_TRANSFORM | GLOBAL_TRANSFORM, 1)[0];
world.core.set_audio_source(sound, AudioSource::new("shoot").playing());
}
  1. The audio feature is not enabled:
nightshade = { git = "...", features = ["engine", "wgpu", "audio"] }
  1. File format is unsupported. Use WAV, OGG, MP3, or FLAC.

Performance Issues

Low frame rate

  1. Entity count is high:
#![allow(unused)]
fn main() {
println!("Entities: {}", world.core.query_entities(RENDER_MESH).count());
}
  1. Disable expensive effects:
#![allow(unused)]
fn main() {
world.resources.graphics.ssao_enabled = false;
world.resources.graphics.bloom_enabled = false;
}
  1. Reduce shadow resolution:
#![allow(unused)]
fn main() {
world.resources.graphics.shadow_map_size = 1024; // Default is 2048
}
  1. Use a primitive collider instead of a trimesh:
#![allow(unused)]
fn main() {
world.core.set_collider(entity, ColliderComponent::new_cuboid(1.0, 1.0, 1.0));
}

Memory usage high

  1. Despawn entities you no longer need:
#![allow(unused)]
fn main() {
world.despawn_entities(&[entity]);
}
  1. Drop unused textures:
#![allow(unused)]
fn main() {
world.resources.texture_cache.clear_unused();
}
  1. Use smaller textures on distant objects.

Stuttering or hitching

  1. Per-frame allocations cause garbage and cache misses. Iterate directly rather than collecting:
#![allow(unused)]
fn main() {
// Bad, allocates every frame
let entities: Vec<Entity> = world.core.query_entities(LOCAL_TRANSFORM).collect();

// Good, iterates without allocation
for entity in world.core.query_entities(LOCAL_TRANSFORM) {
    // ...
}
}
  1. Move asset and prefab loading into initialize so the first frame already has everything ready:
#![allow(unused)]
fn main() {
fn initialize(&mut self, world: &mut World) {
    spawn_cube_at(world, Vec3::new(0.0, 1.0, 0.0));
}
}

Visual Issues

Objects are black

The scene has no lighting or the ambient term is zero:

#![allow(unused)]
fn main() {
spawn_sun(world);
world.resources.graphics.ambient_light = [0.1, 0.1, 0.1, 1.0];
}

Objects are too bright or washed out

Tonemapping or color grading is off. ACES is a good default:

#![allow(unused)]
fn main() {
world.resources.graphics.color_grading.tonemap_algorithm = TonemapAlgorithm::Aces;
world.resources.graphics.color_grading.brightness = 0.0;
}

Textures look wrong

  1. Normal maps appear inverted. Some tools export Y-flipped normals. Check the export settings.

  2. Wrong color space. Base color textures should be sRGB. Normal, metallic, and roughness textures should be linear.

  3. UV origin mismatch. glTF uses top-left UV origin. Models authored against a different convention may need a UV flip.

Z-fighting (flickering surfaces)

Two surfaces sit too close together for the depth buffer to separate them.

#![allow(unused)]
fn main() {
// Pull the near plane out
camera.near = 0.1;  // Instead of 0.01

// Or separate the surfaces along the conflict axis
floor_transform.translation.y = 0.0;
decal_transform.translation.y = 0.01;
}

WebAssembly Issues

"WebGPU not supported"

  • Use Chrome 113+ or Edge 113+
  • Firefox needs dom.webgpu.enabled set in about:config
  • Safari support is limited

Assets fail to load

WASM cannot read the filesystem directly. Assets have to be served over HTTP and fetched at runtime:

<script>
fetch('assets/model.glb')
    .then(response => response.arrayBuffer())
    .then(data => { /* use data */ });
</script>

Performance worse than native

This is normal. WebGPU and the JS bridge add overhead. Turn down quality settings for web builds:

#![allow(unused)]
fn main() {
#[cfg(target_arch = "wasm32")]
{
    world.resources.graphics.ssao_enabled = false;
    world.resources.graphics.shadow_map_size = 512;
}
}

Getting Help

If you are stuck on something not covered here:

  1. Check the GitHub Issues
  2. Search for similar reports
  3. Open a new issue including:
    • Nightshade version
    • Platform (OS and GPU)
    • The smallest code that reproduces the problem
    • The error message or a screenshot