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

demowright

v2.8.0

Published

Playwright video production plugin — cursor overlay, keystroke badges, TTS narration, and narration-driven video scripts for test recordings

Readme

demowright

Playwright HUD plugin — renders a visible mouse cursor, keystroke display, auto-slowdown, TTS narration, and subtitles into test video recordings, making them readable by humans and AI (e.g. Gemini video analysis).

Demos

6 runnable examples in examples/ — see Examples guide

| # | Demo | What it shows | |---|------|---------------| | 01 | Dashboard | Cursor, clicks, Ctrl+K search, modal form typing | | 02 | Monaco Editor | Real VS Code editor — typing, Ctrl+S/Z/A, tab switching | | 03 | E-commerce Checkout | Browse, add to cart, fill payment form with annotate() | | 04 | Narrated Tour | SaaS landing page tour — heavy TTS + subtitles | | 05 | Kanban Board | Move cards between columns, add tasks | | 06 | Native API | Zero helperspage.click(), page.fill() only |

npx playwright test --config examples/playwright.config.ts  # run all 6

Problem

Playwright's video recording doesn't capture the browser cursor or keyboard input. Tests run too fast for meaningful video review.

Solution

demowright injects a lightweight overlay into every page during test execution:

  • 🖱️ Visible cursor — SVG pointer follows mouse with click ripple effects
  • ⌨️ Keystroke display — keys shown as HUD badges; modifier keys (Shift/Ctrl/Alt) as persistent blue badges
  • 🐢 Auto-slowdown — configurable delays after actions for human-readable recordings
  • 🗣️ TTS narration — spoken annotations via pluggable providers (OpenAI, ElevenLabs, espeak, URL template)
  • 💬 Subtitles — visual text overlays that fade in/out during recordings
  • 🎵 Audio capture — record browser audio to WAV via Web Audio API tap
  • 🔌 Non-invasive — 4 integration methods, from zero-change config to full programmatic control

Quick Start

npm install demowright

Zero-change setup (recommended) ⭐

Add one line to your playwright.config.ts — no test files need to change:

// playwright.config.ts
import { defineConfig } from "@playwright/test";
import { withDemowright } from "demowright/config";

export default withDemowright(
  defineConfig({
    use: { video: "on" },
  }),
);

Your existing tests keep using import { test } from '@playwright/test' — the HUD is injected automatically.

Alternative: CLI flag (zero code changes at all)

NODE_OPTIONS="--require demowright/register" npx playwright test

Alternative: Import replacement

// Change this:
import { test, expect } from "@playwright/test";
// To this:
import { test, expect } from "demowright";

Alternative: Programmatic (full control)

import { test as base } from "@playwright/test";
import { applyHud } from "demowright";

const test = base.extend({
  context: async ({ context }, use) => {
    await applyHud(context, { cursor: true, keyboard: true, actionDelay: 150 });
    await use(context);
  },
});

Configuration

// Via withDemowright (recommended)
export default withDemowright(defineConfig({ ... }), {
  actionDelay: 200,
  cursorStyle: 'dot',
});

// Via test.use (import replacement approach)
test.use({
  qaHud: {
    cursor: true,            // show cursor overlay (default: true)
    keyboard: true,          // show keystroke display (default: true)
    cursorStyle: 'default',  // 'default' | 'dot' | 'crosshair'
    keyFadeMs: 1500,         // key label fade time in ms
    actionDelay: 120,        // delay after each action for readability (ms)
    audio: false,            // path to save WAV, or false to disable
    tts: false,              // TTS provider: URL template, function, or false
  },
});

// Via env vars (CLI approach)
QA_HUD_CURSOR=0 QA_HUD_DELAY=200 NODE_OPTIONS="--require demowright/register" npx playwright test

| Env Var | Description | Default | | ------------------------- | ------------------------- | --------- | | QA_HUD=0 | Disable HUD entirely | enabled | | QA_HUD_CURSOR=0 | Disable cursor overlay | enabled | | QA_HUD_KEYBOARD=0 | Disable keyboard display | enabled | | QA_HUD_DELAY=200 | Action delay in ms | 120 | | QA_HUD_CURSOR_STYLE=dot | Cursor style | default | | QA_HUD_KEY_FADE=2000 | Key label fade time in ms | 1500 | | QA_HUD_TTS=url | TTS URL template (%s) | disabled |

Helpers — Recording-Only Convenience Functions

import { clickEl, typeKeys, narrate, annotate, hudWait } from "demowright/helpers";

await annotate(page, "Welcome to the product tour"); // subtitle + TTS
await clickEl(page, "#get-started");                  // animated cursor + ripple + click
await typeKeys(page, "[email protected]", 60, "#email"); // char-by-char with key badges
await hudWait(page, 500);                              // waits only during recording
await narrate(page, "Now let's submit the form");      // TTS narration

All helpers are no-ops when HUD is inactive — safe to leave in production tests.

TTS Narration

Configure a TTS provider for spoken narration in recordings:

export default withDemowright(defineConfig({ ... }), {
  tts: "http://localhost:5000/tts?text=%s", // URL template
  audio: "test-audio.wav",                   // capture audio to WAV
});

Or use a function for APIs requiring auth (OpenAI, ElevenLabs, etc.):

await applyHud(context, {
  tts: async (text) => {
    const res = await fetch("https://api.openai.com/v1/audio/speech", {
      method: "POST",
      headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}`, "Content-Type": "application/json" },
      body: JSON.stringify({ model: "tts-1", voice: "alloy", input: text }),
    });
    return Buffer.from(await res.arrayBuffer());
  },
});

How It Works

  1. Event listeners are injected via context.addInitScript() — captures mouse/keyboard events before DOM exists, survives navigations
  2. DOM overlay is injected via page.evaluate() after each navigation (goto, reload, setContent, etc.)
  3. The overlay uses pointer-events: none and max z-index — never interferes with test interactions
  4. Page actions (click, fill, type, etc.) are wrapped with configurable delays for video readability

Documentation

| Guide | Description | |-------|-------------| | Getting Started | Installation, 4 integration methods, configuration | | Helpers API | clickEl, typeKeys, moveTo, hudWait reference | | Narration & Subtitles | narrate(), subtitle(), annotate() | | TTS Setup | Configuring text-to-speech providers | | Cursor & Keyboard | Cursor styles, key badges, click ripples, auto-slowdown | | Audio Capture | Recording browser audio to WAV | | Examples | 6 runnable demo scenarios | | Wrapper Strategies | Making native Playwright calls show the HUD |

License

MIT