Concepts#
The vocabulary humument uses, and how the pieces fit together. Every term
here maps to a concrete type in src/types.ts
and a section of the Library API.
Coordinate system#
All coordinates are pixel coordinates on the normalized page image, which is
1400 × 2100 grayscale (see humument-images). The origin
is the top-left, with the y-axis pointing down — the same convention as
an HTML <canvas>. A bounding box is
{ x0, y0, x1, y1 } (Bbox), and a point is { x, y } (Pt).
Because the word boxes are in this image's pixel space, drawing over the page is
1:1: size your canvas to H.page.width × H.page.height, draw the page scan at
(0, 0), and every word/gutter/river coordinate lands in the right place.
Pages#
A page is one printed leaf of the 1892 edition, numbered 1–367 — the same
number Tom Phillips used, because this edition maps page-for-page onto
A Humument. Humument.load({ page }) returns everything for one page:
H.page (dimensions, the type-block body bbox, the OCR-valid region, and the
image URL) plus the words and whitespace geometry below.
Words and lines#
A word (Word) is one OCR'd token: its text, its pixel box
(x0,y0,x1,y1), a 0-based lineIdx within the page, OCR confidence, split-off
prefix/suffix punctuation, and NLP annotations — pos (spaCy UPOS tag),
lemma, freq (modern-corpus frequency), rarity (normalized log-inverse
frequency, higher = rarer), and the isContent / isConnective flags.
H.words is the page's words sorted by (lineIdx, x0); H.lines is the same
words grouped into lines. These annotations are what the chunker scores on.
Chunks#
A chunk is a short, reading-order-adjacent phrase — the candidate "kept
words" of an erasure. The chunker (H.chunks / H.selectChunks) matches two
shallow part-of-speech patterns greedily, longest-first:
NP := ADP? (DET|PRON|VERB)? (ADJ|ADV|NUM)* (NOUN|PROPN)+
VP := ADV* (VERB|AUX) (ADJ|ADV|NUM|AUX|PART)*
so a chunk reads as a little noun or verb phrase ("the embracing thoughts",
"quietly waited"). selectChunks then scores each phrase (favoring rarer words
and 2–3-word phrases ending on a noun, penalizing clichés) and picks the top few,
spread across the page by line distance so they don't clump. See
Chunks.
Whitespace geometry#
The pipeline precomputes the empty space between the type so you can route rivers without any image analysis at runtime. Three related structures:
- Gutters (
H.gutters) — the channels of whitespace. AGutteris either a horizontal inter-line gap (h_line) or a vertical intra-line slit (v_slit), described by a centre-linepolyline, its narrowestminWidth, and a heuristicriverScore(how river-like it looks). - Docks (
H.docks, aMap<wordId, Dock>) — for each word, how much empty space it has in each direction (breathing*), which direction has the most slack, and the ports (compass-tagged entry/exit points) into the surrounding gutters. - Navigation graph (
H.graph) — a graph whose nodes are gutter/port positions and whose edges are the traversable whitespace, weighted by distance. This is what the Dijkstra river pathfinder walks.
See Pages & Words for the exact shapes.
Rivers#
A river is a path of whitespace connecting two kept words — the hand-drawn
line Phillips runs between the words he keeps. humument finds them two
ways (Rivers):
H.river.between(a, b)— Dijkstra over the whitespace graph. Constrained to real gutters, cheap, and returns aChannelSegment(an ordered polyline plus the gutter id used for each span, so a renderer can vary stroke width).H.river.flow(a, b, opts)— a greedy walk through a Perlin noise field, biased toward the target and away from obstacle words. Organic, and a good fallback when the graph can't connect two words (island gutters).
Blobs, balloons, banners, and ribbons#
The geometry helpers turn words, bounding boxes, and river paths into point arrays you can render with any 2D API:
- A blob (
H.geom.blob, 0.2.0) is the faithful A Humument balloon: a tight hull hugging every word, with consecutive phrases fused into one organic silhouette by tapered necks that flare where they attach. Built as a signed-distance union traced with marching squares. Multi-line phrases come out as stepped, concave hulls — the shape Phillips actually cuts. - A balloon (
H.geom.balloon) is a simple wobbly closed loop around a bounding box — always convex, and much cheaper than a blob; use it for animated, per-frame drawing. - A banner (
H.geom.banner, 0.2.0) is an angular pennant strip with square, pointed, or swallowtail-notched ends — the paper-ribbon dialogue shapes of p15. - A channel / ribbon (
H.geom.channel) turns a riverChannelSegmentinto a thick wavy band that meanders within its gutter.
Both are driven by cheap seedable value-noise (H.noise, H.random), so a
given seed always redraws the same hand-drawn wobble. See
Geometry and Noise & Random.
Chapters#
A chapter (ChapterRef) is a page whose top line reads "CHAPTER <Roman>".
Humument.catalog.listChapters() returns them as { pageNum, label, roman },
the chapter taken to start on that page and run until the next.