Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/OmarMtya/enginejs-module/llms.txt

Use this file to discover all available pages before exploring further.

Engine.js drives all motion and physics through a requestAnimationFrame-based loop. Understanding how the loop starts, ticks, and stops — and what happens to your scene state along the way — lets you write predictable, glitch-free games.

How the loop works

When you call $g.Animar(), the engine runs IniciarAnimacion(), which first calls Inicializar() to prepare the scene, then snapshots the current figure list into Environment.backup and hands control to requestAnimationFrame.
$g.Animar()
  └─ IniciarAnimacion()
       ├─ Inicializar()           — overlap resolution + play 'inicial' sounds
       ├─ Environment.backup = … — deep clone of all figures
       └─ requestAnimationFrame(Step)
            └─ Step(timestamp)
                 ├─ Dibujar(false)
                 │    ├─ clear canvas
                 │    ├─ draw all figures
                 │    └─ calcularSiguientePaso()  — physics tick
                 └─ requestAnimationFrame(Step)   — schedule next frame
Every frame, Step calls Dibujar(false). Passing false means “draw and advance physics”. Passing true means “draw only” — the canvas is repainted without moving anything, which is ideal for rendering a static preview before the game starts.

The animando flag

The module-level animando variable is set to true the first time Dibujar runs and serves as a guard inside Dibujar itself. If you call Dibujar(false) directly before IniciarAnimacion() has been called, Inicializar() will run automatically on that first call. Once animando is true, subsequent calls to Dibujar(false) skip Inicializar().
The animando guard lives inside Dibujar, not in IniciarAnimacion. Calling $g.Animar() a second time while the loop is already running will invoke Inicializar() again and schedule an additional requestAnimationFrame loop. Avoid calling $g.Animar() more than once without first calling $g.DetenerAnimacion().

Initialization: Inicializar()

Before the first frame is painted, Inicializar() performs two jobs:
1

Overlap separation

A bubble-sort-style pass iterates all figures. If any two figures are already overlapping at scene start, the engine pushes the outer figure to the right along the X axis so they begin the simulation in a valid, non-intersecting state.
2

Play 'inicial' sounds

Any figure whose transform.sonido.activacion equals 'inicial' has its audio source played immediately, so ambient or background sounds begin as soon as the loop starts.

Frame counter: Environment.contador

Environment.contador increments by 1 on every call to Dibujar, regardless of whether physics are advancing. You can read this value at any point to implement time-based logic — for example, triggering an event after a fixed number of frames or measuring elapsed frames since a collision.
// Trigger something every 60 frames (~1 second at default FPS)
if ($g.contador % $g.FPS === 0) {
  console.log('One second elapsed');
}
Environment.FPS defaults to 60 and is used in the gravity acceleration formula inside afectarGravedad():
this.rigido.valor += (this.rigido.valor / (Environment.FPS * 100));
Changing FPS directly alters how quickly gravity accumulates each frame.

Static preview with Dibujar(true)

You can render the scene without starting physics by calling $g.Dibujar(true). This is useful for showing an initial game state while waiting for user input.
$g.InitCanvas(canvas, container);

const box = new $g.Figura({
  tipo: 'cuadrado',
  transform: new $g.Transform({ x: 100, y: 100, anchura: 80, altura: 80, relleno: '#4F46E5' }),
  rigido: new $g.Rigido(9.8)
});

$g.AgregarFigura(box);
$g.Dibujar(true); // Renders the scene once — no physics, no loop

Stopping the loop: DetenerAnimacion()

$g.DetenerAnimacion() cancels the pending requestAnimationFrame, restores every figure from Environment.backup, resets animando to false, and pauses any 'inicial' sounds.
$g.DetenerAnimacion();
// Environment.figuras is now a fresh copy of the original scene
Because backup is a deep clone taken at the moment Animar() was called, stopping and restarting the loop effectively resets the entire scene to its initial state.

Complete start / stop example

The snippet below wires up a canvas, adds a falling box, and lets the player start or stop the simulation with buttons.
<canvas id="gameCanvas"></canvas>
<div id="gameContainer" style="width:800px; height:600px;">
  <canvas id="gameCanvas"></canvas>
</div>
<button id="start">Start</button>
<button id="stop">Stop</button>

<script type="module">
  import '/path/to/enginejs-module/index.js';

  const canvas    = document.getElementById('gameCanvas');
  const container = document.getElementById('gameContainer');

  $g.InitCanvas(canvas, container);

  const floor = new $g.Figura({
    tipo: 'cuadrado',
    transform: new $g.Transform({ x: 0, y: 580, anchura: 800, altura: 20, relleno: '#334155' }),
    rigido: new $g.Rigido(0)
  });

  const ball = new $g.Figura({
    tipo: 'circulo',
    transform: new $g.Transform({ x: 400, y: 50, radio: 30, relleno: '#6366F1' }),
    rigido: new $g.Rigido(9.8)
  });

  $g.AgregarFigura(floor);
  $g.AgregarFigura(ball);

  document.getElementById('start').onclick = () => $g.Animar();
  document.getElementById('stop').onclick  = () => $g.DetenerAnimacion();
</script>
When Stop is clicked, the scene is fully restored — the ball reappears at y: 50 and is ready for another run the moment Start is pressed again.

Build docs developers (and LLMs) love