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

@pleasantmachines/kento-attention

v0.1.0

Published

What a player is told, in what order, and what each distance shows. A game produces more events than anyone can take in, and the event that matters is not the loudest. This package holds the model that decides, so a game's alarm, voice, pings, on-screen l

Readme

@kento/attention

What a player is told, in what order, and what each distance shows. A game produces more events than anyone can take in, and the event that matters is not the loudest. This package holds the model that decides, so a game's alarm, voice, pings, on-screen list and camera jump all read one ranking instead of each keeping its own rate limit. It knows no game: what a class of event means, what a viewer may know and what a channel does are the game's. src/index.ts is the public entry.

Contract

Pure, with no renderer and no audio (its own boundaries.mjs island): it imports only itself. It keeps no simulation state and takes time from its caller, so it is presentation, off any hash. The same calls give the same results, but it uses Math.exp and Math.hypot: do not let a simulation read it.

| Export | What it is | | --- | --- | | createAttention({ classes, channels, knows, ... }) | The director, below | | AttentionClass | id, severity (0..100), urgency (what being new or getting worse adds), group (classes of one group at one place are one situation, at the worst's severity), radius, linger, channels (per channel a lowest score, or false for never) | | AttentionChannel | id, min, gap (between any two raises), again (between two raises for one situation), unseenOnly (default true: what is on the screen needs no telling), pierce (a score this far over its last raise goes through the gap) | | .signal({ kind, x, z, weight?, detail? }) | One thing that happened. knows decides, once, and a refused signal is gone. Returns whether it was taken | | .frame({ t, inView, stake? }) | Merges the signals since the last frame and returns { ranked, raised }: every situation best first, and what each channel may say this frame, at most one a channel. A clock that went back (a rewind) forgets everything | | .acknowledge(id) | The player went to look: a jump, a click on its line | | .counts() | withheld (refused by knows), ignored (no such class), live | | scoreOf(terms) | A score from its ScoreTerms, held to 0..100 | | createZoomBands(bands, { hysteresis, fade }) | band(distance), a named band that does not flicker on its line; weight(id, distance), a cross-fade whose two sides sum to one | | clusterPoints(points, { reach, least }) | Points of one group chained within reach: { group, x, z, r, members }, in the input's order, linear in the points |

The score

A situation's score is the sum of named terms, held to 0..100, and Situation.terms keeps them, so "why is this first" has a plain answer:

  • severity: the worst class seen in it.
  • worsening: the class's urgency times how far its recent rate (2 s) runs ahead of its slower one (10 s). New is worst; a steady fight comes to nothing with no repetition rule of its own.
  • stake: whatever the game's stake(situation) says the director cannot know, such as whether anyone is defending it.
  • watched: taken off while it is on the screen.
  • acknowledged: taken off once the player has looked (a jump, or lookedAfter seconds on the screen), until its recent rate doubles.
  • fading: half of the positive terms go, over its linger, after its last signal.

Invariants

  • A signal knows refused cannot rank or be said, whatever its severity. knows is required, so no caller gets a director without saying what its viewer may know. A designer withholding a warning uses the class's channels: { x: false } or knows.
  • Fifty hits at one place are one situation and one raise. A worse class in the same situation does not wait for again; it still waits for the channel's gap, unless it pierces it.
  • At most most live (default 24): the least important ends when another begins. Ordering is fixed: score, then age, then id.

Known gaps

It ranks by what it is told. It does not measure comprehension: whether a player understands a situation is a question for people.