---
title: clock
description: The frame clock of a gpu: elapsed time, last delta, frame count, and the manual `advance()` that lets an external ticker own the clock. Use it whenever a shader, a camera or a simulation needs time; use `advance()` when something else already owns the timeline (GSAP/Motion, an XR frame callback, a fixed-timestep loop, a deterministic replay).
---

# clock



## Import

```ts
import { clock } from "vgpu";
```

## Signature

```ts
import type { Gpu } from "vgpu";

interface Clock {
  readonly time: number;
  readonly deltaTime: number;
  readonly frameCount: number;
  advance(dtSeconds: number): void;
}

declare function clock(gpu: Gpu): Clock;
```

## Parameters

| Param             | Type     | Required | Default | Notes                                                                                                                                            |
| ----------------- | -------- | -------: | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| gpu               | `Gpu`    |        ✔ | —       | The context returned by `init()`. One clock per gpu: `clock(gpu) === clock(gpu)`.                                                                |
| advance.dtSeconds | `number` |        ✔ | —       | Seconds to move the clock forward, finite and `>= 0`. Scale it for a timescale (`dt * 0.5`), or pass a constant for a fixed timestep (`1 / 60`). |

| Property   | Type     | Default | Notes                                                                                                                                |
| ---------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| time       | `number` | `0`     | Seconds since the first frame. Advances once per frame: with the wall-clock delta, or with the value the last `advance()` was given. |
| deltaTime  | `number` | `0`     | Seconds between the last two ticks. Exactly the argument of the last `advance()` when driving the clock manually.                    |
| frameCount | `number` | `0`     | Frames opened by `frame(gpu)` / `frameLoop(gpu)`. `advance()` never counts a frame.                                                  |

**Returns:** `Clock` — a live view of this gpu's frame clock. It reads through to the clock, so a single instance can be captured outside the loop and read inside it.

**Throws:** `VGPU-GPU-DISPOSED` when `clock(gpu)` runs after `gpu.dispose()` — read the clock before disposing, or `init()` a new gpu; `VGPU-GPU-FOREIGN` when the argument was not created by `init()`; `VGPU-CLOCK-DELTA-INVALID` when `advance()` receives a value that is not a finite, non-negative number — pass elapsed seconds, e.g. `advance(1 / 60)`.

## Examples

```ts
import { init, clock, effect, frameLoop, surface } from "vgpu";

declare const canvas: HTMLCanvasElement;

const gpu = await init();
const canvasSurface = surface(gpu, canvas);
const wave = effect(gpu, `
  struct Params { time: f32 }
  @group(0) @binding(0) var<uniform> params: Params;
  @fragment fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
    return vec4f(uv, sin(params.time) * 0.5 + 0.5, 1.0);
  }
`, { set: { params: { time: 0 } } });

// Automatic: every frame advances the clock with the wall-clock delta.
const time = clock(gpu);
frameLoop(gpu, (frame) => {
  wave.set({ params: { time: time.time } });
  frame.pass(canvasSurface, wave);
});
```

```ts
import { init, clock, effect, frame, target } from "vgpu/mock";

const gpu = await init();
const scene = target(gpu, { size: [64, 64] });
const shader = effect(gpu, `@fragment fn fs_main() -> @location(0) vec4f { return vec4f(1); }`);

// Manual: a fixed timestep makes the render deterministic, run after run.
const time = clock(gpu);
for (let step = 0; step < 120; step++) {
  time.advance(1 / 60);
  frame(gpu, (currentFrame) => currentFrame.pass(scene, shader));
}
console.log(time.time, time.frameCount); // 2, 120
```

```ts
import { init, clock, frameLoop } from "vgpu/mock";

const gpu = await init();
const time = clock(gpu);

// Timescale: the same wall clock, played at half speed. Slow motion is one multiplication.
let previousMs = performance.now();
const timescale = 0.5;
frameLoop(gpu, () => {
  const nowMs = performance.now();
  time.advance(((nowMs - previousMs) / 1000) * timescale);
  previousMs = nowMs;
});
```

## Notes

* One tick per frame, manual first: `frame()` advances the clock with wall-clock time **unless** `advance()` already ran since the last frame. Calling `advance(dt)` and then `frame()` in the same tick advances exactly once, by `dt`.
* `advance()` moves `time` and `deltaTime` immediately, before any frame opens — so code that reads the clock outside a frame (input smoothing, physics substeps) sees the value it is about to render with.
* Mixing is allowed and useful: drive the clock manually while an external ticker runs, then drop back to plain `frame(gpu)` calls and the wall clock takes over again, measured from the last tick.
* The clock is not a global. It belongs to the gpu, and it is created lazily: a program that never opens a frame and never calls `clock(gpu)` never allocates it.
* There is no clock on `Frame`. Pass `clock(gpu)` (or the numbers you read from it) into render helpers instead of reaching for frame state.
* **See also:** `frame`, `frameLoop`, `Gpu`, and the guide *Driving vgpu with an external ticker*.


---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)