Learn

J! Code Academy

Making a Speedrun Timer

Hosted by Icoso

Create a speedrun timer UI that starts at the first checkpoint and stops at the finish. Build UI with J.uiElement, expose init/start/stop helpers, update every tick using world time, and integrate via checkpoint collisions.

Script

Hey everyone, and welcome to Episode 8 of Jamango Academy! Time is flying, so let’s build a speedrun timer for our obby. We’ll create UI text, start it at the first checkpoint, and stop it at the finish.

Initialize timer UI (timer.ts)#

Create a function to set up the UI, placing a text element we can update.

ts
import * as J from "jamango";

export let timerText: HTMLElement;
let startTime = 0;
let timerRunning = false;

export function initUI() {
  J.uiElement.innerHTML = `
    <div class="absolute size-full p-4 text-white">
      <p class="timer absolute left-12 text-5xl font-medium" style="top:120px;font-family:'Luckiest Guy'">⏲ 0:00</p>

Start and stop helpers#

Expose functions other scripts can call to control the timer.

ts
export function startTimer() {
  startTime = J.getWorldTime();
  timerRunning = true;
}

export function stopTimer() {
  timerRunning = false;
}

Update the display each tick#

Only update when the timer is running. Format as mm:ss with a leading zero for seconds.

ts
J.onGameTick((_, currentTime) => {
  if (timerRunning == false) return;

  const elapsedTime = currentTime - startTime;
  const minutes = Math.floor(elapsedTime / 60);
  const seconds = Math.floor(elapsedTime % 60);
  const formattedTime = `${minutes}:${seconds.toString().padStart(2, "0")}`;

  timerText.innerText = `⏰ ${formattedTime}`;
});

Hook into checkpoints#

Start at checkpoint 0 (the first jump), stop at the final checkpoint (e.g. 4).

ts
// respawn.ts
import * as TimerUI from "./timer";

J.onEntityCollisionStart(
  {
    source: [PlayerCheckpointTrait],
    target: [CheckpointTrait],
  },
  (sourceId, targetId) => {
    const checkpointTrait = J.getTrait(targetId, CheckpointTrait);

That’s it! You’ve got a clean, readable speedrun timer that updates every frame and integrates with your existing checkpoint system. Compete with friends and share your best times!