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

signalk-github-pages

v1.0.3

Published

Publish Signal K vessel telemetry to a GitHub Pages site — a static tracker, updated from the boat, with no server ashore.

Readme

GitHub Pages Vessel Tracker

Your boat publishes its own website.

signalk-github-pages: a Signal K plugin that turns live vessel data into a static GitHub Pages site — position, tracks, instruments and conditions — with no server ashore and no git checkout on board.

Signal K plugin Node 20+ TypeScript License BSD-3-Clause npm downloads Boats


Underway, the boat publishes every two minutes. At the dock, hourly. Ashore, anyone with the link sees where you are, where you have been, what the wind is doing and how the batteries are holding up — served by GitHub Pages, which does not go down when the hotspot does, and costs nothing.

Tip: Buy a domain and point it at the Pages site, so the link you give people is myboat.com rather than you.github.io. In the repository's Settings → Pages, set the custom domain, add the DNS records GitHub lists at your registrar, and tick Override site address on the plugin's config page so link previews resolve against the new address. Use a domain attached to Pages, not an HTTP redirect: a redirect changes the address in the browser to the github.io one, which defeats the point, and breaks the installed home-screen app's scope. Costs about $12 a year for a .com.

   Signal K server                          GitHub                    Ashore
┌────────────────────┐              ┌──────────────────┐        ┌──────────────┐
│  navigation.*      │  in-process  │  Git Data API    │  Pages │              │
│  environment.*     ├─────────────▶│  blobs → tree    ├───────▶│  your-site   │
│  electrical.*      │    plugin    │  → commit → ref  │        │  .github.io  │
└─────────┬──────────┘              └──────────────────┘        └──────────────┘
          │
          │ navigation.state
          │ sets the cadence
          ▼
   plugin data dir
   (rolling state)

No git binary. No working copy to corrupt. No systemd unit. Nothing to hand-edit: every setting is either on the plugin's config page or read from the server. The plugin reads the self tree in-process, keeps its rolling state in app.getDataDirPath(), and each cycle is one commit built on the live HEAD.

What you get

For people ashore

| | | |---|---| | Where the boat is | Live position on a map, redacted inside your privacy zones | | Where it has been | A track per local calendar day, as GPX, listed on a Voyages tab. Each voyage has its own link to share, and its own sail log if you write one | | Where it is going | A passage banner from the waypoint or route active on the plotter, gone on arrival | | How it is doing | Instruments colored by the zones set on the server, sparklines from your history provider, active notifications and how often each has fired | | Conditions | Tides from the nearest NOAA station and a 48-hour wind, swell and temperature forecast | | Your own links | Buttons to anything else the boat has online, from site.customLinks |

How it behaves

  • Adaptive cadence. Fast underway, slow at anchor, straight off navigation.state, with a publish the moment it changes.
  • Nothing hand-edited. A value the boat knows is read from Signal K: name, registrations, units, alarm zones, the active polar, the passage. A value you choose is a field on the config page.
  • Shares the repository. The plugin writes only the paths it declares in .tracker-manifest.json. Everything else in the repository is yours.
  • Measures its own cost. Every cycle logs bytes on the wire, API calls and rate limit left, and warns when the instrument log gets expensive.
  • On-boat console. A Signal K webapp that previews the site from live data, publishes on request and prunes old voyages.

Live example

mermug.com is this plugin running on a 1994 Beneteau First 42s7 on a Raspberry Pi 5, served from a custom domain. It shows the whole thing: the position map, daily tracks on the Voyages tab, instruments with sparklines, tides and the 48-hour forecast.

Quick start

1. A repository with Pages on. The plugin publishes to <you>.github.io unless you override the name; anything else is served at /<repo>/. Settings → Pages → Deploy from a branch → main / (root).

Use a repository that holds only the tracker. The token can rewrite every file in it, and the site is served from your github.io origin, so a leaked token means someone else's JavaScript on your page. A dedicated repository keeps that to the tracker. The plugin shares a repository politely, but the token does not.

2. A token. Make a fine-grained PAT and tick exactly this much:

| In the token form | Set it to | |---|---| | Resource owner | You, or the organization that owns the repository | | Repository access | Only select repositories → the Pages repository | | Repository permissions → Contents | Read and write | | Repository permissions → Metadata | Read-only — added for you, cannot be removed | | Expiration | 90 days, with a calendar reminder to rotate. Publishing stops with a 401 the day it lapses, and the plugin raises notifications.tracker.publishFailed after half an hour of failures |

Nothing else is needed: no Actions, no Pages, no account permissions. The commonly missed one is Contents, because a token without it reads the repository perfectly and fails on the first commit with a 403.

A classic token works too if you prefer one: the repo scope, or public_repo if the repository is public. It is a blunter instrument — it reaches every repository you can push to — so use a fine-grained one unless you have a reason not to.

The plugin reads the failure status back to you: 401 says the token is wrong or expired, 403 says it lacks Contents: read and write, 404 says it cannot see the repository.

3. Install it. In the Signal K admin UI, Appstore → Available, search for GitHub Pages, install, and restart the server when it asks. From a shell, the same thing is:

cd ~/.signalk
npm install signalk-github-pages
sudo systemctl restart signalk        # or however you run the server

To run unreleased code from main, install github:zackphillips/signalk-github-pages instead; npm clones it and runs the TypeScript build through the package's prepare script.

Then open Server → Plugin Config → GitHub Pages Vessel Tracker, fill in the repository owner and the token, enable. Everything else has a working default or is derived.

The first cycle writes the whole site — HTML, CSS, JS, icons — then telemetry only. Give Pages a minute, then open the URL.

Tip: Install signalk-autostate if you have not. It sets navigation.state, which is what makes the cadence adaptive. Without it every cycle uses the stationary interval.

Configuration

Two fields are required: github.owner and github.token. The ones you are most likely to change:

| Field | Default | What it does | |---|---|---| | interval.underwayMinutes | 2 | Cadence when sailing or motoring | | interval.stationaryMinutes | 60 | Cadence moored, anchored, or state unknown | | privacyZones[] | empty | {name, lat, lon, radius_m}; see Privacy | | paths.hide | one server notice | Paths never published, notifications included | | instrumentLog.hours | 1 | How far back the sparklines reach; 0 publishes none | | site.logo, site.icon | empty | The boat's logo, and the tab and home-screen icon |

The repository name, branch, site URL, timezone and tide station are derived, and each has an override. The polar comes from Polar Management. The full field list is in Configuration.

Warning: A token typed into the config page is stored as plain JSON under ~/.signalk/plugin-config-data/, and Signal K's admin API returns plugin configuration to any admin session. It is readable by anyone with a shell on the server, anyone logged in as a Signal K admin, and anything that backs up that directory. Scope it to the one repository, and rotate it if the Pi ever leaves your hands.

To keep it off the config page, put it in a file and point the plugin at it (Token from a file).

Privacy

GitHub Pages sites are public. Anything the plugin publishes can be read by anyone who has the URL.

  • Privacy zones. A position inside a zone is published as the zone's center and left out of the track entirely. Every position in the snapshot is checked, navigation.anchor.position included. Correcting a zone also trims tracks that are already published.
  • Positions go through one path. The instrument log never asks for a position, and the passage banner publishes names, never coordinates.
  • Zones start empty. Nothing is hidden until you say what to hide. Put the center off your slip and make the radius reach past it with room to spare.
  • Notifications are free text written by whichever plugin raised them, and they are published verbatim. notifications.publish turns them off, and paths.hide drops any path or subtree.

Details are in Privacy.

Documentation

| | | |---|---| | Configuration | Every field, and the five overrides | | Track and instruments | Track thinning, the history provider, sparkline windows, instrument paths and bandwidth | | Privacy | Privacy zones in full | | The site | Units and alarm zones, notifications, branding, what is read from Signal K, the passage banner, tides, polars | | The repository and the console | What the plugin writes, and the on-boat console | | Troubleshooting | The cycle log, "Data unavailable", a plugin missing from the list |

Trade-offs worth knowing

The plugin runs inside the server process. A bug here can affect the navigation data hub. Every cycle is wrapped: an exception skips one update, is reported in the admin UI, and never reaches the server's event loop. That is the cost of reading the tree in-process, and it buys away an HTTP poll that could freeze the site on stale data.

It needs a data link. The site updates when the boat has one. Offshore it shows the last publish and how long ago that was.

The token sits in plain text, on the page or in the file you point the plugin at. The file keeps it out of the admin API and config backups, not off the Pi's disk.

One commit per cycle. The repository grows at the rate you publish. Exclude the instrument paths you do not look at.

Nothing is served from the boat. That is KIP's job. This site is for people ashore, and it stays up when the boat's link does not.

Development

npm install
npm test          # vitest
npm run typecheck # tsc --noEmit
npm run build     # tsc → dist/
npm run dev       # site/ + sample/ on http://localhost:8000

npm run dev serves the real frontend against fixture telemetry, so no boat is required. Publisher.runCycle() takes a self tree and returns what it did without calling back into the server, so a full publish cycle is tested without Signal K and without a network. The source layout and the rules that are not obvious are in AGENTS.md.

License

BSD 3-Clause. See LICENSE.