When the Slug patent was released to the public domain, I put together[1] Snail[2], a Slug implementation in Zig.
One thing I found was that it was tough to get small text to look good with some fonts. TrueType fonts often have bytecode that tweaks curve points to better fit the pixel grid at a particular size. Part of the pitch for Slug is that it doesn't require per-size glyph prep, so Slug text is just unhinted.
As monitors have gotten denser, the major font renderers have moved away from bytecode hinting, either toward auto-hinting (ignore the bytecode, look at the outline, and decide what to do) or toward no hinting at all.
Snail has GPU auto-hinting that tries to replicate a lot of that, so I could have hinted text without per-size prep. It precomputes knots at various glyph features, and the shader then moves the knots to stretch/squeeze parts of the glyph. It's not perfect (especially for serif fonts!), benefits from per-font tuning, and focuses on Latin glyphs (pretty much always draws CJK glyphs unhinted because they're too complex for the current shaders to handle). Also, cases where you want hinting and wouldn't be better served by just scissoring prepared bitmaps aren't all that common. It also includes a TrueType VM, for cases where the per-size cost is acceptable (DejaVu Mono looks decent with the auto-hinter, but it has phenomenal hinting bytecode).
It was a lot of fun to put together, I learned a lot, and as far as I know the auto-hinter is unique among Slug implementations. Slug is a very cool algorithm.
[1] through high-effort delegation to Claude
[2] https://github.com/psyclyx/snail - includes some diagrams (made with Snail!) that explain most of the prep/rendering of a glyph with Slug
GuB-42
I once implemented SDF text rendering. To me, the thing I liked the most about this technique it how easy it is to add effects on top. With a few lines of shader code, I had outlines and softening of the edges (antialiasing). I didn't try the MSDF variant, as I didn't mind corners not being sharp when scaled up, so I don't know if these effects break on MSDF.
Slug doesn't seem to support any of these, it is just "for a given point, am I in or am I out?", but it doesn't tell you by how much, which is great on really high resolution displays and large sizes, but you would lose the ability to do the kind of effects you can do with SDFs, and have to deal with antialiasing separately.
show comments
mattdesl
I've also been working on a GPU curve renderer, Windfoil, based on a formulation that Fable 5 originally proposed to me during a directed search [1]. It is similar in some ways to Slug, not always as fast, but uses less shader storage (single band instead of two) and produces higher quality anti-aliasing i.e. closer to a box-filtered ground truth.
It may be of interest to some game/graphics devs here...
This article has some inaccurate information since MSDF atlas doesn't have to be baked statically, so the "CJK character means huge atlas" is not really an issue if you can async upload them to the atlas.(Async outline extraction is a bit harder for C libraries, so that's why the pipeline is mostly restricted to atlas upload).
The other thing is MSDF rendering is fairly cheap and can be done on the CPU quite easily without GPU shaders, the atlas generation/upload is the expensive part, but it's a one-time cost per character per font as the atlas is just a normal bitmap texture file, MSDF text have sharp edges at most zoom resolutions, and the small size text is better handled with simple CPU raster anyways.
I really failed to see significant benefit of using Slug over MSDF + raster fallback for small fonts, it's definitely more exact, but I'm not sure if the marginal resolution benefit is worth it over much more complicated GPU dependent rendering, so I'd really want to test it out myself when I have the time over taking the word of an obviously AI written article for it.
show comments
exDM69
As hobby project, I wrote a font rasterizer algorithm (two algorithms actually) that produces pixel perfect anti-aliased images (like Slug) using a similar but different algorithm. Rather than using Slug's clever root classifier for Bezier curves, I subdivide Bezier curves into monotonic sections where evaluating the winding number is much simpler and can be done in parallel for a group of pixels. It works nicely on GPU with warp/wave/subgroup operations and CPU using SIMD.
At first glance, subdividing the Bezier curves sounds like a bad idea (more Beziers to rasterize) but it opens doors for some parallelism, and most Bezier curves that appear in fonts are monotonic in the first place (so the increase is very modest). This was inspired by this entertaining but not very serious video about font rasterization [0].
The first parallelism optimization is checking against the curve bounding box vs. a rectangular (in uv-space) region of pixels, and this can quickly determine if the Bezier needs to be evaluated in the first place. This can be done per GPU warp.
The second optimization works only for rectilinear transformation (no rotation, skew or perspective). Solving the quadratic equation involves a square root and a division (which alone are >30% of the computation), which can be computed for each row and column of pixels instead of for each pixel (2n instead of n^2).
Both optimizations rely on mathematical invariants of monotonicity, ie. the derivative of the Bezier curve must be non-zero. All Bezier curves can be robustly subdivided into monotonic sections using de Casteljau's algorithm.
My simple benchmarks compare favorably to Slug on the GPU and to "fast" rasterization algorithms on the CPU (which is an order of magnitude faster than "fancy" rasterization algorithms with hinting etc).
Unfortunately there are so many hobby projects and so little time. All I have is messy shaders that draw individual characters and a few benchmarks to see how quickly (and something similar for the CPU). Going from there to a complete text rendering system would be a lot of work. Writing a more detailed article with illustrative code examples is something I'd want to do but haven't gotten around to.
If you want to offer words of encouragement or geek out about rasterization algorithms, I welcome any input.
Man, I am getting incredibly tired of reading LLM-generated writing
show comments
Const-me
“What makes glyphs hard” Another reason is hinting. Traditional text renderers like FreeType are aware of the pixel grid and they adjust the curves slightly, snapping them to that grid. For all methods in the article quite hard to do on GPUs.
“Chinese, Japanese, and Korean have tens of thousands of glyphs, and baking all of them at several sizes is a memory disaster” One possible solution is dynamic atlas built on CPU for visible glyphs only.
“The distance-field panels notch, where interpolating between stored samples no longer matches the true curve” Can’t it be fixed in the shader, using screen-space derivatives of the SDF? I think in theory, SDF value for pixel center combined with screen-space gradient vector of that number delivers enough data to compute partial coverage for the pixels on the edge.
flohofwoe
Here's a simple Slug rendering example on top of sokol_gfx.h:
There's quite a bit of helper code plus stb_truetype.h and stb_ds.h under the hood to parse TTF files and crunch the TTF curve data into the runtime format expected by the Slug shader (this stuff should better go into an offline asset pipeline tool):
...the list of external dependencies is a bit scary for a small self-contained sample though (Harfbuzz, SheenBidi, libunibreak, etc...), but that basically shows that proper international text rendering is really damn hard, even when trying to simplify the code as much as possible.
show comments
seanw265
Interesting read. Text rendering techniques have always fascinated me.
I'm a bit confused because at some points it seems like the author is conflating "tessellation" and "Rive". Are they the same thing? As an uneducated reader, my understanding would be that Rive is an implementation of a renderer using the tessellation approach. But surely a generic tessellation approach could support perfect arbitrary transformations even if Rive doesn't?
Maybe there's something I'm missing.
Also, a nitpick: in the "head to head" section, the author highlights Slug's better performance in green for the entries that it wins (or ties). For the sake of fairness, shouldn't we highlight the winners in every category? Surely Rive's "low" memory usage beats Slug's "moderate"?
pavlov
> "In 2017 Eric Lengyel published an algorithm, called Slug, that stopped dodging. It renders glyphs directly from their outlines in the fragment shader, with no texture atlas and no per-frame tessellation. Lengyel patented it in 2019, and on March 17, 2026 he dedicated that patent to the public domain."
It's nice that he gave the patent to public domain, but this is not how patents are supposed to work. You can't patent something two years after it was already published.
I'm guessing he actually filed for a patent before publishing, and the article should read: "Lengyel was granted a patent for it in 2019"
It's an AI-written article, so maybe it's not reasonable to expect it to be consistent on this level...
show comments
jayd16
Is there a runtime comparison of the shaders needed? Seems like you might have to do a lot of texture sampling if you have to walk the ray through the data but maybe there's a trick?
MSDF is pretty much just the target texel in question plus the surrounding samples in a way the GPU can do entirely upfront before the math starts. (M)SDF glyphs also play nicely with mip mapping and I would think this Slug algorithm needs uncompressed data. Maybe that doesn't matter because you just don't scale the data ever?
show comments
rezmason
Slug looks impressive!
The project I'm most known for is basically an MSDF shader with a bloom pass. It serves my needs 100%, though if I expand to support arbitrary text, I may reach for Slug.
The one issue with MSDF I want to raise is, it seems everybody uses the same msdfgen texture creation program from Viktor Chlumský's master's thesis 11 years ago. I wish there were other implementations. Who ever heard of a graphics technique that was only ever programmed once, and then used everywhere without substantial iteration? We need to de-XKCD-2347 MSDFs for everyone's sake, including and especially Chlumský.
show comments
sirwhinesalot
There's another GPU text rendering algorithm missing from the comparison: Rook & Possum's Scanline Sweeper:
Sean Barret (creator of the stb public domain libraries) independently invented a CPU-based implementation of the same idea, used in stb_truetype.
logdahl
I knew the second Eric posted about releasing Slug to the public domain we'd get 100s of "OpenSlug" slopped-up. Will be interesting to see which implementation will win or if Slug will keep being a thing.
show comments
bel8
MSDF looks better than Slug for me in the first example.
But slug wins in perspective in my eyes.
I use MSDF to render crisp text in my webgl hobby game. Hope to publish it with source code when I get the time.
thanks for sharing the article. I'll take a deeper look at it later.
show comments
hncbw02z5a
MSDF corners gave me trouble til I bumped the distance range at small sizes.
LoganDark
> By Chris Hanson
What a name!
(Skipped the rest of the article cause it's AI.)
reactordev
Excellent write up. The cited references are on point too. Eric Lengyel is a legend.
Slug mentioned!
When the Slug patent was released to the public domain, I put together[1] Snail[2], a Slug implementation in Zig.
One thing I found was that it was tough to get small text to look good with some fonts. TrueType fonts often have bytecode that tweaks curve points to better fit the pixel grid at a particular size. Part of the pitch for Slug is that it doesn't require per-size glyph prep, so Slug text is just unhinted.
As monitors have gotten denser, the major font renderers have moved away from bytecode hinting, either toward auto-hinting (ignore the bytecode, look at the outline, and decide what to do) or toward no hinting at all.
Snail has GPU auto-hinting that tries to replicate a lot of that, so I could have hinted text without per-size prep. It precomputes knots at various glyph features, and the shader then moves the knots to stretch/squeeze parts of the glyph. It's not perfect (especially for serif fonts!), benefits from per-font tuning, and focuses on Latin glyphs (pretty much always draws CJK glyphs unhinted because they're too complex for the current shaders to handle). Also, cases where you want hinting and wouldn't be better served by just scissoring prepared bitmaps aren't all that common. It also includes a TrueType VM, for cases where the per-size cost is acceptable (DejaVu Mono looks decent with the auto-hinter, but it has phenomenal hinting bytecode).
It was a lot of fun to put together, I learned a lot, and as far as I know the auto-hinter is unique among Slug implementations. Slug is a very cool algorithm.
[1] through high-effort delegation to Claude [2] https://github.com/psyclyx/snail - includes some diagrams (made with Snail!) that explain most of the prep/rendering of a glyph with Slug
I once implemented SDF text rendering. To me, the thing I liked the most about this technique it how easy it is to add effects on top. With a few lines of shader code, I had outlines and softening of the edges (antialiasing). I didn't try the MSDF variant, as I didn't mind corners not being sharp when scaled up, so I don't know if these effects break on MSDF.
Slug doesn't seem to support any of these, it is just "for a given point, am I in or am I out?", but it doesn't tell you by how much, which is great on really high resolution displays and large sizes, but you would lose the ability to do the kind of effects you can do with SDFs, and have to deal with antialiasing separately.
I've also been working on a GPU curve renderer, Windfoil, based on a formulation that Fable 5 originally proposed to me during a directed search [1]. It is similar in some ways to Slug, not always as fast, but uses less shader storage (single band instead of two) and produces higher quality anti-aliasing i.e. closer to a box-filtered ground truth.
It may be of interest to some game/graphics devs here...
[1] https://github.com/texel-org/windfoil-algorithm
This article has some inaccurate information since MSDF atlas doesn't have to be baked statically, so the "CJK character means huge atlas" is not really an issue if you can async upload them to the atlas.(Async outline extraction is a bit harder for C libraries, so that's why the pipeline is mostly restricted to atlas upload).
The other thing is MSDF rendering is fairly cheap and can be done on the CPU quite easily without GPU shaders, the atlas generation/upload is the expensive part, but it's a one-time cost per character per font as the atlas is just a normal bitmap texture file, MSDF text have sharp edges at most zoom resolutions, and the small size text is better handled with simple CPU raster anyways.
I really failed to see significant benefit of using Slug over MSDF + raster fallback for small fonts, it's definitely more exact, but I'm not sure if the marginal resolution benefit is worth it over much more complicated GPU dependent rendering, so I'd really want to test it out myself when I have the time over taking the word of an obviously AI written article for it.
As hobby project, I wrote a font rasterizer algorithm (two algorithms actually) that produces pixel perfect anti-aliased images (like Slug) using a similar but different algorithm. Rather than using Slug's clever root classifier for Bezier curves, I subdivide Bezier curves into monotonic sections where evaluating the winding number is much simpler and can be done in parallel for a group of pixels. It works nicely on GPU with warp/wave/subgroup operations and CPU using SIMD.
At first glance, subdividing the Bezier curves sounds like a bad idea (more Beziers to rasterize) but it opens doors for some parallelism, and most Bezier curves that appear in fonts are monotonic in the first place (so the increase is very modest). This was inspired by this entertaining but not very serious video about font rasterization [0].
The first parallelism optimization is checking against the curve bounding box vs. a rectangular (in uv-space) region of pixels, and this can quickly determine if the Bezier needs to be evaluated in the first place. This can be done per GPU warp.
The second optimization works only for rectilinear transformation (no rotation, skew or perspective). Solving the quadratic equation involves a square root and a division (which alone are >30% of the computation), which can be computed for each row and column of pixels instead of for each pixel (2n instead of n^2).
Both optimizations rely on mathematical invariants of monotonicity, ie. the derivative of the Bezier curve must be non-zero. All Bezier curves can be robustly subdivided into monotonic sections using de Casteljau's algorithm.
My simple benchmarks compare favorably to Slug on the GPU and to "fast" rasterization algorithms on the CPU (which is an order of magnitude faster than "fancy" rasterization algorithms with hinting etc).
Unfortunately there are so many hobby projects and so little time. All I have is messy shaders that draw individual characters and a few benchmarks to see how quickly (and something similar for the CPU). Going from there to a complete text rendering system would be a lot of work. Writing a more detailed article with illustrative code examples is something I'd want to do but haven't gotten around to.
If you want to offer words of encouragement or geek out about rasterization algorithms, I welcome any input.
[0] https://www.youtube.com/watch?v=SO83KQuuZvg Sebastian Lague - Coding Adventures: Rendering text.
Man, I am getting incredibly tired of reading LLM-generated writing
“What makes glyphs hard” Another reason is hinting. Traditional text renderers like FreeType are aware of the pixel grid and they adjust the curves slightly, snapping them to that grid. For all methods in the article quite hard to do on GPUs.
“Chinese, Japanese, and Korean have tens of thousands of glyphs, and baking all of them at several sizes is a memory disaster” One possible solution is dynamic atlas built on CPU for visible glyphs only.
“The distance-field panels notch, where interpolating between stored samples no longer matches the true curve” Can’t it be fixed in the shader, using screen-space derivatives of the SDF? I think in theory, SDF value for pixel center combined with screen-space gradient vector of that number delivers enough data to compute partial coverage for the pixels on the edge.
Here's a simple Slug rendering example on top of sokol_gfx.h:
via WebGPU backend: https://floooh.github.io/sokol-webgpu/slug-sapp.html
via WebGL2 backend: https://floooh.github.io/sokol-html5/slug-sapp.html
There's quite a bit of helper code plus stb_truetype.h and stb_ds.h under the hood to parse TTF files and crunch the TTF curve data into the runtime format expected by the Slug shader (this stuff should better go into an offline asset pipeline tool):
https://github.com/floooh/sokol-samples/blob/master/libs/slu...
...the actual text rendering code is also taking a couple of shortcuts, e.g. no kerning, no right-to-left, and also no text shaping.
There's also a new and complete text rendering stack by Mikko Mononen called Skribidi (AFAIK not based on Slug though):
https://github.com/memononen/Skribidi
...the list of external dependencies is a bit scary for a small self-contained sample though (Harfbuzz, SheenBidi, libunibreak, etc...), but that basically shows that proper international text rendering is really damn hard, even when trying to simplify the code as much as possible.
Interesting read. Text rendering techniques have always fascinated me.
I'm a bit confused because at some points it seems like the author is conflating "tessellation" and "Rive". Are they the same thing? As an uneducated reader, my understanding would be that Rive is an implementation of a renderer using the tessellation approach. But surely a generic tessellation approach could support perfect arbitrary transformations even if Rive doesn't?
Maybe there's something I'm missing.
Also, a nitpick: in the "head to head" section, the author highlights Slug's better performance in green for the entries that it wins (or ties). For the sake of fairness, shouldn't we highlight the winners in every category? Surely Rive's "low" memory usage beats Slug's "moderate"?
> "In 2017 Eric Lengyel published an algorithm, called Slug, that stopped dodging. It renders glyphs directly from their outlines in the fragment shader, with no texture atlas and no per-frame tessellation. Lengyel patented it in 2019, and on March 17, 2026 he dedicated that patent to the public domain."
It's nice that he gave the patent to public domain, but this is not how patents are supposed to work. You can't patent something two years after it was already published.
I'm guessing he actually filed for a patent before publishing, and the article should read: "Lengyel was granted a patent for it in 2019"
It's an AI-written article, so maybe it's not reasonable to expect it to be consistent on this level...
Is there a runtime comparison of the shaders needed? Seems like you might have to do a lot of texture sampling if you have to walk the ray through the data but maybe there's a trick?
MSDF is pretty much just the target texel in question plus the surrounding samples in a way the GPU can do entirely upfront before the math starts. (M)SDF glyphs also play nicely with mip mapping and I would think this Slug algorithm needs uncompressed data. Maybe that doesn't matter because you just don't scale the data ever?
Slug looks impressive!
The project I'm most known for is basically an MSDF shader with a bloom pass. It serves my needs 100%, though if I expand to support arbitrary text, I may reach for Slug.
The one issue with MSDF I want to raise is, it seems everybody uses the same msdfgen texture creation program from Viktor Chlumský's master's thesis 11 years ago. I wish there were other implementations. Who ever heard of a graphics technique that was only ever programmed once, and then used everywhere without substantial iteration? We need to de-XKCD-2347 MSDFs for everyone's sake, including and especially Chlumský.
There's another GPU text rendering algorithm missing from the comparison: Rook & Possum's Scanline Sweeper:
https://rookandpossum.com/posts/scanline-sweeper/
Sean Barret (creator of the stb public domain libraries) independently invented a CPU-based implementation of the same idea, used in stb_truetype.
I knew the second Eric posted about releasing Slug to the public domain we'd get 100s of "OpenSlug" slopped-up. Will be interesting to see which implementation will win or if Slug will keep being a thing.
MSDF looks better than Slug for me in the first example.
But slug wins in perspective in my eyes.
I use MSDF to render crisp text in my webgl hobby game. Hope to publish it with source code when I get the time.
thanks for sharing the article. I'll take a deeper look at it later.
MSDF corners gave me trouble til I bumped the distance range at small sizes.
> By Chris Hanson
What a name!
(Skipped the rest of the article cause it's AI.)
Excellent write up. The cited references are on point too. Eric Lengyel is a legend.