Skip to Content
Modlock

Timers

Run code later, on a beat or as a sequence of steps.

A timer calls your function at a time on the game's clock, so you never count frames yourself.

CallRuns the callback
after(seconds, fn)Once, seconds of game time from now.
every(seconds, fn)Every seconds. A late frame does not shift the runs after it.
sequence(fn)On the next frame, then after each wait the callback returns. The callback receives how many times it has run, and returns the seconds to wait or nothing to stop.
import { after, every, log, sequence } from 'modlock'

const heartbeat = every(1, () => log('tick'))
after(10, () => heartbeat.cancel())

// Three steps, two seconds apart.
sequence((run) => {
  log(`Step ${run}`)
  return run < 3 ? 2 : undefined
})
local heartbeat = modlock.every(1, function()
	modlock.log("tick")
end)
modlock.after(10, function()
	heartbeat:cancel()
end)

-- Three steps, two seconds apart.
modlock.sequence(function(run)
	modlock.log(`Step {run}`)
	return if run < 3 then 2 else nil
end)
heartbeat = modlock.every(1, lambda: modlock.log("tick"))
modlock.after(10, heartbeat.cancel)


# Three steps, two seconds apart.
def step(run: int) -> float | None:
    modlock.log(f"Step {run}")
    return 2 if run < 3 else None


modlock.sequence(step)
heartbeat := mod.Every(time.Second, func() { mod.Log("tick") })
mod.After(10*time.Second, heartbeat.Cancel)

// Three steps, two seconds apart.
mod.Sequence(func(run int) (time.Duration, bool) {
	mod.Log("Step", run)
	return 2 * time.Second, run < 3
})

How timers behave

Each call returns a timer with finished and cancel().

  • Timers count the game's clock, so pausing the game pauses them. They keep running across a map change.
  • The frame rate sets a timer's precision: it runs on the first frame at or after its time, and at most once per frame. A repeating timer that falls behind skips the runs it missed.
  • Timers due on one frame run in the order they came due.
  • A timer made inside a callback first runs on the next frame.
  • A callback that throws ends only its own timer and logs timer failed.

In Go, the timers take a time.Duration, and a sequence callback returns the wait and whether to run again.

On this page