Visualizations
495 / 500

495 · Type and image

Line Breaking

Greedy line breaking versus Knuth-Plass, with rivers and the breakpoint graph.

The same paragraph is justified to the same measure twice. Greedy first fit packs each line as full as it can and never looks back, so an unlucky long word leaves a line full of holes. Knuth-Plass, the algorithm inside TeX, gives every line an adjustment ratio r, a badness of 100|r|^3 and demerits of (10 + badness)^2, then finds the set of breaks with the fewest total demerits as a shortest path through a graph of feasible breakpoints, relaxing its tolerance when no path exists. Stretched spaces are tinted red, rivers of aligned gaps are traced in blue, each line's badness sits in the margin, and the graph underneath draws every feasible line as an arc with the optimal path in gold and greedy's choices in red.

Try it. Drag the blue handles (or click inside a column) to set the column width and watch both paragraphs reflow. Hover a line to see its ratio, badness and demerits and its arc in the graph. Enter or Space switches the text, R toggles rivers, and the arrow keys nudge the width. Left alone, the measure slowly breathes.

  • Knuth-Plass dynamic programming
  • Boxes, glue and badness
  • River detection across lines
  • Cached measureText layout

View the source · one module, plus a small shared runtime for sizing, the animation loop and input

Build your own

Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.

Build a side-by-side comparison of greedy line breaking and the Knuth-Plass algorithm with JavaScript and the HTML canvas element. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.

Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window. Paint it an off-white paper color.
- Put a public domain paragraph in a string (for example the last paragraph of Darwin's Origin of Species) and measure every word once with ctx.measureText in a serif font, caching the widths.
- Model each space as glue: natural width w, able to stretch by w/2 or shrink by w/3. For a line, the adjustment ratio r is the missing width divided by the total stretch (or the excess divided by the shrink), badness is 100|r|^3, and demerits are (10 + badness)^2. The last line is set ragged with badness 0.
- Greedy: put as many words on each line as fit at natural spacing.
- Knuth-Plass: let best[j] be the fewest total demerits for setting the first j words. For each j, try every earlier break i whose line i..j can be set with r >= -1 and badness under a tolerance, keep the cheapest, and walk back from the end to recover the breaks.
- Draw both paragraphs fully justified in two columns of the same width, with each line's badness written in the left margin.

Once that works, make it beautiful:
- Add a draggable handle that sets the column width so both paragraphs reflow live, easing words to their new positions.
- Tint stretched spaces red, and trace rivers: gaps that overlap the gap below them for three or more lines.
- Under the columns, draw the breakpoint graph: each possible break as a dot on a line, each feasible line as an arc, the optimal path highlighted and greedy's breaks drawn below.

Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as adding hyphenation points with a penalty, Knuth's fitness classes for adjacent lines, or an emergency stretch pass for very narrow columns.
PreviousWatch MovementAn exploded mechanical watch whose Swiss lever escapement is simulated, not animated. NextChord OrbifoldTymoczko's geometry of chords: a twisted prism and a Mobius strip you can hear.

Related visualizations

  • Compression EchoesType and image LZ77 compresses a poem while every back-reference loops back over the page in gold.
  • Huffman GardenAlgorithms Letter frequencies sprout into a Huffman tree drawn as a botanical plate.
  • One Line PortraitType and image Thousands of stipple dots become one unbroken pen line, untangled by 2-opt.
  • Glyph RasterizerType and image Letters become pixels: exact-area scanline coverage, subpixel RGB and hinting.
  • Nonogram ForgeAlgorithms Paints a pixel picture, proves its clues have one answer, then solves it line by line.
  • Diff GraphAlgorithms Myers' O(ND) diff, the algorithm behind git diff, as a search through the edit graph.
  • Syntax RailroadType and image A recursive descent parser drives a train through railroad syntax diagrams.
  • Temperature GardenMachine learning Greedy, beam, top-k, nucleus and temperature sampling grown as a botanical plate.
  • Seam CarvingType and image Content-aware resizing: seams peel away and the lighthouse stays intact.

Use ← and → to move between demos. While the canvas has focus, keys go to the demo instead.

← More from Emergent Mind Labs