Skip to content

Reference

import {
chop,
layoutText,
defineFont,
select,
measureFontMetrics,
clearPretextCache,
} from '@tonybonet/chop'
ExportPurpose
chop(source)Project animation-ready DOM elements from a selector or HTMLElement.
layoutText(text, font, options)Measure text and return plain layout handles.
defineFont(cssFont)Create a typed CSS font descriptor.
select(handles, query)Filter handles for stagger and composition logic.
measureFontMetrics(font)Read browser-derived font metrics.
clearPretextCache()Clear Pretext and font metric caches.
const title = chop('.headline')

source can be a selector or an HTMLElement. The returned ChopElements array is the word elements.

title
title.lines
title.chars
title.paragraphs
title.meta
title.metrics
title.relayout()
title.destroy()

Removed API surface:

  • no title.words
  • no title.elements(unit)
  • no title.select
  • no by option
interface ChopElements extends Array<HTMLElement> {
readonly lines: readonly HTMLElement[]
readonly chars: readonly HTMLElement[]
readonly paragraphs: readonly HTMLElement[]
readonly meta: ChopMeta
readonly metrics: ChopFontMetrics | null
relayout(): void
destroy(): void
}

Words project immediately. Lines, characters, and paragraphs project lazily on first access.

const result = layoutText('Hello world', '700 48px Inter', {
width: 420,
whiteSpace: 'normal',
})

Use this when you want measured layout data without DOM projection.

interface ChopResult {
lines: readonly ChopHandle[]
words: readonly ChopHandle[]
chars: readonly ChopHandle[]
paragraphs: readonly ChopHandle[]
lineSegments: readonly LineSegment[]
meta: ChopMeta
}
const font = defineFont('700 48px Inter')
const result = layoutText('Typed font input', font)

defineFont() validates and wraps a CSS font shorthand string. Passing a string directly to layoutText() also works.

select(result.chars, { mode: 'even' })
select(result.words, { mode: 'first', count: 3 })
select(result.chars, { mode: 'range', from: 0.25, to: 0.75 })
select(result.chars, {
mode: 'grouped',
by: 'word',
query: { mode: 'last', count: 1 },
})

Supported query modes:

ModeShape
slice{ mode: 'slice', from, to? }
every{ mode: 'every', every, offset? }
odd{ mode: 'odd' }
even{ mode: 'even' }
first{ mode: 'first', count }
last{ mode: 'last', count }
at{ mode: 'at', indices }
middle{ mode: 'middle', count? }
range{ mode: 'range', from, to }
grouped{ mode: 'grouped', by, query }
where{ mode: 'where', predicate }

Use meta when UI controls need counts without querying the DOM manually.

interface ChopMeta {
readonly lineCount: number
readonly wordCount: number
readonly charCount: number
readonly paragraphCount: number
readonly height: number
readonly naturalWidth: number
readonly preserveLineBreaks: boolean
readonly preserveSpaces: boolean
readonly keepWordsTogether: boolean
readonly fontMetrics: ChopFontMetrics | null
}
interface ChopHandle {
id: string
unit: 'line' | 'word' | 'char' | 'paragraph'
text: string
index: number
lineIndex?: number
wordIndex?: number
paragraphIndex?: number
isWhitespace: boolean
start: { segmentIndex: number; graphemeIndex: number }
end: { segmentIndex: number; graphemeIndex: number }
rect?: ChopRect
}

Handles are layout records. They are useful for custom renderers, selection logic, and tests.

interface ChopTextOptions {
width?: number
whiteSpace?: 'normal' | 'pre-wrap'
wordBreak?: 'normal' | 'keep-all'
locale?: string
lineHeight?: number
letterSpacing?: number
}

lineHeight and letterSpacing are absolute pixels. DOM mode infers these from the element. Pure mode receives them through options.

Projected elements receive stable data attributes and CSS custom properties.

UnitAttributeMain index variable
Line[data-chop-line]--chop-line-index
Word[data-chop-word]--chop-word-index
Character[data-chop-char]--chop-char-index
Paragraph[data-chop-paragraph]--chop-paragraph-index
[data-chop-char] {
animation-delay: calc(var(--chop-char-index) * 32ms);
}
MethodUse it for
relayout()Recompute after text, font loading, or container width changes.
destroy()Remove the overlay and restore the source element styles.
clearPretextCache()Clear process-level measurement caches in long-lived sessions.
OldNew
chop(node, { by: ['word'] }).elements('word')chop('.headline')
instance.elements('line')title.lines
instance.elements('char')title.chars
instance.elements('paragraph')title.paragraphs
instance.meta()title.meta
instance.refresh()title.relayout()
chop(text, font)layoutText(text, font)