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.
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| Import | What |
|---|---|
glyphline | the core: createHighlighter, motion, shapes, wordAtPoint |
glyphline/pdf | text and geometry of a pdf.js page |
glyphline/dom | text and geometry of HTML |
glyphline/react | <GlyphOverlay>, useDomSource, useAsyncSource, useHighlighter |
glyphline/svelte | <GlyphOverlay>, domText, asyncText, use:highlight |
glyphline/style.css | default 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