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

pdf-flipper

v1.0.0

Published

A responsive, animated PDF flipbook viewer. Give it a PDF URL and watch it turn into a beautiful interactive book.

Readme

pdf-flipbook

A responsive, animated PDF flipbook viewer.
Give it a PDF URL and it becomes a beautiful interactive book — complete with page-turn animations, keyboard/swipe navigation, and full responsiveness.

npm version license


✨ Features

  • 📖 Realistic 3D page-flip animation (CSS transforms, no WebGL needed)
  • 📄 Renders any PDF via PDF.js — no server required
  • 📱 Fully responsive — two-page spread on desktop, single page on mobile
  • ⌨️ Keyboard navigation (← →) and touch swipe support
  • 🎨 Dark & light themes built-in, fully customisable via CSS variables
  • 🧩 Works with React, Vue, vanilla JS, or any framework
  • 🌐 No jQuery, no heavy UI libraries

📦 Installation

npm install pdf-flipbook
# or
yarn add pdf-flipbook

🚀 Quick Start

1 — Vanilla JS (ESM)

<div id="my-book" style="height: 600px;"></div>

<script type="module">
  import PdfFlipbook from 'pdf-flipbook';
  import 'pdf-flipbook/style.css';

  const book = new PdfFlipbook('#my-book', 'https://example.com/document.pdf');
</script>

2 — Vanilla JS (UMD / CDN)

<link rel="stylesheet" href="https://unpkg.com/pdf-flipbook/dist/pdf-flipbook.css">
<script src="https://unpkg.com/pdf-flipbook/dist/pdf-flipbook.umd.js"></script>

<div id="my-book"></div>
<script>
  const { PdfFlipbook } = window.PdfFlipbook;
  new PdfFlipbook('#my-book', '/path/to/file.pdf');
</script>

3 — React

import { useEffect, useRef } from 'react';
import PdfFlipbook from 'pdf-flipbook';
import 'pdf-flipbook/style.css';

export default function BookViewer({ pdfUrl }) {
  const ref = useRef(null);

  useEffect(() => {
    if (!ref.current) return;
    const book = new PdfFlipbook(ref.current, pdfUrl, { theme: 'light' });
    return () => book.destroy();
  }, [pdfUrl]);

  return <div ref={ref} style={{ height: 600 }} />;
}

4 — Vue 3

<template>
  <div ref="container" style="height: 600px" />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import PdfFlipbook from 'pdf-flipbook';
import 'pdf-flipbook/style.css';

const props  = defineProps({ pdfUrl: String });
const container = ref(null);
let book;

onMounted(() => {
  book = new PdfFlipbook(container.value, props.pdfUrl);
});

onUnmounted(() => book?.destroy());
</script>

⚙️ API

new PdfFlipbook(container, pdfUrl, options?)

| Parameter | Type | Description | |-------------|---------------------------|--------------------------------------------| | container | string \| HTMLElement | CSS selector or DOM element to mount into | | pdfUrl | string | URL of the PDF to display | | options | object | Optional configuration (see below) |

Options

| Option | Type | Default | Description | |--------------------|------------|-----------|----------------------------------------------------| | flipDuration | number | 700 | Page-flip animation duration (ms) | | shadowIntensity | number | 0.4 | Shadow opacity at peak flip (0–1) | | maxDpr | number | 2 | Max device-pixel-ratio for canvas quality | | toolbar | boolean | true | Show the bottom toolbar with page info | | theme | string | "dark" | "dark" or "light" | | preloadAhead | number | 2 | Pages to preload ahead of current spread | | onFlip | function | null | Callback: (fromPage, toPage) => void | | onReady | function | null | Callback: () => void — all pages loaded | | onError | function | null | Callback: (error) => void |

Instance Methods

book.next()         // Turn to the next spread
book.prev()         // Turn to the previous spread
book.goTo(pageNum)  // Jump to a specific page (1-indexed)
book.destroy()      // Remove the flipbook and clean up events

Static Properties

// Override the PDF.js worker URL (do this before instantiating):
PdfFlipbook.workerSrc = '/path/to/pdf.worker.min.mjs';

🎨 Theming

The flipbook is fully customisable via CSS variables on the .pfb element:

.pfb {
  --pfb-bg:           #1a1a2e;   /* stage background            */
  --pfb-page-bg:      #fdfaf5;   /* page background colour      */
  --pfb-spine-color:  #0f0f1a;   /* spine colour                */
  --pfb-spine-width:  12px;      /* spine width                 */
  --pfb-accent:       #c9a96e;   /* loader/accent colour        */
  --pfb-flip-z:       600px;     /* perspective depth           */
  --pfb-book-shadow:  0 30px 80px rgba(0,0,0,.6);
}

🌍 CORS & PDF Sources

PDF.js fetches the file from the browser, so the PDF server must serve the correct CORS headers:

Access-Control-Allow-Origin: *

If you control the server, add that header. If you're loading local files during development, serve them via a local HTTP server (not file://).


📋 Browser Support

| Browser | Support | |---------|---------| | Chrome 90+ | ✅ | | Firefox 88+ | ✅ | | Safari 14+ | ✅ | | Edge 90+ | ✅ | | IE 11 | ❌ |


📝 License

MIT © 2024