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

@ridewolf/city-flythrough

v0.2.0

Published

A procedural city with living traffic on a 2D canvas: deterministic world generation, traffic lights, roundabouts, lane changes, and adaptive performance. Zero dependencies.

Readme


A camera drifts over an endless city. Roads have widths and speed limits; cars keep to their lanes, queue at red lights, yield into roundabouts, plan proper turning arcs, occasionally break down and jam a lane. Blocks are buildings, parks, and plazas. Clouds drift over; very rarely, a plane crosses. None of it is recorded or faked — it's a real micro-simulation over a world that is a pure function of coordinates, so it runs forever in a few kilobytes and never repeats.

Built as a lock-screen backdrop for a production mobility app; extracted because it turned out to be the fun kind of engineering worth sharing.

Quickstart

bun add @ridewolf/city-flythrough
import { createCityFlythrough } from '@ridewolf/city-flythrough';

const flythrough = createCityFlythrough(document.querySelector('canvas'), {
  theme: 'dark',      // or 'light'; switchable live via setTheme()
  minimal: false,     // true → lighter budgets for background use
});
flythrough.start();

Or run the bundled demo: bun run build && bunx serve .examples/demo.html.

What makes it interesting

  • Deterministic world — every road class, block, roundabout, and light phase is a hash of its grid coordinates. The camera can fly anywhere and come back; nothing is stored, nothing drifts.
  • Honest traffic — car following with queue compression, asymptotic braking to stop lines, roundabout yield arcs, lane-aware turning arcs that never cross the oncoming side, gap-checked lane changes, rare in-lane breakdowns.
  • Adaptive performance — a mount-time micro-benchmark scales entity budgets and the DPR cap to the device (0.25×–1.2×); a runtime guard sheds cars if thermals bite anyway; a frame cap stops 120 Hz panels from paying quadruple for a slow pan. prefers-reduced-motion renders a single static frame.
  • Testable by construction — all randomness flows through an injected RNG. The suite drives seeded simulations and asserts real invariants: lights are never green both ways, cars never overlap, roundabouts never trap anyone, a 3 600-step soak stays finite and lane-disciplined.

API

| Export | Purpose | | --- | --- | | createCityFlythrough(canvas, options) | The full backdrop: start / stop / setTheme / destroy, plus live sim and sky handles. | | TrafficSim, Sky | The simulation layers, usable headlessly (that's how the tests run them). | | renderFrame, PALETTE_DARK, PALETTE_LIGHT | The renderer and themes — bring your own loop or palette. | | roadInfo, lightGreen, hash, ... | The deterministic world functions, exported individually. | | measurePerfFactor, dprCapFor | The device benchmark, reusable for any canvas scene. | | agentDrawPos | Where a car is painted, in world coordinates — for overlays that have to agree with the renderer. |

Options: minimal, theme / palette, rng (deterministic scenes), respectReducedMotion, and onOverlay.

Drawing on top of the scene

onOverlay runs once per rendered frame, after the scene, with the context already in world coordinates — so agentDrawPos(car) lands where that car was drawn, with no viewport arithmetic:

createCityFlythrough(canvas, {
  onOverlay: (ctx, { dt, agents }) => {
    const car = agents[0];
    if (!car) return;
    const { px, py } = agentDrawPos(car);
    ctx.fillText('42 km/h', px, py - 14);
  },
});

The transform is translate-only, so text and line widths keep their pixel sizes. Anything that persists across frames should advance on dt and drop its subject once it leaves agents — the sim recycles cars that go off-screen, and a handle kept past that pins an overlay to a car the scene no longer draws.

Performance

Measured with mitata on an Apple M4, Bun 1.3 (bun run bench, seeded simulation, 1280×800 viewport):

| Cars on screen | sim.step | renderFrame (JS side) | | --- | --- | --- | | 40 | 5.5 µs | 74 µs | | 120 | 19.1 µs | 76 µs | | 300 | 54.9 µs | 94 µs |

Plus the world functions the camera leans on constantly: roadInfo ≈ 3.6 ns, hash ≈ 7.3 ns per call — cheap enough that nothing needs caching, which is why flying anywhere and coming back costs nothing and stores nothing.

Read these honestly. renderFrame here runs against a no-op context, so the table is our per-frame work, not the GPU's rasterization — on a real device fill rate dominates, and that is exactly what the DPR cap exists to control. Tripling the traffic multiplies the simulation cost by ten but barely moves the drawing cost, because the city itself (roads, blocks, trees) is most of the frame. Even at 300 cars the JS side of a frame is ~0.15 ms against a 16.7 ms budget at 60 Hz, so the adaptive budget is there for weak GPUs and thermal throttling, not for the maths.

Documentation

  • The simulation — the world hashing, the traffic model, and the three-layer performance envelope.

Why we built this

At Ridewolf the operator app needed a lock screen that felt alive without shipping video assets or burning batteries. A procedural city was the answer — and somewhere between "cars should stop at lights" and "entrants must yield to the ring", it quietly became a traffic simulation with opinions. It now doubles as our favourite demo of adaptive canvas performance.

Contributing

Contributions welcome — new block types, vehicle behaviours, and palettes especially. See the contributing guide. Run bun test, bun run lint, bun run typecheck before a PR. Security issues: SECURITY.md — never in a public issue.

License

MIT © Ridewolf