npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@thi.ng/timestep

v1.0.47

Published

Deterministic fixed timestep simulation updates with state interpolation

Readme

@thi.ng/timestep

npm version npm downloads Mastodon Follow

[!NOTE] This is one of 211 standalone projects, maintained as part of the @thi.ng/umbrella monorepo and anti-framework.

🚀 Please help me to work full-time on these projects by sponsoring me on GitHub. Thank you! ❤️

About

Deterministic fixed timestep simulation updates with state interpolation.

For a more thorough description of both the problem and solution(s), please see Glenn Fiedler's article upon which this implementation is principally based on.

Managing fixed timestep updates

The package provides a configurable TimeStep class to manage the update logic. To participate in these managed updates, the user must provide state values/wrappers implementing the ITimeStep interface for the two main phases of the frame update:

  • integrate(dt: number, ctx: ReadonlyTimeStep): void: Depending on actual elapsed time and the configured timestep, this function might be called several times per update cycle to update the sim to its next desired state to:
    1. Backup the current state of the sim (at the beginning of that function call). This backup is required for the second phase of the update.
    2. Update the state to the desired next state using the provided timestep dt (ctx is only given for information).
  • interpolate(alpha: number, ctx: ReadonlyTimeStep): void: In this phase a previously backed up state should be linearly interpolated to the current state using the provided alpha tween factor and the result stored separately such that it can be used for subsequent rendering/display purposes.

In other words, this means any updatable state value will require 3 versions: previous, current (next), interpolated. Only the interpolated version is to be used for rendering (or other userland purposes). For that reason, the package also provides wrappers for numeric and vector-based (arbitrary length and optimized 2D/3D/4D versions) state variables, illustrated in the following short example:

import { defTimeStep, defNumeric, defVector2 } from "@thi.ng/timestep";
import { maddN2 } from "@thi.ng/vectors";

// initialize with default options (i.e. dt = 1/60 = 60 fps)
// start time is given in milliseconds but will be converted to seconds
// see: https://docs.thi.ng/umbrella/timestep/interfaces/TimestepOpts.html
const sim = defTimeStep({ dt: 1 / 60, startTime: Date.now() });

// define numeric state variable, increase using @ 10 units per second
const a = defNumeric(0, (x, dt) => x + dt * 10);

// define vector state variable, update by applying velocity of [-10, 20] (per second)
// also see thi.ng/vectors for hundreds of other useful vector operations...
// the update function MUST write its result in given vector (1st arg)
const b = defVector2([0, 0], (v, dt) => maddN2(v, [-10, 20], dt, v));

// even though the sim will update at a fixed (theoretical) 60 fps,
// the simulated render frame rate here is only 25 fps...
setInterval(() => {
    // provide current time and an array of state values to update
    // (any ITimeStep impl can be given here, incl. custom types)
    sim.update(Date.now(), [a, b]);
    // show current frame, num updates, time (relative to start) and interpolated state values
    console.log(sim.frame, sim.updates, sim.current, a.value, b.value);
}, 1000 / 25);

// 1   2   0.042 0.253  [ -0.253, 0.506 ]
// 2   4   0.082 0.663  [ -0.663, 1.326 ]
// 3   7   0.124 1.073  [ -1.073, 2.146 ]
// 4   9   0.164 1.483  [ -1.483, 2.966 ]
// 5   12  0.206 1.893  [ -1.893, 3.786 ]
// 6   14  0.246 2.293  [ -2.293, 4.586 ]
// 7   17  0.288 2.713  [ -2.713, 5.426 ]
// 8   19  0.328 3.123  [ -3.123, 6.246 ]
// 9   22  0.371 3.543  [ -3.543, 7.086 ]
// 10  24  0.411 3.953  [ -3.953, 7.906 ]
// 11  27  0.452 4.353  [ -4.353, 8.706 ]
// 12  29  0.493 4.773  [ -4.773, 9.546 ]
// 13  32  0.534 5.173  [ -5.173, 10.346 ]
// 14  34  0.575 5.593  [ -5.593, 11.186 ]
// 15  37  0.617 6.003  [ -6.003, 12.006 ]
// 16  39  0.659 6.423  [ -6.423, 12.846 ]
// 17  42  0.700 6.833  [ -6.833, 13.666 ]
// 18  44  0.740 7.233  [ -7.233, 14.466 ]
// 19  46  0.781 7.643  [ -7.643, 15.286 ]
// 20  49  0.822 8.053  [ -8.053, 16.106 ]
// 21  51  0.861 8.453  [ -8.453, 16.906 ]
// 22  54  0.904 8.873  [ -8.873, 17.746 ]
// 23  56  0.944 9.283  [ -9.283, 18.566 ]
// 24  59  0.986 9.703  [ -9.703, 19.406 ]
// 25  61  1.028 10.113 [ -10.113, 20.226 ]
// ...

Since the 25 fps render framerate is not a multiple of the 60 fps used by the sim, the output shows that for each render frame (1st column), there're either 2 or 3 sim updates performed (2nd column) to accommodate the 60 fps.

This should then also clarify why state interpolation is the final step of each update cycle: When multiple updates are performed in a single frame, the sim's state is technically ahead of the render time line and therefore we need to compute (interpolate) the correct state between previous and current, then use these interpolated values for rendering (in the abstract sense)...

The last row also shows that both a and b arrive at their expected values after 1 second (25 frames)...

Status

ALPHA - bleeding edge / work-in-progress

Search or submit any issues for this package

Related packages

  • @thi.ng/boids - n-dimensional boids simulation with modular behavior system

Installation

yarn add @thi.ng/timestep

ESM import:

import * as ts from "@thi.ng/timestep";

Browser ESM import:

<script type="module" src="https://esm.run/@thi.ng/timestep"></script>

JSDelivr documentation

For Node.js REPL:

const ts = await import("@thi.ng/timestep");

Package sizes (brotli'd, pre-treeshake): ESM: 1.02 KB

Dependencies

Note: @thi.ng/api is in most cases a type-only import (not used at runtime)

Usage examples

One project in this repo's /examples directory is using this package:

| Screenshot | Description | Live demo | Source | |:-------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------|:--------------------------------------------------|:-------------------------------------------------------------------------------| | | Basic 2D boid simulation and spatial indexing neighbor lookups | Demo | Source |

API

Generated API docs

TODO

Authors

If this project contributes to an academic publication, please cite it as:

@misc{thing-timestep,
  title = "@thi.ng/timestep",
  author = "Karsten Schmidt",
  note = "https://thi.ng/timestep",
  year = 2023
}

License

© 2023 - 2025 Karsten Schmidt // Apache License 2.0