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

pinch-type

v0.2.6

Published

Pinch to zoom text, not the page. Canvas-based text scaling for mobile web.

Readme

pinch-type

Three canvas-based text effects for mobile web, built on @chenglou/pretext.

  • Pinch Type — intercepts pinch-to-zoom and scales text size instead of zooming the page
  • Scroll Morph — fisheye effect: text near the viewport center is large and bright, edges are small and dim
  • Combined — both effects together

Live Demo →

Install

npm install pinch-type @chenglou/pretext

Quick Start

import { createPinchType, createScrollMorph, createPinchMorph } from 'pinch-type';

// 1. Pinch Type — uniform text, pinch gestures scale all text
const pt = createPinchType(document.getElementById('reader'));
pt.setText('Your long article text here…');

// 2. Scroll Morph — fisheye effect, no pinch zoom
const sm = createScrollMorph(document.getElementById('reader'));
sm.setText('Your long article text here…');

// 3. Combined — fisheye + pinch-to-zoom (the original behavior)
const pm = createPinchMorph(document.getElementById('reader'));
pm.setText('Your long article text here…');

// Clean up when done:
instance.destroy();

The container element should have a defined width and height (e.g. 100vw × 100vh). Each function creates a fullscreen <canvas> inside it.

API

createPinchType(element, options?)

Uniform text rendering with pinch-to-zoom scaling.

| Option | Type | Default | Description | |---|---|---|---| | fontSize | number | 18 | Base font size | | minFontSize | number | 8 | Smallest size reachable via pinch | | maxFontSize | number | 60 | Largest size reachable via pinch | | fontFamily | string | "Inter", system-ui, sans-serif | CSS font-family | | lineHeight | number | 1.57 | Line-height ratio | | padding | number | 28 | Content padding (px) | | background | string | #0a0a0a | Canvas background color | | friction | number | 0.95 | Scroll momentum friction (0–1) | | onZoom | (fontSize) => void | — | Callback after each pinch zoom |

createScrollMorph(element, options?)

Fisheye scroll effect. No pinch-to-zoom.

| Option | Type | Default | Description | |---|---|---|---| | centerFontSize | number | 26 | Font size at viewport center | | edgeFontSize | number | 11 | Font size at viewport edges | | morphRadius | number | 300 | Radius (px) of the center→edge gradient | | fontFamily | string | "Inter", system-ui, sans-serif | CSS font-family | | lineHeight | number | 1.57 | Line-height ratio | | padding | number | 28 | Content padding (px) | | background | string | #0a0a0a | Canvas background color | | friction | number | 0.95 | Scroll momentum friction (0–1) |

createPinchMorph(element, options?)

Combined: fisheye scroll effect + pinch-to-zoom.

| Option | Type | Default | Description | |---|---|---|---| | centerFontSize | number | 26 | Font size at viewport center | | edgeFontSize | number | 11 | Font size at viewport edges | | minFontSize | number | 8 | Smallest size reachable via pinch | | maxFontSize | number | 60 | Largest size reachable via pinch | | morphRadius | number | 300 | Radius (px) of the center→edge gradient | | fontFamily | string | "Inter", system-ui, sans-serif | CSS font-family | | lineHeight | number | 1.57 | Line-height ratio | | padding | number | 28 | Content padding (px) | | background | string | #0a0a0a | Canvas background color | | friction | number | 0.95 | Scroll momentum friction (0–1) | | onZoom | (center, edge) => void | — | Callback after each pinch zoom |

Instance Methods (all three)

| Method | Description | |---|---| | setText(text) | Update displayed text and re-layout | | resize() | Force re-layout (auto-called on window resize) | | destroy() | Remove canvas, listeners, and animation loop | | canvas | The underlying <canvas> element (read-only) |

Lightweight Mode

Just want pinch-to-zoom on your existing page? Use the lightweight API — no canvas, no dependencies, ~1KB. Want the full canvas rendering experience? Use createPinchType / createScrollMorph / createPinchMorph above.

pinchZoom(options?) — Vanilla JS

import { pinchZoom } from 'pinch-type';

const cleanup = pinchZoom({
  target: document.getElementById('article'),  // default: document.documentElement
  min: 12,        // min font size, default 12
  max: 32,        // max font size, default 32
  initial: 16,    // starting size, default 16
  step: 1,        // px per zoom step, default 1
  onZoom: (size) => console.log(size),
});

// Later: remove all listeners
cleanup();

Detects two-finger touch pinch and trackpad pinch (ctrl+wheel / meta+wheel). Single-finger scroll is unaffected. Applies font-size directly to the target element.

usePinchZoom(options?) — React Hook

Requires react as a peer dependency.

import { usePinchZoom } from 'pinch-type';

function Reader() {
  const { fontSize, ref } = usePinchZoom({ min: 12, max: 32 });
  return <article ref={ref} style={{ fontSize }}>...</article>;
}

| Option | Type | Default | Description | |---|---|---|---| | min | number | 12 | Minimum font size | | max | number | 32 | Maximum font size | | initial | number | 16 | Starting font size | | step | number | 1 | Pixels per zoom step | | onZoom | (size) => void | — | Callback after each zoom |

How It Works

Text is measured and wrapped using @chenglou/pretext for accurate segment-aware line breaking. Each frame, lines are drawn to a canvas. For scroll morph, font size and opacity are interpolated based on distance from the viewport center (ease-out cubic). Touch events drive momentum scrolling with configurable friction, and two-finger pinch gestures scale the font size range in real time.

License

MIT — Lucas Crespo