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

@tokagemushi/manga-viewer

v0.2.0

Published

A standalone, feature-rich manga and comic viewer for the web. RTL/LTR, pinch zoom, inertia, spread mode, swipe, keyboard navigation, and more.

Readme

📖 Manga Viewer

A standalone, zero-dependency manga & comic viewer for the web.

Built for Japanese manga reading conventions (RTL page order, spread mode on landscape) but fully configurable for any comic format.


✅ Features

  • RTL & LTR reading direction
  • Spread mode — automatic two-page spread on landscape screens
  • Pinch zoom with inertia & rubber-band bounce
  • Swipe navigation with momentum
  • Double-tap zoom (touch & mouse)
  • Keyboard navigation — arrow keys, Space, Home/End, Esc
  • Mouse & touch support
  • Reading progress saved to localStorage
  • UI controls — header, footer, page slider, zoom buttons
  • Help overlay with context-aware instructions
  • Resume dialog — "Continue from page X?"
  • Orientation detection — auto spread/single on resize
  • Preloading — nearby pages loaded eagerly
  • Insert pages — ads, HTML, or image inserts at any position
  • Preview limit — free-preview with purchase prompt
  • Google AdSense integration
  • Scroll mode — vertical continuous scroll
  • Fullscreen — native + pseudo-fullscreen fallback
  • Status bar cover — for mobile notch/safe-area
  • Share — X (Twitter) share & link copy
  • Dark theme — matches mobile light / desktop dark automatically
  • No dependencies — pure vanilla JS & CSS, no build tools required
  • ES Moduleimport MangaViewer from './manga-viewer.js'

🚀 Quick Start

1. Download or CDN

<link rel="stylesheet" href="manga-viewer.css">
<script type="module">
  import MangaViewer from './manga-viewer.js';
</script>

2. Create a viewer

<div id="viewer"></div>

<script type="module">
  import MangaViewer from './manga-viewer.js';

  const viewer = new MangaViewer({
    container: '#viewer',
    pages: [
      'pages/001.jpg',
      'pages/002.jpg',
      'pages/003.jpg',
      // ...
    ],
    direction: 'rtl',
    title: 'My Manga',
  });
</script>

That's it. The viewer takes over the container element with a full-screen reading experience.


📚 API Reference

Constructor Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | container | string \| HTMLElement | '#viewer' | CSS selector or DOM element | | pages | Array<string \| Object> | [] | Image URLs or page objects (see below) | | direction | 'rtl' \| 'ltr' | 'rtl' | Reading direction | | firstPageSingle | boolean | true | Show first page alone in spread mode | | viewMode | 'page' \| 'scroll' | 'page' | Page-flip or vertical scroll | | title | string | '' | Displayed in the header | | backUrl | string | '/' | URL for the back button | | shareUrl | string | '' | URL used for share/copy (defaults to current page) | | bookmarkEnabled | boolean | true | Enable bookmark UI and bookmark manager | | bookmarkApi | string \| null | null | API endpoint used to sync bookmarks (falls back to localStorage) | | storageKey | string | 'manga_progress' | localStorage key for reading progress | | showHeader | boolean | true | Show/hide header bar | | showFooter | boolean | true | Show/hide footer bar | | loadingText | string | 'Loading...' | Loading screen text | | previewLimit | number \| null | null | Number of free-preview pages | | purchaseUrl | string | '' | URL for purchase button | | purchasePrice | string | '' | Price label on purchase button | | adsense | { client, slot } | null | Append AdSense page at end | | onPageChange | Function | null | (currentPage, totalPages) => {} | | onComplete | Function | null | Called when last page is reached |

Page Objects

Pages can be simple image URLs or objects:

// Simple
'page001.jpg'

// Image with link
{ type: 'image', src: 'ad.jpg', linkUrl: 'https://...', linkTarget: '_blank', backgroundColor: '#000' }

// HTML insert
{ type: 'html', html: '<div>...</div>', backgroundColor: '#fff' }

// AdSense
{ type: 'adsense', client: 'ca-pub-XXX', slot: '123456' }

Instance Properties

| Property | Type | Description | |----------|------|-------------| | viewer.currentPage | number | Current page number (1-indexed) | | viewer.totalPages | number | Total page count |

Instance Methods

| Method | Description | |--------|-------------| | viewer.goToPage(n) | Jump to page number (1-indexed) | | viewer.goToSlot(n) | Jump to slot index (0-indexed) | | viewer.zoomIn() | Zoom in by one step | | viewer.resetZoom() | Reset zoom to 1× | | viewer.destroy() | Remove viewer and clean up all event listeners |


🎨 Styling

The viewer uses mv- prefixed CSS classes to avoid conflicts. All styles are in manga-viewer.css. The default theme:

  • Desktop: dark background with light controls
  • Mobile (≤768px): light background with dark controls

Override any class in your own stylesheet. Key classes:

  • .mv-container — outer wrapper
  • .mv-header / .mv-footer — top/bottom bars
  • .mv-page-slider — range input (slider)
  • .mv-page-slot — individual page frame

🖥 Browser Support

| Browser | Support | |---------|---------| | Chrome / Edge | ✅ Latest | | Firefox | ✅ Latest | | Safari / iOS Safari | ✅ Latest | | Samsung Internet | ✅ Latest |

Requires ES Module support (<script type="module">).


📄 License

MIT — Created by tokagemushi