import { layoutMarkupLines, parseMarkup, positionMarkupLines } from '@datamoc/mw_games/two-d/ui';
const spans = parseMarkup('Take <b>two</b> coins<img>coin.png</img>');
const measure = (piece: { text: string; image?: string }) =>
piece.image !== undefined ? 16 : piece.text.length * 8;
const lines = layoutMarkupLines(spans, measure, 120);
const runs = positionMarkupLines(lines, { measure, maxWidth: 120, lineHeight: 16 });
console.log(runs.map((run) => run.span.image ?? run.span.text).join(''));
Positions already-laid-out lines into a flat list of placed runs, one per span, so a canvas backend draws each span as its own
Text2D(or an image as its own sprite) at the reportedx/y. This is the halflayoutMarkupLinesdeliberately leaves out: it decides which spans share a line, this decides where on the line each one lands.Direction is what makes the two backends equivalent rather than merely identical in text: an
rtlline places its first (logical) span at the right edge and flows left from it, while anltrline flows right from the left edge, so the same spans read in the language's own order on either side. Alignment then moves the whole line withinmaxWidth, defaulting to the direction's natural edge ('right'forrtl,'left'forltr). A line wider thanmaxWidthis not clipped - the same "a single long word still renders" rulelayoutMarkupLinesalready keeps - it simply starts left of zero.