Debugging Guide
Open the editor to debug issues live.
Common Errors
"No entry file found"
The project needs exactly one entry file. The default is main.js (shown with an entry badge). You cannot change entry in the UI — put your return in that file.
"Module 'xxx' not found"
Import specifier must match a file name in the explorer (with or without .js):
import { helper } from './utils'; // needs utils or utils.js"Circular import detected"
A imports B and B (directly or indirectly) imports A. Extract shared code into a third leaf module.
Syntax errors / "Unexpected token"
Typical causes:
- Missing
}or) - Default or namespace imports (only named imports are supported)
- Multiline
import { ... }(keep on one line) - Top-level
await
Named import { ... } from './file' is allowed in the entry file.
"xxx is not defined"
Only time, dt, state, w, h, and your imports exist in the entry. Modules do not see frame globals — pass them as arguments.
// BUG
return { particles: [{ x: x, y: 100 }] };
// FIX
const x = 100;
return { particles: [{ x, y: 100 }] };"Cannot read property of undefined"
Missing init:
if (!state.init) {
state.particles = [];
state.init = true;
}
state.particles.push({ x: 100, y: 100 });Simulation Behavior
Particle stays still
Position overwritten every frame, or using let instead of state:
state.x = (state.x ?? 100) + 50 * dt;Particle teleports
Forgot dt:
state.x += 50 * dt; // not state.x += 50Jump after tab switch
dt is clamped to 50ms. If you still see jumps, check for custom time accumulation that ignores the clamp.
Nothing renders
You must return a FrameResult. While paused, the host stops the frame callback — expect a cleared canvas with grid/axes only.
Edits reset the sim
Recompile (~400ms after typing stops) clears state and time. That is intentional. Use Pause to freeze without clearing; Restart to clear without changing code.
Click does nothing
if (state.clickX !== undefined) {
// handle
state.clickX = undefined;
state.clickY = undefined;
}Avoid truthy checks alone if 0 could be a valid coordinate (rare, but !== undefined is safer).
Performance
- Cap primitive counts (see Performance Guidelines).
- Bound trail / particle arrays.
- Prefer squared distances in hot loops:
const perceptionSq = r * r;
const distSq = dx * dx + dy * dy;
if (distSq < perceptionSq) { /* ... */ }- Show frame cost in the HUD:
return { text: { dt: (dt * 1000).toFixed(1) + 'ms' } };Consistently > 16ms means the frame is overloaded.
Editor Issues
Code doesn't update
Wait for the 400ms debounce after typing.
Error won't clear
Fix the code, or click Restart. Persistent errors are real compile/runtime failures.
Red squiggles in Monaco
TypeScript does not know about injected globals. Squiggles are usually false positives. Add // @ts-nocheck at the top if they distract you.
Restart vs Reset
| Restart | Reset | |
|---|---|---|
| Code | Kept | Restored to starter main.js |
state / time | Cleared | Cleared |