diff --git a/src/core/course.js b/src/core/course.js index e7f32b7..d23860c 100644 --- a/src/core/course.js +++ b/src/core/course.js @@ -163,7 +163,7 @@ export function createCourse({ seed = 1, difficultyRun = DIFFICULTY_RUN } = {}) const roll = rng(); if (roll < 0.18) runway(); else if (roll < 0.42) slalom(d); - else if (roll < 0.62) chasm(d); + else if (roll < 0.62) chasm(); else if (roll < 0.78) catwalk(d); else if (roll < 0.9) stack(d); else gauntlet(d); diff --git a/src/main.js b/src/main.js index d05e712..7e480e1 100644 --- a/src/main.js +++ b/src/main.js @@ -74,7 +74,9 @@ mute.addEventListener('click', (event) => { setMuted(!sound.muted); }); addEventListener('keydown', (event) => { - if (event.code === 'KeyM') setMuted(!sound.muted); + /** A held key repeats, and a mute that flips thirty times a second is a + * mute nobody can aim. */ + if (event.code === 'KeyM' && !event.repeat) setMuted(!sound.muted); }); /** diff --git a/src/render/props.js b/src/render/props.js index 4b9fa9e..deb5bab 100644 --- a/src/render/props.js +++ b/src/render/props.js @@ -76,9 +76,12 @@ export function createHazard() { wire(THEME.agent, 0.55), ); core.position.y = HAZARD.height / 2; - core.name = 'core'; group.add(core); + /** Handed over rather than looked up: the renderer turns this every frame + * for every agent in shot, and a search of the group is a search. */ + group.userData.core = core; + return group; } diff --git a/src/render/view.js b/src/render/view.js index 2f265b6..a9e1f93 100644 --- a/src/render/view.js +++ b/src/render/view.js @@ -89,7 +89,7 @@ export function createView({ scene, camera, studio }) { if (hazard.z > player.z + DRAW.ahead) break; const mesh = agents.take(); mesh.position.set(hazard.x, hazard.y, hazard.z); - mesh.getObjectByName('core').rotation.set(time * 0.9, time * 1.4, 0); + mesh.userData.core.rotation.set(time * 0.9, time * 1.4, 0); } agents.end(); diff --git a/src/ui/hud.js b/src/ui/hud.js index 1284d5d..540afec 100644 --- a/src/ui/hud.js +++ b/src/ui/hud.js @@ -5,8 +5,14 @@ const LEAD = { over: 'Connection terminated. The shell was never the problem.', }; +/** HTML-safe: every figure on this panel is one of our own numbers, but a + * panel that writes unescaped strings is a habit worth not having. */ +function safe(text) { + return String(text).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c])); +} + function stat(label, value) { - return `