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.
- No collider on the floor:
#![allow(unused)] fn main() { world.core.set_collider(floor, ColliderComponent::new_cuboid(50.0, 0.5, 50.0)); }
- 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); }
- 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
- 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); } } }
- The update is not being called:
#![allow(unused)] fn main() { fn run_systems(&mut self, world: &mut World) { update_animation_players(world, dt); } }
- The
AnimationPlayerlives 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
- No
AudioSourceentity 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()); }
- The
audiofeature is not enabled:
nightshade = { git = "...", features = ["engine", "wgpu", "audio"] }
- File format is unsupported. Use WAV, OGG, MP3, or FLAC.
Performance Issues
Low frame rate
- Entity count is high:
#![allow(unused)] fn main() { println!("Entities: {}", world.core.query_entities(RENDER_MESH).count()); }
- Disable expensive effects:
#![allow(unused)] fn main() { world.resources.graphics.ssao_enabled = false; world.resources.graphics.bloom_enabled = false; }
- Reduce shadow resolution:
#![allow(unused)] fn main() { world.resources.graphics.shadow_map_size = 1024; // Default is 2048 }
- 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
- Despawn entities you no longer need:
#![allow(unused)] fn main() { world.despawn_entities(&[entity]); }
- Drop unused textures:
#![allow(unused)] fn main() { world.resources.texture_cache.clear_unused(); }
- Use smaller textures on distant objects.
Stuttering or hitching
- 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) { // ... } }
- Move asset and prefab loading into
initializeso 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
-
Normal maps appear inverted. Some tools export Y-flipped normals. Check the export settings.
-
Wrong color space. Base color textures should be sRGB. Normal, metallic, and roughness textures should be linear.
-
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.enabledset inabout: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:
- Check the GitHub Issues
- Search for similar reports
- Open a new issue including:
- Nightshade version
- Platform (OS and GPU)
- The smallest code that reproduces the problem
- The error message or a screenshot