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

wavefm

v0.2.0

Published

WAVELENGTH in your terminal — a synced, terminal-styled YouTube listening room. Real audio via mpv, the full web UI as an Ink TUI.

Readme

wavefm

WAVELENGTH in your terminal. A synced, terminal-styled YouTube listening room as a rich Ink TUI — with real audio. Join a room, queue tracks, chat, react, vote-skip, and stay sample-accurately in sync with everyone else listening, all from your shell.

The in-room UI is a full-window, two-panel player (think cmus / ncmpcpp): a full-width header bar, a left PLAYER panel (now-playing + a big animated spectrum visualizer), and a right CONSOLE panel (scrollback + a single command input). It fills the whole terminal and re-flows on resize. You still drive everything by typing one command line — no modal popups, no hotkeys to memorise.

This is a CLI front end for the live WAVELENGTH server at https://timeogilson.be/wave. It speaks the same Socket.IO protocol and REST API as the web app and the SSH gateway.

Quick start

npx wavefm

That's it. On first run you'll be prompted for the room password (the same one the web login screen takes). Your session cookie is then saved to ~/.config/wavefm/session.json (valid ~30 days), so subsequent runs skip the prompt.

Install it permanently

npx wavefm downloads and runs the latest build each time. To get a standing command you can just type, install it globally — then launch with wave or wavefm (the same program, two names):

npm install -g wavefm
wave            # or: wavefm

Update a global install with npm install -g wavefm@latest.

After login you land on the room gate (exactly like the web app): create a new room or join one by id — there is no default/auto-join room. Pass --room to deep-link straight into a specific room and skip the gate:

npx wavefm --room ABCD-1234 --name yourhandle

Audio: mpv (preferred) or ffplay

wavefm plays real audio by streaming from the server and driving an external player:

  • mpv (strongly preferred) — gives sample-accurate sync (live seek + micro speed-nudges), live volume, and a 10-band EQ.
  • ffplay (fallback, ships with ffmpeg) — "close" sync only (~1–2s, re-seek based). No live volume/EQ/speed; pause becomes stop-and-respawn.
  • neither — wavefm still runs fully (silent) in --no-audio mode and prints an install hint. The UI, progress bar, and sync all work; you just won't hear anything.

Installing mpv

| OS | Command | | ------- | ---------------------------------------------------- | | macOS | brew install mpv | | Windows | winget install mpv.io or scoop install mpv | | Linux | sudo apt install mpv / dnf install mpv / pacman -S mpv |

ffplay comes with ffmpeg (brew/apt/dnf/pacman install ffmpeg, or winget install Gyan.FFmpeg on Windows).

Flags

| Flag | Description | | -------------------- | ------------------------------------------------------------------------ | | --server <url> | Base URL. Default https://timeogilson.be/wave (origin + path prefix). | | --room <id> | Deep-link straight into a room (skip the gate). Omit it to pick/create at startup. | | --name <handle> | Display name to join as. | | --password <pw> | Skip the login prompt (e.g. for scripts; prefer the prompt). | | --no-audio | Run the UI without spawning a player (silent). | | --player <path> | Force a specific player binary (mpv or ffplay; basename decides kind). | | wave logout | Clear the saved session for the current server and exit. |

Environment

  • MPV_PATH / FFPLAY_PATH — explicit player binary paths.
  • WAVE_CLI_DEBUG=1 — write a debug log to a file (never to stdout, which Ink owns).

The console (how you drive it)

Once you're in a room the screen is a full-window, two-panel layout under a full-width header bar (▌WAVELENGTH · <room>#<id> · <N listening> · <clock>):

╭ ▌WAVELENGTH ─────────────────── late night#AB12 · 2◉ · 14:59 ╮
│ > Harder Better Faster Stronger │  timeo joined               │
│ Daft Punk                       │  ❯ search daft punk         │
│ 1:23 ━━━━━━━━─────────── 3:45   │  1 One More Time   5:20     │
│ ♪█████░ 80%  ⟳off  ⤮off         │  2 Around the World 7:09    │
│                                 │  timeo  this slaps          │
│   ▄    █       ▆    ▃           │                             │
│ █ █ ▅  █  ▇ ▃  █ ▄  █ ▂         │                             │
│ next › Genesis                  │  ❯ type a song… ▌           │
╰─────────────────────────────────┴─────────────────────────────╯
  • PLAYER panel (left) — the visual centerpiece. Top: the read-only, auto-updating now-playing readout (play/pause glyph + title + author, a live progress bar with times, and a meta line — ♪vol% · repeat · shuffle, plus buffering… / host-lock when relevant). Bottom: a compact spectrum visualizer (a short row of discrete bars, audio-reactive on mpv) anchored above the next › <up-next> line.
  • CONSOLE panel (right) — the scrollback log fills the panel: system events (X joined), chat (name message), your command echoes (❯ play 1), and numbered search/queue results, newest at the bottom. The single, always-focused command input (❯) is pinned at the bottom — the only place you type.

The whole thing fills the terminal and re-renders on resize; the visualizer and panels recompute their size to fit. On very narrow terminals (below ~56 columns) the two panels stack vertically instead (player on top, console below) so nothing is squeezed into an unreadable column.

After you press Enter, the command runs, is echoed into the scrollback, and the input clears immediately and stays focused — the typed line never lingers in the field.

Input keys (the input owns the keyboard — there are no global hotkeys):

| Key | Action | | -------------- | -------------------------------------------- | | enter | run the line (then the field clears) | | ↑ / ↓ | command history | | tab | autocomplete the command name | | ctrl+l | clear the console | | ctrl+c | quit |

The visualizer

A compact, bottom-anchored EQ — a short row of discrete vertical bars (block glyphs ▁▂▃▄▅▆▇█, one blank column between bars, ~16–28 bars by width), capped to a few rows tall and pinned to the bottom of the PLAYER panel (the now-playing block and empty space take the rest). Each bar carries a slow peak-hold cap, and its tip reads brighter than its body. Bars rise fast and fall gracefully (attack/gravity smoothing); paused/stopped settles to a low baseline.

Real audio reactivity requires mpv. With the mpv backend the bars pulse with the track's actual loudness: mpv runs a pass-through astats audio filter and exposes its per-frame RMS over the JSON IPC (af-metadata), which wavefm maps to a smoothed energy level and shapes across the bars. With ffplay or no audio the Node process has no access to the audio signal, so the bars show an honest stylized animation (layered, bass-weighted sines) — lively, but not signal-driven. Install mpv (winget install mpv.io / brew install mpv / apt install mpv) for the reactive version.

The golden rule

Anything that isn't a known command is searched, and the top result is queued to play next. So daft punk one more time just plays it. Chat is the explicit say verb, so plain text always means "play", never "send a message".

Numbered results

After a search (or a bare queue listing, or history), results are numbered and addressable by index against that last list:

  • play 2 — queue result 2 to play next
  • next 2 — play result 2 right now (alias of skip 2)
  • queue 2 — append result 2 to the end of the queue
  • fav 2 — favourite result 2

A bare number is shorthand for play <n>. rooms numbers the room list too, so join 2 joins the second room.

Commands

play, search, skip/next, prev, pause, seek, vol, mute, queue, now, repeat, shuffle, fav, history, rooms, join, create, leave, room, code, lock, say, me, react, vote, theme, eq, lyrics, settings, clear, tune, help.

Type help in the console for the full grid, or help <command> for one. A few that used to be popup panels are now inline:

  • eq — print the 10 bands; eq 3 +4 edits a band, eq flat resets.
  • lyrics — print the current synced/plain lyrics window.
  • settings — print the room + listener settings; toggle with settings repeat all, settings shuffle on, settings autoradio off, settings crossfade 4, settings lock.
  • rooms — list joinable rooms (numbered), then join <n>.

Themes

Five terminal palettes, set or cycled with the theme command (theme, or theme <name>): amber (default), phosphor, ice, c64, ibm.

Parity notes (honestly scoped)

  • CRT toggle has no terminal analogue (no per-cell scanline shader), so it is not surfaced as a command — the stored value is kept only for web parity.
  • Crossfade (crossfadeSec > 0) becomes an instant gapless swap (single mpv instance, no dual-deck).
  • Visualizer is a short, bottom-anchored discrete-bar EQ. It is audio- reactive on mpv (driven by mpv's live astats RMS) and a stylized animation on ffplay / no-audio (the Node process has no signal there). Animated while playing, settles flat when paused.

Requirements

  • Node >= 20 (for global fetch and node:net).
  • A terminal that supports truecolor for the full theme palette (falls back to the nearest ANSI otherwise).