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

ascii-city

v0.3.1

Published

An INFINITE seeded ASCII cyberpunk city you can walk around and drive in, right in your terminal (or browser). GTA before GTA 6, in glyphs.

Readme

ascii-city

A walkable — and drivable — ASCII cyberpunk city. By default it's an ambient stroll: traffic cruises the avenues, pedestrians wander the sidewalks, and you can hop into any car (E) just to drive around. Set engine.game: true in js/config.js for GTA mode: missions, money, wanted stars, and cops. Three layers:

  • The basejs/citygen.js, a seeded city generator: spec in, deterministic city model out. Pure data, no rendering, strictly printable ASCII (0x20–0x7E). The city is INFINITE: roads sit on a jittered lattice and every block is a pure function of (seed, coordinates), so generateRegion() can materialize any window of it; js/world.js slides a 160×160 window around the player (regen ~3ms, bit-identical overlap, so recentring is invisible).
  • The simjs/sim.js, the shared gameplay core: player (on foot or driving), civilian traffic, pedestrians, police + wanted stars, delivery missions + money, radio stations, and BFS GPS routing.
  • The renderersjs/walker.js (browser) and js/tui.js (terminal), the same first-person raycaster drawing the same sim as glyphs.

js/config.js is the single input: city goes straight into generateCity(), engine tunes the renderer. City specs land there.

Run — browser

python3 serve.py 8670

http://localhost:8670 — click to walk. WASD move, mouse look, shift run, F or left-click shoots, E enters/exits cars, V toggles third person, M minimap, N new seed, 1-4 glyph size. Police respond to crimes by default (engine.police: false for a peaceful city; engine.missions: true adds deliveries and money).

Run — terminal

npx . # from the repo, or: npm i -g . && ascii-city

Same city, same raycaster, rendered as ANSI truecolor cells. V toggles a third-person chase cam, F fires (hold in kitty terminals), E jacks cars, and the HUD shows a speedometer while driving. In terminals with the kitty keyboard protocol (iTerm2, Ghostty, kitty, WezTerm) you get real hold-to-move: hold WASD, shift to run, hold arrows or drag the mouse to look. Elsewhere (e.g. Terminal.app, which never reports key releases) it falls back to latched movement: w walks and keeps going, s stops then reverses, space stops, a/d/arrows turn in eased steps, r toggles run. n new city, q quits, either way. Flags: --seed, --palette neon|terminal|amber|rust|ice, --size WxD, --fov, --dist, and --frame to print a single frame and exit. Needs Node 18+ and a truecolor terminal. js/tui.js mirrors js/walker.js — change the projection or ramps in one, mirror it in the other.

The generator

import { generateCity } from './js/citygen.js';
const model = generateCity({ seed: 'ghost-harbor-412', size: { width: 200, depth: 160 } });

Any subset of DEFAULT_CONFIG (see js/citygen.js) can be passed: road spacing/widths/jitter, per-district weight/centerBias/heights/parcels/window style/wall glyph (custom district types are kept), building tiers and antennas, plazas, trees, every glyph. Each stage pulls from its own named RNG stream and per-cell effects are coordinate hashes, so changing one parameter never reshuffles unrelated parts of the city.

Model output: cells (road/sidewalk/building/park/plaza/tree), roadAxis (lane markings), heightMap (per-cell height — what the raycaster marches), bIndex (cell → building), buildings (footprint, tiers, district, window style), plus blocks/trees/fountains/stats.

The walker

Per screen column: DDA front-to-back through the grid. Each cell contributes a wall face and a top-surface strip, clipped against yCur (lowest unpainted row) so occlusion is free. Window lattices are per-building coordinate hashes — stable across frames. Distance fog is quantized so the glyph atlas stays small.

Debug page

http://localhost:8670/debug.html — slider playground over the generator (plan view + skyline probe). Diagnostic tool only, not the product.

Roadmap

  • traffic + pedestrians (roads/sidewalks already in the model)
  • interiors, lifts, elevation
  • signs, rain, audio