Skip to content

Fix/terrain smoothing and init time - #15

Open
Saishyam-master wants to merge 2 commits into
mainfrom
fix/terrain-smoothing-and-init-time
Open

Fix/terrain smoothing and init time#15
Saishyam-master wants to merge 2 commits into
mainfrom
fix/terrain-smoothing-and-init-time

Conversation

@Saishyam-master

@Saishyam-master Saishyam-master commented Jul 16, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added realistic terrain generation with mountains and improved terrain smoothing.
    • Introduced a dynamic minimap with contour lines, sea-level shading, aircraft tracking, and finish line indicator.
    • Added a visible 3D finish line flag in the environment.
    • Implemented a flight timer with on-screen display.
    • Introduced wind and turbulence effects influencing aircraft movement.
    • Added altitude-based fire effects and a detailed crash fire/smoke animation.
  • Enhancements

    • Increased aircraft maximum thrust and speed for more dynamic flight.
    • Improved robustness in aircraft loading and mesh handling.
    • Added control lockout when the aircraft is on fire or crashed.
  • Style

    • Added a new stylesheet for minimap appearance and layout.

…sim startup

- Implement smoothTerrain() to fix ReferenceError and enable terrain rendering
- Add robust mesh readiness checks before aircraft setup
- Prevent all undefined mesh/aircraft errors at startup and in animation loop
- Ensure project loads with no white screen or runtime errors
@coderabbitai

coderabbitai Bot commented Jul 16, 2025

Copy link
Copy Markdown

Walkthrough

The changes introduce a new external stylesheet for minimap UI, overhaul terrain and minimap generation with procedural mountains and smoothing, add a dynamic minimap display, implement a finish line flag, introduce wind and turbulence effects, add fire and crash visuals, and provide a flight timer. Control lockout, altitude-based effects, and increased aircraft thrust and speed are also included.

Changes

File(s) Change Summary
index.html Added external link to /style.css for styles.
style.css Added styles for minimap canvas: fixed position, size, border, shadow, and z-index.
src/controls.js Added control lockout mechanism to disable input when controlsLocked is true; added JSDoc for setupControls.
src/environment.js Overhauled terrain/minimap with procedural peaks, smoothing, minimap UI, finish flag, altitude/fire effects, and flight timer. Exported minimap and timer functions.
src/main.js Deferred aircraft loading until terrain/ocean ready, added wind/turbulence, integrated fire, crash, control lockout, and flight timer logic.
src/physics.js Doubled max thrust/speed; added exported emitCrashStream for fire/smoke effects at crash sites.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Aircraft
    participant Controls
    participant Environment
    participant Physics
    participant Minimap
    participant Timer

    User->Controls: Keyboard input
    Controls->Aircraft: Update controls (unless controlsLocked)
    loop Animation Frame
        Physics->Aircraft: Apply physics, wind, turbulence
        Aircraft->Environment: Check altitude (fire effect if too high)
        Aircraft->Minimap: Update minimap position/heading
        Aircraft->Timer: Start/stop/update timer (airborne/finish)
        alt Crash or fire
            Physics->Aircraft: emitCrashStream (fire/smoke effect)
            Controls->Aircraft: Lock controls
        end
    end
    Environment->Minimap: Redraw minimap if needed
Loading

Poem

A mountain rises, winds now blow,
The minimap glows with peaks below.
A flag awaits, the timer ticks,
Fire and smoke for daring tricks.
With thrust anew, we soar and spin—
Oh, what a flighty world we’re in!
— 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (4)
src/main.js (1)

129-129: Consider using optional chaining for cleaner code.

The static analysis correctly identifies opportunities to use optional chaining.

Apply optional chaining for more concise code:

-  if (aircraft && aircraft.airborne && !window.timerStarted) {
+  if (aircraft?.airborne && !window.timerStarted) {
-  if (aircraft && aircraft.position && aircraft.velocity) {
+  if (aircraft?.position && aircraft?.velocity) {

Also applies to: 146-146

src/environment.js (3)

74-86: Extract magic numbers as named constants for better maintainability.

The terrain generation uses several magic numbers that would benefit from being named constants. This improves code readability and makes future adjustments easier.

+// Terrain generation constants
+const BASE_FREQUENCY_SCALE = 0.5;
+const INITIAL_AMPLITUDE = 1.5;
+const FREQUENCY_MULTIPLIER = 1.7;
+const AMPLITUDE_DECAY = 0.55;
+const BASE_OCTAVES_ADDITION = 3;
+
 // Generate base elevation with layered noise
 const baseElevationFn = (x, y) => {
   let elevation = 0;
-  let frequency = scale * 0.5;
-  let amplitude = 1.5;
-  for (let o = 0; o < octaves + 3; o++) {
+  let frequency = scale * BASE_FREQUENCY_SCALE;
+  let amplitude = INITIAL_AMPLITUDE;
+  for (let o = 0; o < octaves + BASE_OCTAVES_ADDITION; o++) {
     elevation += noise.noise(x * frequency, y * frequency, 0) * amplitude;
-    frequency *= 1.7;
-    amplitude *= 0.55;
+    frequency *= FREQUENCY_MULTIPLIER;
+    amplitude *= AMPLITUDE_DECAY;
   }
   return elevation;
 };

89-118: Consider extracting mountain generation parameters as constants.

The mountain peak generation logic uses many hardcoded values that would be clearer as named constants.

+// Mountain generation parameters
+const MIN_PEAK_DISTANCE = 6000;
+const MAX_PEAK_ATTEMPTS = 200;
+const TARGET_PEAK_COUNT = 18;
+const PEAK_RADIUS_MIN = 8000;
+const PEAK_RADIUS_MAX = 20000;
+const PEAK_OFFSET_RANGE = 4000;
+const PEAK_HEIGHT_BASE = 2.0;
+const PEAK_HEIGHT_VARIATION = 1.2;
+const PEAK_RADIUS_BASE = 3500;
+const PEAK_RADIUS_VARIATION = 1200;
+
 // Generate dispersed mountain peaks with minimum distance
 const mountainPeaks = [];
-const minPeakDist = 6000;
 let attempts = 0;
-while (mountainPeaks.length < 18 && attempts < 200) {
+while (mountainPeaks.length < TARGET_PEAK_COUNT && attempts < MAX_PEAK_ATTEMPTS) {
   const angle = Math.random() * Math.PI * 2;
-  const radius = 8000 + Math.random() * 12000;
-  const px = Math.cos(angle) * radius + Math.random() * 4000;
-  const py = Math.sin(angle) * radius + Math.random() * 4000;
+  const radius = PEAK_RADIUS_MIN + Math.random() * (PEAK_RADIUS_MAX - PEAK_RADIUS_MIN);
+  const px = Math.cos(angle) * radius + Math.random() * PEAK_OFFSET_RANGE;
+  const py = Math.sin(angle) * radius + Math.random() * PEAK_OFFSET_RANGE;
   let tooClose = false;
   for (const p of mountainPeaks) {
     const d = Math.sqrt((px - p.x) ** 2 + (py - p.y) ** 2);
-    if (d < minPeakDist) {
+    if (d < MIN_PEAK_DISTANCE) {
       tooClose = true;
       break;
     }
@@ -106,8 +106,8 @@
       mountainPeaks.push({
         x: px,
         y: py,
-        height: 2.0 + Math.random() * 1.2, // Lowered peak height
-        radius: 3500 + Math.random() * 1200
+        height: PEAK_HEIGHT_BASE + Math.random() * PEAK_HEIGHT_VARIATION,
+        radius: PEAK_RADIUS_BASE + Math.random() * PEAK_RADIUS_VARIATION
       });
     }

410-426: Define the downward velocity as a constant.

The hardcoded velocity value of -100 should be extracted as a named constant for better maintainability and clarity.

 const ALTITUDE_LIMIT = 3200; // meters above sea level
+const FIRE_FALL_VELOCITY = -100; // m/s downward velocity when on fire
+
 export function checkAltitudeLimit(aircraft) {
   if (!aircraft || !aircraft.position) return;
   if (aircraft.position.y > ALTITUDE_LIMIT && !aircraft.isOnFire) {
     // Trigger fire effect
     aircraft.isOnFire = true;
     // Show fire sprite/overlay (implement in your render loop)
     // Disable controls (implement in controls.js)
     // Start falling
-    aircraft.velocity.y = -100;
+    aircraft.velocity.y = FIRE_FALL_VELOCITY;
     // Optionally play sound, etc.
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcbaa2a and 7807408.

📒 Files selected for processing (6)
  • index.html (1 hunks)
  • src/controls.js (4 hunks)
  • src/environment.js (3 hunks)
  • src/main.js (3 hunks)
  • src/physics.js (2 hunks)
  • style.css (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/environment.js (2)
src/physics.js (2)
  • i (592-592)
  • i (612-612)
src/main.js (3)
  • scene (13-13)
  • aircraft (46-46)
  • dx (135-135)
🪛 Biome (1.9.4)
src/main.js

[error] 129-129: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 146-146: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (8)
index.html (1)

8-8: LGTM!

The external stylesheet link is correctly placed and follows standard conventions for separating styles from HTML.

src/physics.js (1)

67-71: Performance parameters doubled.

The thrust and speed increases significantly enhance aircraft performance. Ensure these values are balanced with the game's difficulty and physics constraints.

style.css (1)

1-13: Well-structured minimap styles.

The CSS provides clean, functional styling for the minimap with appropriate positioning, sizing, and visual presentation.

src/controls.js (1)

3-6: Control lockout mechanism implemented correctly.

The lockout checks are properly placed to prevent all control inputs when the aircraft is in a locked state (fire/crash). The JSDoc addition improves code documentation.

Also applies to: 25-26, 55-56, 72-73

src/main.js (3)

34-44: Good implementation of mesh readiness polling.

The polling mechanism ensures both terrain and ocean meshes are ready before proceeding with aircraft initialization, preventing potential undefined reference errors.


52-60: Wind and turbulence effects add realism.

The wind system with steady direction and random turbulence provides good environmental dynamics. The implementation correctly scales the effects by delta time.

Also applies to: 186-201


104-126: Robust safety checks and fire effect integration.

The comprehensive property checks prevent runtime errors, and the fire effect trigger with control lockout provides good gameplay state management.

src/environment.js (1)

375-406: Well-implemented terrain smoothing function.

The smoothTerrain function is properly implemented with correct boundary handling and clear documentation. The averaging algorithm correctly processes the grid structure and preserves X/Y coordinates while only smoothing Z values.

Comment thread src/physics.js
Comment on lines +555 to +726
/**
* NEW: Emits a realistic fire + smoke effect at the given world position.
* @param {THREE.Vector3} position - World impact location.
*/
export function emitCrashStream(position) {
const group = new THREE.Group();
const fireCount = 120;
const smokeCount = 180;
let smokeSprites = [];

// Use the exact impact point as the center for all particles
const center = position.clone();
// Use a fixed bounding box around the impact point for coverage
const bbox = new THREE.Box3(
center.clone().addScalar(-6),
center.clone().addScalar(6)
);

// Helper to create a single particle
function createParticle(tex, size, color, opacity, pos, vel, fade, expand, animate) {
const mat = new THREE.SpriteMaterial({
map: tex,
color: color,
opacity: opacity,
transparent: true,
depthWrite: false,
blending: tex === FIRE_TEX ? THREE.AdditiveBlending : THREE.NormalBlending
});
const sprite = new THREE.Sprite(mat);
sprite.position.copy(pos);
sprite.scale.set(size, size, size);
sprite.userData = { vel, fade, expand, animate, baseSize: size, opacity };
group.add(sprite);
return sprite;
}

// Fire core (bright, small, fast, climbs up)
for (let i = 0; i < fireCount; i++) {
// Distribute within bounding box centered at impact
const pos = new THREE.Vector3(
THREE.MathUtils.lerp(bbox.min.x, bbox.max.x, Math.random()),
THREE.MathUtils.lerp(bbox.min.y, bbox.max.y, Math.random()),
THREE.MathUtils.lerp(bbox.min.z, bbox.max.z, Math.random())
);
const vel = new THREE.Vector3(
(Math.random() - 0.5) * 2,
Math.random() * 8 + 8,
(Math.random() - 0.5) * 2
);
const color = new THREE.Color().setHSL(0.08 + Math.random() * 0.06, 1, 0.5 + Math.random() * 0.2);
createParticle(
FIRE_TEX, 8 + Math.random() * 6, color, 1,
pos, vel, 2.2 + Math.random() * 0.7, 1.5 + Math.random(), true
);
}

// Fire glow (larger, orange, slower, climbs up)
for (let i = 0; i < fireCount / 2; i++) {
const pos = new THREE.Vector3(
THREE.MathUtils.lerp(bbox.min.x, bbox.max.x, Math.random()),
THREE.MathUtils.lerp(bbox.min.y, bbox.max.y, Math.random()),
THREE.MathUtils.lerp(bbox.min.z, bbox.max.z, Math.random())
);
const vel = new THREE.Vector3(
(Math.random() - 0.5) * 1.5,
Math.random() * 5 + 4,
(Math.random() - 0.5) * 1.5
);
const color = new THREE.Color().setHSL(0.07, 1, 0.35 + Math.random() * 0.1);
createParticle(
FIRE_TEX, 16 + Math.random() * 8, color, 0.8,
pos, vel, 2.8 + Math.random(), 2.5 + Math.random(), true
);
}

terrain.parent.add(group);

// Animate all particles
let time = 0;
function animateFire() {
time += 0.016;
for (let i = group.children.length - 1; i >= 0; i--) {
const sprite = group.children[i];
const ud = sprite.userData;
sprite.position.addScaledVector(ud.vel, 0.016);
ud.vel.y += 0.12 * 0.016;
ud.vel.x += (Math.random() - 0.5) * 0.02;
ud.vel.z += (Math.random() - 0.5) * 0.02;
sprite.scale.setScalar(ud.baseSize + ud.expand * time);
// Fade less aggressively
sprite.material.opacity = Math.max(0, ud.opacity * (1 - time / (ud.fade + 1.5)));
// Animate fire flicker
if (ud.animate && Math.random() < 0.2) {
sprite.material.color.offsetHSL(0, 0, (Math.random() - 0.5) * 0.1);
}
// Remove if faded
if (time > ud.fade + 1.5) {
group.remove(sprite);
}
}
if (group.children.length > 0) {
requestAnimationFrame(animateFire);
}
}
animateFire();

// After a short delay, add smoke
setTimeout(() => {
// Thick smoke (dark, slow, large, rises and drifts)
for (let i = 0; i < smokeCount; i++) {
const pos = new THREE.Vector3(
THREE.MathUtils.lerp(bbox.min.x, bbox.max.x, Math.random()),
THREE.MathUtils.lerp(bbox.min.y, bbox.max.y, Math.random()),
THREE.MathUtils.lerp(bbox.min.z, bbox.max.z, Math.random())
);
const vel = new THREE.Vector3(
(Math.random() - 0.5) * 1.2,
Math.random() * 4 + 2,
(Math.random() - 0.5) * 1.2
);
const color = new THREE.Color().setHSL(0, 0, 0.08 + Math.random() * 0.12);
smokeSprites.push(createParticle(
SMOKE_TEX, 18 + Math.random() * 12, color, 0.7 + Math.random() * 0.2,
pos, vel, 4.5 + Math.random() * 2, 3 + Math.random() * 2, false
));
}
// Light smoke (gray, very large, slow, fades out, rises and drifts)
for (let i = 0; i < smokeCount / 2; i++) {
const pos = new THREE.Vector3(
THREE.MathUtils.lerp(bbox.min.x, bbox.max.x, Math.random()),
THREE.MathUtils.lerp(bbox.min.y, bbox.max.y, Math.random()),
THREE.MathUtils.lerp(bbox.min.z, bbox.max.z, Math.random())
);
const vel = new THREE.Vector3(
(Math.random() - 0.5) * 0.8,
Math.random() * 2 + 1,
(Math.random() - 0.5) * 0.8
);
const color = new THREE.Color().setHSL(0, 0, 0.25 + Math.random() * 0.15);
smokeSprites.push(createParticle(
SMOKE_TEX, 32 + Math.random() * 16, color, 0.4 + Math.random() * 0.2,
pos, vel, 6 + Math.random() * 2, 4 + Math.random() * 2, false
));
}
// Animate smoke
let smokeTime = 0;
function animateSmoke() {
smokeTime += 0.016;
for (let i = smokeSprites.length - 1; i >= 0; i--) {
const sprite = smokeSprites[i];
const ud = sprite.userData;
sprite.position.addScaledVector(ud.vel, 0.016);
ud.vel.y += 0.12 * 0.016;
ud.vel.x += (Math.random() - 0.5) * 0.02;
ud.vel.z += (Math.random() - 0.5) * 0.02;
sprite.scale.setScalar(ud.baseSize + ud.expand * smokeTime);
// Fade less aggressively
sprite.material.opacity = Math.max(0, ud.opacity * (1 - smokeTime / (ud.fade + 2)));
if (smokeTime > ud.fade + 2) {
group.remove(sprite);
smokeSprites.splice(i, 1);
}
}
if (smokeSprites.length > 0) {
requestAnimationFrame(animateSmoke);
} else {
terrain.parent.remove(group);
}
}
animateSmoke();
}, 400); // 400ms delay before smoke appears
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical: Remove duplicate function definition and fix undefined variable.

The emitCrashStream function is already defined within setupPhysics (lines 84-251) with identical implementation. Additionally, this exported version references an undefined terrain variable at line 630, which will cause a runtime error.

Remove this duplicate function and instead, either:

  1. Move the function outside setupPhysics and pass terrain as a parameter, or
  2. Keep it inside setupPhysics and export a wrapper function

Here's the recommended fix:

-/**
- * NEW: Emits a realistic fire + smoke effect at the given world position.
- * @param {THREE.Vector3} position - World impact location.
- */
-export function emitCrashStream(position) {
-  const group = new THREE.Group();
-  // ... (entire function body)
-}

Instead, modify the function inside setupPhysics to make it accessible:

 export function setupPhysics(aircraft, onTakeoff, terrain, ocean, camera) {
   // ... existing code ...
   
-  function emitCrashStream(position) {
+  aircraft.emitCrashStream = function(position) {
     // ... existing implementation ...
   }

Then in main.js, use aircraft.emitCrashStream(position) instead of the imported function.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/physics.js between lines 555 and 726, there is a duplicate definition of
the emitCrashStream function which also references an undefined terrain variable
causing runtime errors. Remove this entire duplicate exported function. Instead,
keep the original emitCrashStream function inside setupPhysics (lines 84-251)
and modify it to accept terrain as a parameter or make it accessible via the
aircraft object. Then export a wrapper or access it through aircraft in main.js,
avoiding direct import of this duplicate function.

Comment thread src/main.js
Comment on lines +128 to +142
// --- NEW: Timer triggers ---
if (aircraft && aircraft.airborne && !window.timerStarted) {
startFlightTimer();
window.timerStarted = true;
}
// Stop timer if at finish line (simple proximity check)
if (aircraft && typeof mazeGoal !== 'undefined') {
const dx = aircraft.position.x - mazeGoal.x;
const dz = aircraft.position.z - mazeGoal.y;
if (Math.sqrt(dx*dx + dz*dz) < 200 && window.timerStarted) {
stopFlightTimer();
window.timerStarted = false;
}
}
updateFlightTimerDisplay(); // NEW: update timer display

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Missing imports and initialization for timer and finish line.

The code references mazeGoal (line 134) which is not defined or imported. Also, window.timerStarted should be properly initialized.

Add the missing import and initialization:

-import { setupEnvironment, terrainMesh, oceanMesh, checkAltitudeLimit, startFlightTimer, stopFlightTimer, updateFlightTimerDisplay } from './environment.js';
+import { setupEnvironment, terrainMesh, oceanMesh, checkAltitudeLimit, startFlightTimer, stopFlightTimer, updateFlightTimerDisplay, mazeGoal } from './environment.js';

And initialize the timer flag:

 let missionManager = null;
+window.timerStarted = false;

🏁 Script executed:

#!/bin/bash
# Check if mazeGoal is exported from environment.js
ast-grep --pattern 'export { $$$ mazeGoal $$$ }' src/environment.js || \
ast-grep --pattern 'export const mazeGoal' src/environment.js || \
ast_grep --pattern 'export let mazeGoal' src/environment.js

Length of output: 69


🏁 Script executed:

#!/bin/bash
# Search for mazeGoal references in src directory
rg -n 'mazeGoal' src/

# Search for timerStarted initialization or usage in src directory
rg -n 'timerStarted' src/

Length of output: 999


Define and Export mazeGoal & Initialize timerStarted

The code references mazeGoal but there’s no definition or export anywhere in the JS modules, and window.timerStarted is never initialized. You’ll need to:

• In src/environment.js – add a definition and export for your goal coordinates.

 // …existing code around line 299…
 // Place at mazeGoal (assume mazeGoal is defined globally)
 if (typeof mazeGoal !== 'undefined') {
   goalFlag.position.set(mazeGoal.x, 0, mazeGoal.y);
 }
+
+// Define and export the maze goal coordinates
+export const mazeGoal = { 
+  x: /* target X */, 
+  y: /* target Y */ 
+};

• In src/main.js – import mazeGoal at the top and explicitly initialize the timer flag before it’s used:

-import { setupEnvironment, terrainMesh, oceanMesh, checkAltitudeLimit,
-         startFlightTimer, stopFlightTimer, updateFlightTimerDisplay }
-  from './environment.js';
+import {
+  setupEnvironment,
+  terrainMesh,
+  oceanMesh,
+  checkAltitudeLimit,
+  startFlightTimer,
+  stopFlightTimer,
+  updateFlightTimerDisplay,
+  mazeGoal
+} from './environment.js';

let missionManager = null;
+// Initialize the flight timer flag
+window.timerStarted = false;

This ensures mazeGoal is available for proximity checks and that window.timerStarted starts in a defined state.

🧰 Tools
🪛 Biome (1.9.4)

[error] 129-129: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🤖 Prompt for AI Agents
In src/environment.js, define and export a constant for the goal coordinates
named mazeGoal with appropriate x and y values. In src/main.js, import mazeGoal
from src/environment.js at the top of the file. Also, before using
window.timerStarted in the timer logic (around lines 128-142), explicitly
initialize window.timerStarted to false to ensure it has a defined starting
state. This will make mazeGoal available for proximity checks and properly
initialize the timer flag.

Comment thread src/environment.js
Comment on lines +446 to +459
if (!document.getElementById('flight-timer')) {
timerDisplay = document.createElement('div');
timerDisplay.id = 'flight-timer';
timerDisplay.style.position = 'fixed';
timerDisplay.style.top = '24px';
timerDisplay.style.left = '50%';
timerDisplay.style.transform = 'translateX(-50%)';
timerDisplay.style.fontSize = '2em';
timerDisplay.style.fontWeight = 'bold';
timerDisplay.style.color = '#fff';
timerDisplay.style.textShadow = '0 0 8px #222';
timerDisplay.style.zIndex = '1000';
document.body.appendChild(timerDisplay);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Move DOM element creation into initialization function.

Creating DOM elements at module load time can cause issues in server-side rendering or testing environments. Consider moving this into an initialization function that's called when needed.

-// Add timer display to DOM
-if (!document.getElementById('flight-timer')) {
-  timerDisplay = document.createElement('div');
-  timerDisplay.id = 'flight-timer';
-  timerDisplay.style.position = 'fixed';
-  timerDisplay.style.top = '24px';
-  timerDisplay.style.left = '50%';
-  timerDisplay.style.transform = 'translateX(-50%)';
-  timerDisplay.style.fontSize = '2em';
-  timerDisplay.style.fontWeight = 'bold';
-  timerDisplay.style.color = '#fff';
-  timerDisplay.style.textShadow = '0 0 8px #222';
-  timerDisplay.style.zIndex = '1000';
-  document.body.appendChild(timerDisplay);
-}
+// Initialize timer display
+function initializeTimerDisplay() {
+  if (!timerDisplay && !document.getElementById('flight-timer')) {
+    timerDisplay = document.createElement('div');
+    timerDisplay.id = 'flight-timer';
+    timerDisplay.className = 'flight-timer'; // Use CSS class
+    document.body.appendChild(timerDisplay);
+  }
+}
+
+// Call this when starting the timer
+export function startFlightTimer() {
+  initializeTimerDisplay();
+  timerStartTime = performance.now();
+  timerRunning = true;
+}

Also add the corresponding CSS styles to your style.css file:

.flight-timer {
  position: fixed;
  top: 24px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 2em;
  font-weight: bold;
  color: #fff;
  text-shadow: 0 0 8px #222;
  z-index: 1000;
}
🤖 Prompt for AI Agents
In src/environment.js around lines 446 to 459, the creation and styling of the
flight-timer DOM element is done at module load time, which can cause issues in
server-side rendering or testing. Refactor this code by moving the DOM element
creation and appending logic into a dedicated initialization function that is
called only when needed. Additionally, remove the inline style assignments and
instead add the provided CSS styles for the flight-timer class to your style.css
file, then apply this class to the created element.

Comment thread src/environment.js
Comment on lines +314 to +320
minimapCtx.font = 'bold 24px sans-serif';
minimapCtx.fillStyle = '#ff2222';
minimapCtx.strokeStyle = '#fff';
minimapCtx.lineWidth = 2;
minimapCtx.fillText('🏁', flagPx, flagPy - 10);
minimapCtx.strokeText('🏁', flagPx, flagPy - 10);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace emoji with canvas-drawn flag for consistent rendering.

Using emoji (🏁) for the flag may render inconsistently across different browsers and operating systems. Consider drawing the flag using canvas primitives for consistent appearance.

-minimapCtx.font = 'bold 24px sans-serif';
-minimapCtx.fillStyle = '#ff2222';
-minimapCtx.strokeStyle = '#fff';
-minimapCtx.lineWidth = 2;
-minimapCtx.fillText('🏁', flagPx, flagPy - 10);
-minimapCtx.strokeText('🏁', flagPx, flagPy - 10);
+// Draw a flag icon using canvas primitives
+minimapCtx.save();
+// Flag pole
+minimapCtx.strokeStyle = '#333';
+minimapCtx.lineWidth = 2;
+minimapCtx.beginPath();
+minimapCtx.moveTo(flagPx, flagPy);
+minimapCtx.lineTo(flagPx, flagPy - 15);
+minimapCtx.stroke();
+// Flag
+minimapCtx.fillStyle = '#ff2222';
+minimapCtx.beginPath();
+minimapCtx.moveTo(flagPx, flagPy - 15);
+minimapCtx.lineTo(flagPx + 10, flagPy - 10);
+minimapCtx.lineTo(flagPx + 10, flagPy - 5);
+minimapCtx.lineTo(flagPx, flagPy - 10);
+minimapCtx.closePath();
+minimapCtx.fill();
+minimapCtx.restore();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
minimapCtx.font = 'bold 24px sans-serif';
minimapCtx.fillStyle = '#ff2222';
minimapCtx.strokeStyle = '#fff';
minimapCtx.lineWidth = 2;
minimapCtx.fillText('🏁', flagPx, flagPy - 10);
minimapCtx.strokeText('🏁', flagPx, flagPy - 10);
}
if (flagVisible) {
// Draw a flag icon using canvas primitives
minimapCtx.save();
// Flag pole
minimapCtx.strokeStyle = '#333';
minimapCtx.lineWidth = 2;
minimapCtx.beginPath();
minimapCtx.moveTo(flagPx, flagPy);
minimapCtx.lineTo(flagPx, flagPy - 15);
minimapCtx.stroke();
// Flag
minimapCtx.fillStyle = '#ff2222';
minimapCtx.beginPath();
minimapCtx.moveTo(flagPx, flagPy - 15);
minimapCtx.lineTo(flagPx + 10, flagPy - 10);
minimapCtx.lineTo(flagPx + 10, flagPy - 5);
minimapCtx.lineTo(flagPx, flagPy - 10);
minimapCtx.closePath();
minimapCtx.fill();
minimapCtx.restore();
}
🤖 Prompt for AI Agents
In src/environment.js around lines 314 to 320, replace the emoji flag drawn with
fillText and strokeText with a flag drawn using canvas drawing primitives like
fillRect, strokeRect, and path methods. This will ensure consistent rendering
across browsers by manually drawing the flag shape and colors instead of relying
on emoji rendering.

Comment thread src/environment.js
minimap.id = 'minimap-canvas';
minimap.width = minimapWidth;
minimap.height = minimapHeight;
minimap.className = 'minimap-canvas'; // Use CSS class only

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify minimap CSS class is defined in style.css.

The code references a CSS class minimap-canvas that should be defined in the external stylesheet mentioned in the PR summary.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the minimap-canvas CSS class is defined in style.css

# Search for the minimap-canvas class definition
rg -A 5 "\.minimap-canvas" "style.css" || rg -A 5 "\.minimap-canvas"

Length of output: 67


🏁 Script executed:

#!/bin/bash
# Locate any style.css files in the repo
fd -e css style.css

# Search all CSS files for the .minimap-canvas class definition
rg -n '\.minimap-canvas' -g '*.css'

Length of output: 69


Add missing .minimap-canvas CSS rule

It looks like the class minimap-canvas isn’t defined in your stylesheets, so the element will have no styling. Please add a corresponding rule in style.css (or the appropriate CSS file), for example:

/* style.css */
.minimap-canvas {
  /* e.g. */
  width: 100px;
  height: 50px;
  background: #eee;
  /* …other styles… */
}

• File to update: style.css (or your main CSS file)
• Location: alongside other minimap-related rules

🤖 Prompt for AI Agents
In src/environment.js at line 366, the class 'minimap-canvas' is assigned but
not defined in any CSS file. To fix this, add a '.minimap-canvas' CSS rule in
style.css (or the main CSS file) near other minimap-related styles. Include
properties like width, height, background color, and any other necessary styling
to ensure the minimap element is properly styled.

Comment thread src/environment.js
Comment on lines +300 to +302
if (typeof mazeGoal !== 'undefined') {
goalFlag.position.set(mazeGoal.x, 0, mazeGoal.y);
scene.add(goalFlag);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify mazeGoal is properly accessible in this scope.

The code checks if mazeGoal is defined but doesn't show where it comes from. Ensure it's properly imported or declared as a global variable.


🏁 Script executed:

#!/bin/bash
# Description: Verify where mazeGoal is defined and how it's made available to this module

# Search for mazeGoal definition or export
rg -B 2 -A 2 "mazeGoal\s*=" --type js

# Search for global declaration
rg "global.*mazeGoal|window.*mazeGoal" --type js

Length of output: 90


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of mazeGoal to locate its declaration or import
rg -n "mazeGoal" .

# Check for ES module imports of mazeGoal
rg -n "import.*mazeGoal" -t js -t ts

# Check for ES module exports of mazeGoal
rg -n "export.*mazeGoal" -t js -t ts

Length of output: 805


Ensure mazeGoal is defined or imported before use

I didn’t find any declaration, import, or window.mazeGoal assignment in the codebase, yet environment.js (lines 299–301) and main.js reference it as a free/global variable. This will lead to a runtime “undefined” error if mazeGoal isn’t injected externally.

Locations to address:

  • src/environment.js (lines 299–301):
    // Place at mazeGoal (assume mazeGoal is defined globally)
    if (typeof mazeGoal !== 'undefined') {
      goalFlag.position.set(mazeGoal.x, 0, mazeGoal.y);
      scene.add(goalFlag);
    }
  • src/main.js (lines 134–136) & 311–312: similar checks/use

Suggested fixes:

  • Explicitly import or pass mazeGoal into these modules.
  • Or, if it must be global, add at the very start of each file:
    const { mazeGoal } = window;
    and ensure window.mazeGoal is set before these scripts run.
  • Update documentation or initialization script to guarantee mazeGoal is defined on window.
🤖 Prompt for AI Agents
In src/environment.js around lines 299 to 301, mazeGoal is used as a global
variable without any declaration or import, which can cause runtime errors if it
is undefined. To fix this, explicitly import mazeGoal into the module if
possible, or at the start of the file add a line to assign mazeGoal from window
(e.g., const { mazeGoal } = window;) and ensure window.mazeGoal is set before
this script runs. Also apply similar fixes in src/main.js where mazeGoal is
used. Update any initialization or documentation to guarantee mazeGoal is
defined globally before usage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant