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

@technical-1/emulation

v1.1.1

Published

Device, viewport, and mobile emulation for Puppeteer pages — KnownDevices presets, deviceScaleFactor, isMobile, hasTouch, and arbitrary viewports.

Readme

@technical-1/emulation

Device, viewport, and mobile emulation for a Puppeteer PageKnownDevices presets, deviceScaleFactor, isMobile, hasTouch, isLandscape, and arbitrary viewports. You inject the Page (type-only puppeteer-core peer). Errors are typed PptrKitErrors from @technical-1/core; pass an optional DI logger.

import { emulateDevice, listKnownDevices } from "@technical-1/emulation";

// 1) A named KnownDevices preset (applies UA + viewport via page.emulate)
await emulateDevice(page, "iPhone 15 Pro");

// 2) A full custom Device (UA + viewport)
await emulateDevice(page, {
  userAgent: "Mozilla/5.0 (custom) Chrome/144.0.0.0",
  viewport: { width: 375, height: 812, deviceScaleFactor: 3, isMobile: true, hasTouch: true },
});

// 3) A bare viewport (applies via page.setViewport) — arbitrary sizes + touch/mobile flags
await emulateDevice(page, { width: 1280, height: 720 });
await emulateDevice(page, { width: 400, height: 800, isMobile: true, hasTouch: true });

// Discover the presets your installed puppeteer-core ships:
listKnownDevices(); // ["Blackberry PlayBook", …, "iPhone 15 Pro", …]

Behavior

  • Preset name (string) → looked up in puppeteer-core's KnownDevices, applied via page.emulate (sets both user agent and viewport, including deviceScaleFactor / isMobile / hasTouch). An unknown name throws PptrKitError with retryable: false (deterministic caller error).
  • Device ({ userAgent, viewport }) → applied via page.emulate.
  • Viewport ({ width, height, deviceScaleFactor?, isMobile?, hasTouch?, isLandscape? }) → applied via page.setViewport (viewport only; user agent unchanged).

A page.emulate / page.setViewport rejection is wrapped as PptrKitError with retryable: true, carrying the original error as cause.

page.emulate registers the user-agent/viewport for subsequent navigations — call emulateDevice before page.goto. To keep a spoofed UA's Chrome/<version> token in sync with the live binary, or to randomize UA/locale/timezone, compose with @technical-1/fingerprint.

Overrides

Beyond device/viewport emulation, this package ships three standalone override functions — overridePermissions, setGeolocation, and emulateMedia. Each is a typed-error, step-logging function following the same conventions as emulateDevice.

import { overridePermissions, setGeolocation, emulateMedia } from "@technical-1/emulation";

// Grant permissions (camera/mic/geolocation/notifications/clipboard) on a page's context
await overridePermissions(page, ["geolocation", "notifications"]);

// Set coordinates — geolocation requires the permission, so grant + set together:
await setGeolocation(page, { latitude: 48.8584, longitude: 2.2945, accuracy: 5 }, {
  grantPermission: true,
});

// Emulate dark mode + print media
await emulateMedia(page, { colorScheme: "dark", reducedMotion: "reduce" });
await emulateMedia(page, { mediaType: "print" }); // e.g. before @technical-1/pdf
  • overridePermissions(target, permissions, options?) — grants a set of browser permissions on a BrowserContext or on the context owning a Page. Pass a BrowserContext with a required origin, or a Page, whose origin defaults to its current URL when omitted. Throws ConfigError (retryable: false) for an empty permissions list, a missing origin when targeting a BrowserContext, or an origin that can't be derived from the page (e.g. about:blank). A rejection from the underlying call is wrapped as PptrKitError (retryable: true).

    This wraps puppeteer-core's BrowserContext.overridePermissions, which the types mark deprecated in favor of setPermission. The wrapper is intentional for the grant-a-set ergonomics; callers needing per-descriptor state control can use setPermission directly.

  • setGeolocation(page, coords, options?) — sets range-validated coordinates (latitude -90..90, longitude -180..180, accuracy >= 0). page.setGeolocation requires the geolocation permission to already be granted, or it has no visible effect — pass grantPermission: true to grant it (via overridePermissions) before setting the coordinates. Throws ConfigError (retryable: false) for out-of-range/non-finite values.

  • emulateMedia(page, media, options?) — emulates CSS media type (page.emulateMediaType) and/or media features (page.emulateMediaFeatures): prefers-color-scheme, prefers-reduced-motion, forced-colors, color-gamut. Throws ConfigError (retryable: false) when media provides neither a mediaType key nor any feature.

CPU throttling remains out of scope for this package.

Install

pnpm add @technical-1/emulation puppeteer-core

puppeteer-core is a peer dependency (>=22 <25); bring your own.