frond

An EPUB rendering library for TypeScript. Vertical and horizontal treated as equals, verified empirically on Chromium, Firefox and WebKit.

Drop an EPUB here

or

What you will see

  • Read — how the book lays out. Vertical or horizontal is the book's own decision; page turning, chapter jumps, font size, line height, margin and one or two columns are all adjustable. The book takes its colours from this site's theme, up in the masthead — one switch, and the page and the book turn together.
  • Inspect — the facts frond read from this book. The EPUB version, the page progression direction, which navigation document the table of contents came from, which notation declares the cover, and which manifest items are not actually in the package.

This page is a pure browser-side client: the whole flow runs in this tab, with no server involved. EpubBook.open() takes bytes, and frond itself has no download or upload code path at all.

Installing

npm install @yurenju/frond

What you get is plain ES modules plus .d.ts — you need no build step on your side, and no TypeScript. exports opens two entry points: @yurenju/frond/epub (pure TypeScript, zero DOM, runs in Node too) and @yurenju/frond/renderer (needs the DOM).

Using it

<div id="viewer" style="height: 100dvh"></div>

<script type="module">
  import { EpubBook } from "@yurenju/frond/epub";
  import { Renderer } from "@yurenju/frond/renderer";

  const book = await EpubBook.open(await file.arrayBuffer());
  const renderer = await Renderer.attach(
    book,
    document.getElementById("viewer"),
    {
      settings: { fontSize: 20, margin: 32 },
      on: { relocate: (at) => console.log(at.page + 1, "/", at.pageCount) },
    },
  );

  await renderer.next();          // turning a page is an action, not an event handler
  await renderer.goToCfi(saved);  // back to where you left off
</script>

frond does not consume gestures. It states facts (which page we are on, which direction this section laid out in, which section that link points at); "swiping left means next page" is your decision — which is why next() is an action rather than an event handler.

There are no runtime dependencies, so the build output contains not one bare specifier and a browser can import it directly. This page is the proof: it has no bundler, so the two lines above are written here as import … from "./frond/epub/index.js" — the same files tsc emitted, just pointed at by path rather than by package name. The full version is in app.js