> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reskate.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Time

> reskate.time: the clock, timers that run a function once or again and again, and slow motion.

`reskate.time` reads a steady clock, runs functions later, and slows the game down. The clock and the timers need no permission; [slow motion](#slow-motion) needs `game.speed`.

Timers run in the game tick in which they fall due, just before the `tick` handlers. A timer is only as precise as the tick: a timer of 1 ms runs once a tick.

### `reskate.time.now()`

The time in milliseconds on a steady clock. It only goes forward, and it does not follow the wall clock: use it to measure how long something took, not to tell the date (`os.time` and `os.date` do that).

<ResponseField name="ms" type="number">Milliseconds, with fractions. Only differences between two readings mean anything.</ResponseField>

```lua theme={null}
local started = reskate.time.now()
-- ...
reskate.log(string.format("took %.1f ms", reskate.time.now() - started))
```

### `reskate.time.after(ms, fn)`

Runs `fn` once, `ms` milliseconds from now.

<ParamField path="ms" type="number" required>0 or more. 0 runs it at the next tick.</ParamField>
<ParamField path="fn" type="function" required>Called with no arguments.</ParamField>

<ResponseField name="id" type="integer">The timer's id, for `reskate.time.cancel`.</ResponseField>

```lua theme={null}
reskate.time.after(3000, function()
    reskate.log("three seconds later")
end)
```

### `reskate.time.every(ms, fn)`

Runs `fn` every `ms` milliseconds until you cancel it. Each next run is `ms` after the tick in which the last one ran.

<ParamField path="ms" type="number" required>1 or more.</ParamField>
<ParamField path="fn" type="function" required>Called with no arguments.</ParamField>

<ResponseField name="id" type="integer">The timer's id, for `reskate.time.cancel`.</ResponseField>

```lua theme={null}
local count = 0
local id
id = reskate.time.every(1000, function()
    count += 1
    reskate.log("second " .. count)
    if count == 10 then reskate.time.cancel(id) end
end)
```

### `reskate.time.cancel(id)`

Stops a timer. A timer that has already run once (`after`), or was cancelled already, is ignored.

<ParamField path="id" type="integer" required>What `after` or `every` returned.</ParamField>

```lua theme={null}
local warning = reskate.time.after(5000, function() reskate.log("too slow") end)
reskate.on("trick_landed", function() reskate.time.cancel(warning) end)
```

<Note>
  A wrong argument raises an error: a negative or non-finite `ms` for `after`, less than 1 for `every`, or a `fn` that is not a function. A plugin has at most 1024 timers waiting; the next one raises an error. Each timer call has 50 ms, like any handler. See [limits](/plugins/limits).
</Note>

## Slow motion

The game runs slower while any plugin asks for it: the slowest ask runs. It stays smooth: the game takes as many physics steps each real second as before, each the shorter. The clock and the timers above keep real time throughout, so `reskate.time.after(1000, fn)` still runs a second later.

Slow motion never runs in a multiplayer session, where your game must keep the other players' pace: asking in one is refused, and a session that starts while it runs ends it.

### `reskate.time.slow(speed)`

Asks for the game to run at `speed`.

<ParamField path="speed" type="number" default="1">0.05 to 1, of the game's own speed. 1 (or nothing) drops your ask.</ParamField>

<ResponseField name="ok" type="boolean">True when the ask was taken.</ResponseField>
<ResponseField name="why" type="string">`"never in a multiplayer session"` when `ok` is false.</ResponseField>

```lua theme={null}
-- Half speed for 2 s after a hard landing (board_landed needs events.skater).
reskate.on("board_landed", function(e)
    if e.down_speed < 8 then return end
    if reskate.time.slow(0.5) then
        reskate.time.after(2000, function() reskate.time.slow(1) end)
    end
end)
```

A `speed` outside 0.05 to 1 raises an error.

<Note>
  Needs the `game.speed` permission. A taken ask does not always slow the game: not when it already runs as slowly (the trainer's practice speed, for one), without a local skater, or once the game's speed is changed from elsewhere (the trainer, the console) during this slow motion. `reskate.time.speed()` says what runs. When the plugin stops, its ask is dropped.
</Note>

### `reskate.time.speed()`

The speed the game runs at for plugins now.

<ResponseField name="speed" type="number">The slowest plugin's ask while slow motion runs, else 1.</ResponseField>

```lua theme={null}
reskate.on("draw", function(d) -- needs overlay
    local speed = reskate.time.speed()
    if speed < 1 then
        d:text(vector.create(40, 40, 0), string.format("SLOW x%.2f", speed), {size = 24})
    end
end)
```

<Note>Needs the `game.speed` permission.</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.