steadygray
Even colour,
line by line.
Compositors call it colour — the aggregate grey of a text block. When some lines are denser than others, the paragraph looks uneven. Gray Value measures ink pixel density per line using Canvas and adjusts letter-spacing until the paragraph has even colour throughout.
Live demo
How it works
Canvas pixel sampling
Each line of text is rendered to an off-screen Canvas at the correct font size and weight. The pixel data is read and ink pixels are counted. The ratio of ink to total pixels gives the line's optical density.
Per-line spacing correction
The average density across all lines becomes the target. Each line gets a letter-spacing adjustment proportional to its deviation from the target, clamped to the maxAdjustment limit. The correction is re-run on resize.
Usage
Drop-in component
import { GrayValueText } from '@liiift-studio/steadygray'
<GrayValueText maxAdjustment={0.05} calibrationFactor={2}>
Your paragraph text here...
</GrayValueText>Hook
import { useGrayValue } from '@liiift-studio/steadygray'
const ref = useGrayValue({ maxAdjustment: 0.05, calibrationFactor: 2 })
<p ref={ref}>{children}</p>Vanilla JS
import { applyGrayValue, removeGrayValue, getCleanHTML } from '@liiift-studio/steadygray'
const el = document.querySelector('p')
const original = getCleanHTML(el)
applyGrayValue(el, original, { maxAdjustment: 0.05, calibrationFactor: 2 })
// Later — restore original:
removeGrayValue(el, original)Options
| Option | Default | Description |
|---|---|---|
| targetDensity | 'auto' | Target density ratio (0–1). 'auto' uses the average of all lines. |
| method | 'letter-spacing' | CSS property to adjust: 'letter-spacing' or 'word-spacing'. |
| maxAdjustment | 0.05 | Max spacing correction in em units. |
| tolerance | 0.01 | Minimum density difference required before a correction is applied. Adjustments smaller than this threshold are skipped. |
| calibrationFactor | 2.0 | Strength of the correction. Higher = more aggressive. |
| lineDetection | 'bcr' | 'bcr' reads actual browser layout — ground truth, works with any font and inline HTML. 'canvas' uses @chenglou/pretext for arithmetic line breaking with no forced reflow on resize. Install pretext separately. |