glyphline

Introduction

glyphline draws text highlights that sit on the glyphs, a sentence outline that morphs and a word cursor that glides, for pdf.js pages and HTML.

The page below is a PDF rendered by pdf.js. glyphline draws the yellow sentence outline and the amber word cursor over it. Press Read or click any word.

Click a word to start there
Loading the page…

A real PDF page rendered by pdf.js. The cursor follows a timer here (no audio); in a reader it follows the voice. Text stays selectable: drag across it.

What it draws

  • A sentence outline. A range over several lines is one rounded shape, not a stack of rectangles. Line ends of justified text are snapped so the edge stays straight, and a range that crosses columns becomes one shape per column.
  • A word cursor. Along a line it stretches toward the next word and contracts onto it; to another line it travels with the same motion; from nothing it pops in. Interrupting mid-flight continues from what is on screen.
  • The selection. The reader's selection drawn as one shape that follows the glyphs, optionally snapped to whole words.
  • Marks. Static ranges (notes, search hits) with your own classes.

Everything is an <svg> overlay with pointer-events: none, so the text underneath stays selectable and clickable.

Where positions come from

A highlight is only as good as its boxes. For HTML, glyphline asks the browser (Range.getClientRects). For PDF pages it walks the page's glyph stream with the embedded fonts' advance widths, the same way pdf.js paints the canvas, and falls back per text item to the pdf.js text layer where it cannot. The accuracy page shows the difference and how it was measured.

One package

bun add glyphline
ImportWhat
glyphlinethe core: createHighlighter, motion, shapes, wordAtPoint
glyphline/pdftext and geometry of a pdf.js page
glyphline/domtext and geometry of HTML
glyphline/react<GlyphOverlay>, useDomSource, useAsyncSource, useHighlighter
glyphline/svelte<GlyphOverlay>, domText, asyncText, use:highlight
glyphline/style.cssdefault colours

The core has no dependencies. react, svelte and pdfjs-dist are optional peers: install only what your app uses.

Browser support

Any browser with Intl.Segmenter and ResizeObserver. The automated tests run in Chromium.

Made by Lucas Piera

On this page