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

@inkly-org/interactive-demo

v0.2.1

Published

React player and schema for interactive product demos.

Readme

@inkly-org/interactive-demo

The React player and the demo schema for interactive product demos.

A demo is a demo.config.json file: an ordered list of steps, each a screenshot (image) or a screen recording (video) with hotspots, captions and an optional voiceover, plus cover screens made of widgets. The schema is defined with Zod and exported from ./schema.

Install

npm install @inkly-org/interactive-demo react react-dom

Use as a React component

import { Demo } from '@inkly-org/interactive-demo';
import '@inkly-org/interactive-demo/styles.css';

export function ProductTour() {
  return <Demo src="/demos/onboarding/" />;
}

src is either the demo folder's URL (the config is fetched from it and media resolves against it) or the config object itself (an imported demo.config.json; pass baseUrl for the folder its media lives in). Demo validates the config with DemoSchema and renders the player. Props of note: baseUrl, resolveAssetUrl (a custom rule for relative media paths, e.g. a CDN), themeTokens, onEvent (step views, completion, CTA clicks, form submits), layout and controls.

DemoModal opens the same player in a pop-up over your page, rendered in-process through a portal: <DemoModal open={open} onClose={…}><Demo … /></DemoModal>.

A page that isn't React opens a demo page in a pop-up with the loader instead: @inkly-org/interactive-demo/embed.js (the CLI's build copies it to dist/embed.js) adds InteractiveDemo.open(url).

The runtime reference has every prop, the events and the page contract.

Use the self-contained player on a static page

player.js bundles React and the player. A page mounts a demo with one JSON script tag and a root element:

<link rel="stylesheet" href="./player.css" />
<script id="demo-config" type="application/json">{ /* demo.config.json */ }</script>
<div id="root"></div>
<script src="./player.js"></script>

Media paths in the config (assets/<file>) resolve relative to the page. The CLI's build command writes exactly this layout.

The page's #root gets the demo-level canvas background (background / backgroundColor in the config), and two query parameters are honoured: ?autoplay=1 starts playback as soon as the player is ready, and ?render=1 (for an exporter driving the page) implies it.

Once mounted, the player exposes a small contract on window.__demo so a host page or exporter can detect readiness, drive the player and wait for the end:

window.__demo = {
  ready: true,        // set when the player has parsed the config and mounted
  complete: false,    // flips to true when the last step finishes
  stepIds: string[],  // every step id, in order
  controls,           // play(), pause(), next(), prev(), seekToStep(id), …
  demo,               // the validated config
};

Schema

import { DemoSchema, parseDemo } from '@inkly-org/interactive-demo/schema';

DEMO_CONFIG_SCHEMA_URL is the $schema URL for editor autocompletion.

Theme

import { resolveDemoTheme } from '@inkly-org/interactive-demo/themes';

There is one theme: indigo accent, dotted canvas, serif display headings. Customise it with four tokens — primary, secondary, font, radius — through themeTokens or a demo's theme.tokens. resolveDemoTheme().css is the theme's scoped CSS for a React host to inject. Theme presets were removed: theme.preset and the themeId prop are accepted and ignored.

Fonts (optional)

The stylesheet never loads fonts. The UI sans (Inter) and the mono (Geist Mono) fall back to the system fonts unless you opt in. The default theme's heading stack names "Waldenburg" first; it is not shipped (proprietary) and falls back to Inter:

import "@inkly-org/interactive-demo/styles.css";
import "@inkly-org/interactive-demo/fonts.css"; // self-hosted, no network

fonts.css ships two @font-face rules (Inter and Geist Mono, variable weights) pointing at dist/fonts/*.woff2 from the fontsource packages, SIL Open Font License. The CLI's dev and build include it automatically as player-fonts.css next to player.css.