opensourceprojects.dev

A broadsheet for software that doesn't ask for your email

Single-header OpenType shaping and Unicode segmentation for C/C++
GitHub RepoImpressions2

Project Description

View on GitHub

Text Shaping Without the Headache: A Single-Header Solution for Complex Scripts

You've got a great app, but the moment someone types in Arabic, Hindi, or Khmer, your text rendering falls apart. Glyphs render in the wrong order, ligatures don't form, and diacritics land in the wrong places. You could pull in HarfBuzz and ICU, but those are heavyweight dependencies with their own build systems and learning curves. What if you could get proper text shaping and Unicode segmentation in a single C header file?

That's exactly what kb offers. It's a collection of permissively-licensed, single-header libraries for C/C++, and the star of the show is kb_text_shape.h—a library that brings ICU-style text segmentation and HarfBuzz-style OpenType shaping to your project without the baggage.

What It Does

kb_text_shape.h handles the messy middle layer of text rendering. It takes Unicode text and breaks it into segments the way international text standards expect—by direction, line, script, word, and grapheme. Then it shapes those segments using OpenType font features, which means it can handle complex script layout, ligatures, and all the typographic rules that make languages like Arabic and Hindi render correctly.

The library is explicit about what it doesn't do: no rasterization, no paragraph layout, no system font loading. It's purely concerned with telling you which glyphs to draw and where to position them on a single, infinitely-long line. That narrow focus is a feature—you bring your own rendering, font loading, and layout logic, and it handles the intricate Unicode and OpenType rules you'd rather not reimplement.

The API follows a straightforward pipeline. You push fonts into a shape context, feed it UTF-8 text with a language tag, and iterate over the resulting runs and glyphs. The code example in the README shows a complete flow: shape the text, walk through the runs, check for hard line breaks, and draw each glyph with its offsets and advances. You provide the DrawGlyph callback and the font-loading function, and the library does the rest.

Why It's Cool

The single-header pattern is genuinely refreshing. You drop one file into your project, include it, and you're done—no linking against shared libraries, no worrying about ABI compatibility, no build system integration. For a problem as notoriously complex as text shaping, that's a remarkable reduction in friction.

Here's what stands out:

  • It fills a real gap. Most rendering pipelines use stb_truetype for glyph loading and then hit a wall when they need actual shaping. This library pairs naturally with that approach—the README even shows shaping examples rendered with stb_truetype. It's the missing piece between "I can load glyphs" and "I can render international text properly."

  • The scope is honest and practical. Rather than trying to be a full text layout engine, it does one thing well: shaping and segmentation. You're not signing up for a monolithic framework. It complements your existing rendering stack instead of replacing it.

  • The API is clean and C-friendly. The example code is readable even at a glance. You create a context, push fonts, shape text, and iterate over glyphs. The separation between shaping and drawing is clear, and the library gives you exactly the data you need—glyph IDs, offsets, advances, script info, and direction flags.

  • Font coverage checking is built in. Before you commit to rendering a string with a particular font, the library can tell you whether that font can actually display it. That's a practical feature for fallback logic that usually requires extra code on top of shaping libraries.

The screenshots in the README show the proof: Arabic, Hindi, Khmer, Myanmar, Gunjala Gondi, and smallcaps feature toggling, all rendered correctly. That's a lot of typographic complexity handled by one header file.

How to Try It

Getting started is as simple as cloning the repository and including the header in your project:

git clone https://github.com/jimmylefevre/kb

Then include kb_text_shape.h in your C or C++ source file. There's no separate library to build or link against—that's the whole point.

The basic usage pattern from the README shows the essential flow:

kbts_shape_context *Context = kbts_CreateShapeContext(0, 0);
kbts_font *FontA = kbts_ShapePushFontFromFile(Context, "NotoSansMyanmar-Regular.ttf", 0);

// Shape your text
kbts_ShapeBegin(Context, KBTS_DIRECTION_DONT_KNOW, language);
kbts_ShapeUtf8(Context, text, strlen(text), KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX);
kbts_ShapeEnd(Context);

// Iterate over runs and glyphs
kbts_run Run;
while(kbts_ShapeRun(Context, &Run)) {
  // Check for line breaks, draw glyphs
}

You'll need to provide your own font loading and glyph drawing functions, but the README includes a complete example that shows how to wire it all together. If you want to see a full implementation, check out refpad—it's referenced as an in-depth usage example and shows the library in a real application.

Final Thoughts

If you're building a text-heavy application that needs to support international scripts, kb is worth a serious look. It's not a full text layout engine, and it won't handle your paragraph formatting or font discovery—but that's by design. For developers who already have a rendering pipeline and just need proper shaping and segmentation, this library fills a specific, painful gap with minimal integration cost.

The single-header approach means you can try it in an afternoon without committing to a new dependency. Given how complex text shaping can get, having a permissively-licensed option that's this easy to drop into existing C or C++ projects is genuinely useful. Your users typing in Arabic, Hindi, or any of the other complex scripts will thank you.


Follow @githubprojects for more developer tools and open source projects.

Back to Projects
Project ID: 749c86ec-ca7d-4074-b46b-21ed322f5b43Last updated: September 6, 2026 at 02:46 AM