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

@projektemacher/storymapjs

v0.10.1

Published

StoryMapJS viewer library — unofficial TypeScript/OpenLayers rewrite of the Knight Lab StoryMapJS (viewer only)

Readme

StoryMapJS: Maps that tell stories.

Important: this is an unofficial, unapproved fork of the original NUKnightLab/StoryMapJS repository. It is a proof of concept for an AI-based renovation of the codebase, built using the model GLM 5.3 Flash. It is not endorsed by, affiliated with, or supported by Northwestern University Knight Lab.

This fork is a viewer-only library: it renders existing StoryMap JSON files (or IIIF Presentation manifests) with TypeScript + Vite + OpenLayers. There is no authoring tool — create your storymap JSON by hand or with your own code, and see docs/ for the migration notes from the original Knight Lab release.

Development

See docs/DEVELOPMENT.md to get setup for local development of StoryMapJS. This repository is the viewer library only (TypeScript + Vite + OpenLayers); StoryMap JSON is validated against the schema in schema/ on load and via npm run validate.

Contributing language translations

StoryMap ships locale files for dozens of languages under src/language/locale/ (for example es.json). To add or improve a translation, copy an existing file and edit the quoted strings — please don't change the "keys" (the unquoted strings). The file name is the language code, e.g. es.json (codes like zh-cn.json and zh-tw.json are also supported — the value of the storymap's language option must match the file name).

IIIF images

Large images served over the IIIF Image API are rendered so when set to be map_as_image the entire image is shown. When set as cartography the zoom will set so that all the markers fit.

Points are set to only display on mouseover in image mode, but you can set map_as_image to false in the config options to always show the points. The points are hidden when the intent is an image so that nothing obstructs the image the viewer is looking at. Looking at a painting is hard with a bunch of points on it.

Map Options

To disable connecting lines on maps set map_as_image: true in the storymap options (the default false renders cartography).

The menubar buttons can be disabled individually:

show_overview:       false,   // map overview button
show_back_to_start:  false,   // back to the beginning button
fullscreen:          false,   // fullscreen toggle

(true is the default; setting the option to false hides the button.)

More config options available to do what you want with the line:

line_follows_path:      true,		// Map history path follows default line, if false it will connect previous and current only
line_color:             "#c34528",
line_color_inactive:    "#CCC",
line_join:              "miter",
line_weight:            3,
line_opacity:           0.80,
line_dash:              "5,5",
show_lines:             true,
show_history_line:      true,

To disable zoom calculation/edit zoom level set calculate_zoom to false in the config options.

Images can now be used in place of map pins. Use image inside the location object and include a url to use, together with use_custom_marker: true in the location object (or set use_custom_markers: true globally in the storymap options). Same goes for custom icons except you need icon inside the location object.

Limit the map to a bounding box

Set map_bbox to [west, south, east, north] (lon/lat) to constrain the map — nothing outside of the box can be visible:

map_bbox: [-11, 34, 32, 71],   // or null (the default) to leave the map unconstrained

For image-space (IIIF) maps the coordinates are raw image pixels. When the slide content panel is opaque (a solid background that hides the map behind it), the initial fit accounts for the covered area so the story stays inside the visible region.

Custom HTML in slide content

Slide text is rendered as HTML: the text (and headline) fields accept arbitrary markup. If the text contains no <p> tag, it is wrapped in one automatically; otherwise it is used as-is. This means you can use links, images, lists, emphasis and spans in your slides, e.g.:

{
    "headline": "1920: An American in the Making",
    "text": "Immigrants arriving at <a href=\"https://example.org\">Ellis Island</a>.<br><span class='vco-note'>Photograph: Library of Congress.</span>"
}

The vco-note span renders as a small grey note, like the built-in credits.

Caution: the text is rendered raw — it is not sanitized. Only load storymaps from sources you trust.

GDPR consent for external services

Set the consent_required option to true to ask for permission before anything is loaded from external services (media embeds such as YouTube, Twitter or SoundCloud, map tiles, and external font CSS):

{
    "consent_required": true,
    ...
}

Each service asks with an Allow/Deny panel; answering one panel resolves every pending panel of the same service. If a decision was already stored in the cookie, the panel is skipped entirely. Denied services show a placeholder instead of the media, and the map renders without tiles until they are allowed. Decisions are stored in a cookie (storymapjs-consent) for 90 days — clearing cookies asks again.

Troubleshooting

If a storymap fails to render, open the browser console: the viewer logs fetch and validation errors (e.g. "could not load storymap data from ..."). The error event also fires for programmatic consumers.

Bundled credentials

The viewer ships no credentials. Mapbox/Stadia tiles need a token passed via map_access_token, and flickr.com/photos API URLs need api_key_flickr (both settable in the storymap options).