Show HN: uWrap.js – A faster and more accurate text wrapping util in < 2KB

121 leeoniya 21 4/4/2025, 3:03:04 PM github.com ↗

Comments (21)

noduerme · 25d ago
I remember getting so deep in the weeds doing this kind of thing in responsively-resized Flash sites, a challenge similar to doing it in canvas. But what at that time I was trying to do (and what I'd really love to see now) was to reproduce runaround text the way you would have it in Quark or Pagemaker (or that newer Adobe program). Justifiable text flow within an arbitrary closed path shape, so you could have multi-column text with adjustable gutters, running with curved borders around scaling embedded graphics. My solutions for that involved a lot of setup/tear-down of invisible text fields relying on native text handling, line by line or paragraph by paragraph, then a lot of remeasuring, and then a lot of optimization to make it more performant. I wrote a similar set of code for handling text in generated PDF files.

As an old school print designer, I would love to see a return to a web with multi-column text on desktop, that reformatted to single column on mobile, and graphics runarounds much more complicated in shape than what a float can do. The art of typographic layout has been lost on the web, because those things are hard. An OS general-purpose engine that could handle layouts like that in any screen size, on Canvas or using absolute positioned divs or generating PDFs, would go a long way toward restoring artistic originality in the "layouting" of online publications.

leeoniya · 25d ago
> As an old school print designer, I would love to see a return to a web with multi-column text on desktop, that reformatted to single column on mobile, and graphics runarounds much more complicated in shape than what a float can do.

this has been possible for quite some time with CSS columns:

https://developer.mozilla.org/en-US/docs/Web/CSS/columns

plus media queries for desktop vs mobile layouts:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_q...

PinkSheep · 25d ago
Without sarcasm, that's great. Now what is there to prevent me from scrolling up and down on a 16:9 display to read the left column of a 10k letter text and then the right column?

I see it has "length" and "min/max-content" properties... even if there are sufficiently many <p>aragraphs (for vertical splitting), inevitably enough paragraphs will be single column due short length. So it becomes a mix and match between "here we were able to split into columns, and here you get a full width single column text flow"?

PS: Oh and don't get me on the CSS used to determine mobile layouts. My 9:16 4K often enough triggers that degraded experience of mobile.

leeoniya · 25d ago
> Now what is there to prevent me from scrolling up and down on a 16:9 display to read the left column of a 10k letter text and then the right column?

if the author decided on exactly 2 columns then, well, that's not a limitation of the tech. css columns support dynamic columns, but obviously the author would then need to specify a max height.

> My 9:16 4K often enough triggers that degraded experience of mobile.

again, sounds like incompetent authorship rather than a tech limitation.

somishere · 25d ago
I can count on one hand the number of times I've needed something like this in the last decade. But I'd also need to count the same number of times I've implemented a less than ideal solution that's ended up in prod. Great work!
leeoniya · 25d ago
we needed something like this for virtualization of the Table panel, data-heavy dropdowns, and long list views in Grafana. so i guess that's a three-in-one?

i looked for the fastest thing i could find but canvas-hypertxt wasnt accurate enough and allocated an array of split lines per item, which is really wasteful when all you need is a line count. i forked it with some optimizations which improved perf by 60% but still suffered from the accuracy issues. so then decided to DIY my own strategy, and uWrap is the result.

Jaxkr · 25d ago
Hi OP! Thanks for sharing.

I don’t totally understand the point of this. Why would you want to use a Canvas renderer for this use case? If you want to render a massive table, apps will render a subset of it on regular HTML elements like EveryUUID [1].

1: https://news.ycombinator.com/item?id=42342382

sroussey · 25d ago
From the introduction:

uWrap exists to efficiently predict varying row heights for list and grid virtualization[1], a technique for UI performance optimization when rendering large, scrollable datasets.

[1] https://www.patterns.dev/vanilla/virtual-lists/

kevlened · 25d ago
EveryUUID's virtual grid can assume every cell is the same height, but it's much more difficult if you assume cells have wrapped text. This is further complicated if you allow grid resizing.
bufferoverflow · 25d ago
What if you have to display it in a webgl environment?
nhatcher · 25d ago
Hmmm, I might have a brilliant usecase for it:

https://github.com/ironcalc/IronCalc/blob/main/webapp/IronCa...

Thanks!

leeoniya · 25d ago
yep, looks like it!
RadiozRadioz · 25d ago
Nice. I plan to use this tool to pre-calculate the letter size ratios for all my fonts, then bake those into my non-JS server code as constants and use a similar wrapping algorithm. Now there's no runtime canvassing. Thanks for this code
tln · 25d ago
You'd need more than just letter widths because of kerning and ligatures, for 100% accuracy. Anyway, fontkit can work on the server and can get individual glyph metrics as well as metrics for a run of glyphs.

https://github.com/foliojs/fontkit

RadiozRadioz · 25d ago
I don't use ligatures and my solution to the keming problem is to overprovision. Thanks for the link though.
leeoniya · 25d ago
yep, uWrap internally builds a lookup table for char pairs that differ significantly in width together from just adding their raw widths.
dawnerd · 25d ago
I guess similarly related, does anyone know of a modern version of fittext? Kinda surprised it’s not a thing yet (that I know of?) to do natively in css.
ForOldHack · 25d ago
Any underlying dependencies we need to know about?
leeoniya · 25d ago
jonahx · 25d ago
<3

To be clear, the use case of this is anything where I have lots of text on a canvas? Like, a canvas based game with thought bubbles or something like that?

leeoniya · 25d ago
it's where you need to know the wrap points of some text given a width of the container. since Canvas does not offer text wrapping, that is one use case, because you have to wrap manually.

my use case is determining the height of a table cell given a specific column width and text that needs to be rendered inside.