The “Slug” GPU Font Rendering algorithms have been opensourced, so I ported it to js, and threejs!
Demo:
Repo:
Screenshot:
The “Slug” GPU Font Rendering algorithms have been opensourced, so I ported it to js, and threejs!
Demo:
Repo:
Screenshot:
Whoa, whats the story behind this? Havent been followinc what Lengyel is doing.
It’s an alternative to bitmap/sdf fonts. It takes the font curve data, and encodes it in a texture, which is then used on the GPU to render the font directly…
It has sharp corners and smooth curves at large magnification, and decent behavior at minification.
And Eric Lyengel has just graciously open sourced the algorithm, (after licensing it commercially for the last 10 years.)
I mashed together these 2 libraries and ported them to JS/THREE:
Original algo:
A library that loads a TTF font, and generates a binary format (.sluggish) for it:
I made a ShaderMaterial version, and then a version that injects into StandardMaterial (and other material types probably though less tested…)
The Injected version obeys lighting/casts shadows etc.
Characters use ~quad per glyph.
Article here:
https://terathon.com/blog/decade-slug.html
More info:
This is really cool, a neat alternative to bitmap or SDF fonts. Encoding the font curve data into a texture and rendering it on the GPU keeps things sharp at large sizes and still readable when small.
The fact that it can inject into StandardMaterial and work with lighting and shadows makes it feel like it really belongs in a 3D scene, not just floating on top. Using a quad per glyph is simple but effective, and it’s nice to see the original algorithm from Eric Lyengel finally available open source.
I like that it gives you high-quality curves without the usual artifacts you get with bitmap fonts, and it seems flexible enough to integrate into different material setups. Curious how it handles very dense text or long paragraphs in real-time scenes.
Thank you! Yeah it’s a neat algorithm.. and I think could be very useful for games where you need virtual labels for things. Rebuilding the strings is fast. I suspect it’s not the cheapest to render.. but the sample text in the demo is the whole main.js file in one giant string.
The .sluggish files seem to be about half the size of the .ttf, so that’s a bit of a win.
Thanks for checkin it out! ![]()
This is really neat and beautifully implemented. Can’t wait to play with it. Thank you.
I had always felt pain using texts in 3D - usually approaches were not universal - some failed at close-ups, others failed at distant/tiny texts. Slugs appears to resolve both extremes, will have to test it to see how it is performance-wise. Generally my texts are static (e.g. labels), but sometimes I have dynamic texts (e.g. some numeric indicator or timer).
Yeah. there is probably a lot of room for improvement in my implementation/port. My api creates a geometry per text.. I’d like to make a more general single geometry that can contain multiple strings at diferrent transforms. there is a window size that is tuned for antialiasing but might not be calculated dynamically properly.. which manifests as something like blur at large magnification, but I mostly just wanted to get it working so people could play with it.
There’s also a performance optimization mentioned in the original slug source, but which was disabled in the the .sluggish implementation, which uses another texture indirection to cull which curves have to be evaluated.. It might have been a de-opt in sluggishes case.. but I included it or something like it for completeness.
This is a big win - not just because it’s a technical improvement, but because you built a system that can be properly preloaded prior to the initial render (unlike Troika text).
Wild.. someone took the initiative and ported it to TSL: https://x.com/_Ardetya/status/2039945598737219998?s=20
![]()
awesome! this looks great! WICG also seem to be working on something cool down a similar vein… HTML-in-canvas
No i meant, he was pretty aggressive when licensing his stuff and collecting royalties. Last thing i expected to be open sourced.
BTW i totally needed to group them by mesh so i could batch them and move them in groups for a tag system. I vibed it all though ![]()