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

star-canvas

v0.1.12

Published

Canvas game utilities for reliable game initialization - part of Star SDK.

Readme

Star Canvas

Essential DOM utilities for reliable game initialization.

star-canvas solves common bugs in web games: event listeners on null elements, canvas sizing issues, and frame-rate dependent speed. It provides a tiny (~1KB), zero-dependency toolkit with a mobile-first design.

This package is part of the Star SDK.

Features

  • Safe Initialization: Never crash from timing issues with onReady()
  • Delegated Events: Survive innerHTML re-renders with on()
  • Responsive Canvas: Auto-sizing with DPR handling via canvas()
  • Frame-Rate Independence: Delta time for consistent speed via loop()
  • Zero Dependencies: Pure vanilla JavaScript, SSR-safe
  • Tiny: <1KB gzipped

Install

yarn add star-canvas
# or
npm install star-canvas

Quick Start

UI Click Game

import { onReady, mount, on } from 'star-canvas';

onReady(() => {
  const root = mount('#game-root');
  let score = 0;

  function render() {
    root.innerHTML = `
      <div class="h-screen grid place-items-center bg-purple-900 text-white">
        <div class="text-center space-y-4">
          <h1 class="text-4xl font-bold">Score: ${score}</h1>
          <button id="clickBtn" class="px-8 py-4 rounded-xl bg-cyan-400 text-slate-900 font-bold">
            Click Me!
          </button>
        </div>
      </div>`;
  }

  // Delegated event - survives re-renders
  on(root, 'click', '#clickBtn', () => {
    score++;
    render();
  });

  render();
});

Canvas Game

import { onReady, mount, canvas, loop } from 'star-canvas';

onReady(() => {
  const root = mount('#game-root');

  root.innerHTML = `
    <div class="h-screen w-screen bg-slate-900">
      <!-- canvas auto-created here -->
    </div>`;

  const container = root.firstElementChild;
  const { ctx, canvas: c } = canvas(container, { pixelRatio: 'device' });

  const player = { x: 50, y: 50, vx: 200 }; // 200 px/sec

  loop((dt) => {
    // Delta time → same speed on all devices
    player.x += player.vx * dt;

    // Wrap around
    if (player.x > c.width) player.x = 0;

    // Render
    ctx.fillStyle = '#1e293b';
    ctx.fillRect(0, 0, c.width, c.height);

    ctx.fillStyle = '#22d3ee';
    ctx.fillRect(player.x, player.y, 32, 32);
  });
});

API

onReady(fn: () => void)

Run callback when DOM is ready. Works with all script loading patterns.

onReady(() => {
  // Safe to access DOM here
});

mount(selector?: string | Element): HTMLElement

Ensure a root element exists. Creates #game-root if missing.

const root = mount('#game-root'); // guaranteed non-null

on(root, type, selector, handler, options?)

Delegated event listener that survives re-renders.

on(root, 'click', '#button', () => {
  console.log('Clicked!');
});

// Later, safe to do:
root.innerHTML = '<button id="button">Click</button>';
// Event still works!

canvas(root, opts?): { canvas, ctx, resize }

Auto-sizing canvas with DPR handling.

const { canvas: c, ctx } = canvas(container, { pixelRatio: 'device' });
// Auto-resizes when container changes
// Handles retina displays automatically

loop(tick): { start, stop }

RAF loop with delta time for frame-rate independence.

const { stop } = loop((dt) => {
  player.x += speed * dt; // Same speed on 60Hz and 120Hz
});

// Later:
stop();

Why Star DOM?

Problem: Event Listeners on Null

// ❌ Breaks if script runs before DOM ready
const btn = document.getElementById('start');
btn.addEventListener('click', () => { /* ... */ }); // TypeError!
// ✅ Always works
import { onReady, mount, on } from 'star-canvas';

onReady(() => {
  const root = mount();
  on(root, 'click', '#start', () => { /* ... */ });
});

Problem: Canvas Doesn't Resize

// ❌ Fixed size, doesn't adapt
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
// ✅ Auto-sizes to container
const { canvas: c } = canvas(container);
// Resizes when sidebar appears/disappears
// Handles DPR for crisp rendering

Problem: Game Speed Varies by Device

// ❌ 2x faster on 120Hz displays
function gameLoop() {
  player.x += 5; // 300px/sec on 60Hz, 600px/sec on 120Hz
  requestAnimationFrame(gameLoop);
}
// ✅ Same speed everywhere
loop((dt) => {
  player.x += 300 * dt; // 300px/sec on ALL devices
});

License

MIT