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 🙏

© 2026 – Pkg Stats / Ryan Hefner

simple-gameloop

v3.1.0

Published

A simple library for running update and render functions with controls.

Readme

Simple Gameloop

A small library for running code with separated update and render functions with RequestAnimationFrame. The Update function can be paused, resumed, or run at customisable rates by passing in a number to multiply the RAF delta by (slow-motion, double speed etc.).

Principles

Separation of Concerns

This library exposes separate update and render functions to encourage separation of game state logic and rendering logic. Where entities in your animation or game are and how they are rendered are separate concerns, so by separating the code into different functions we can avoid coupling them unnecessarily.

Framerate-independent State Updates

The update function is called from inside requestAnimationFrame, but we do not want the update rate to be tied to the render rate. An animation should run at the same rate whether viewed on a 30hz monitor or a 244hz monitor.

To ensure consistent animation regardless of render speed the update function is passed a dt parameter that represents the time in seconds since the last time the update function was called. Any calculations that result in something moving should be multiplied by this value to guarantee that it will move that far per second.

Let's say you want a square to move right at 100 pixels per second. If you assume 60fps you divide 1000 by 60 to get 16.6, so you write

function update() {
  box.x += 16.6;
}

On a computer with a 60hz monitor you'll see the behaviour you're expecting, maybe with a little hitching but eh that's fine. Then you view it on a 144hz monitor and your square has gone zooming off the screen because it's add 16. 6 pixels to it 144 times a second instead of 60.

So what you do instead is you define all of your units in units per second and multiply that by the time since the last update!

function update(deltaTime) {
  box.x += 100 * deltaTime;
}

On a 60hz monitor deltaTime will be 0.166 and 100 * 0.166 = 16.6 pixels per update. On a 144hz monitor deltaTime will be 0.024, bringing us 2.4 pixels per update.

The delta time is calculated every frame so if your browser runs one frame slower than the others for whatever reason the dt will change appropriately and everything should remain consistent. This also holds for the browser being unable to keep up with the max refresh rate - if you create 1,000,000 boxes your animation will likely run at far fewer frames per second but the box movement will continue at the same rate.

To Use

import * as simpleGameloop from 'simple-gameloop';

/**
 * @param dt - time in seconds since last call to update function
 */
const update = function update(dt) {
  // your update logic here
};

const render = function render() {
  // your render logic here
};

const gameLoop: GameLoop = simpleGameloop.createLoop({
  update,
  render,
});

createLoop returns an object with the following functions:

  • pause() - blocks the update function
  • play() - unblocks the update function
  • destroy() - cancels the current animation frame, halting playback completely
  • setSpeed(number) - speed up or slow down the update call by multiplying the delta by the given number

Create Canvas

There is also a helper function for creating a canvas element of a given size.

const canvasObject = simpleGameloop.createCanvas({
    containerSelector: '.canvasContainer',
    classes: 'canvas other-class',
    width: 500,
    height: 500,
});

This will create a 500x500 canvas inside the .canvasContainer element with the classes canvas and other-class.

canvasObject contains references to:

  • canvas the canvas element
  • context the canvas context (e.g. canvas.getContext('2d')).

Demo

There is a demo that you can run with npm run example.

Future

Fixed-rate Updates

If you want your simulation to be deterministic then you want a fixed update rate. This can be done by tracking how much time has progressed and calling update when X time has passed, passing X in as the delta.