Open-source project
JimmyLefevre/kb avatar
JimmyLefevre/kb

kb_text_shape.h: Unicode segmentation and OpenType shaping in one C header

kb single-header C/C++ libraries

1,224 stars34 forksCZlib

At a glance

What is it?
The kb repository collects single-header, permissively licensed libraries for C and C++, and currently holds one of them, kb_text_shape.h, which segments Unicode text by direction, line, script, word and grapheme and shapes it against OpenType fonts in the manner of HarfBuzz. It deliberately stops before rasterization, paragraph layout and system font discovery.
Who is it for?
kb_text_shape.h suits a C or C++ project that already has a rasterizer and needs correct handling of Arabic, Indic and Khmer text, and that wants to drop in one header rather than take a dependency on ICU and HarfBuzz together. It is the wrong choice if you need a complete text stack, because the header explicitly does not rasterize, does not do paragraph layout and does not load system fonts, and a poor fit if you need font discovery or selection.
Can I use it commercially?
Yes. Zlib is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the repository is: a collection with one entry so far

The kb repository is described as single-header permissively-licensed libraries for C and C++, a description that borrows the vocabulary of the well known stb collection and links to its single-header how-to document. The Libraries section currently lists exactly one: kb_text_shape.h, for Unicode text segmentation and OpenType shaping. The repository layout matches that, with a LICENSE file, the README, an images/ directory holding the example renders, and the single header at the top level. The primary language is C, the licence is Zlib, there are no GitHub releases, and the last push was on 2026-10-02. A one library collection is worth reading as a statement of intent rather than a finished product, because the value of the collection format is that you can drop a header into a project without a build system change, and that only pays off once there are several of them to choose between.

The scope, stated as three things it deliberately does not do

The README draws the boundary in three sentences, and they are the most useful part of the document. It does not handle rasterization. It does not handle paragraph layout. It does not handle selection and loading of system fonts. What it will do is help you know which glyphs to display where on a single, infinitely-long line, using the fonts you have provided. That is a precise contract. It means the library is one step in a text processing pipeline rather than a text engine, and the README links an explanation of the different steps of text processing to make the boundary easier to place. The distinction between knowing where a glyph goes and knowing how to draw it is exactly the line a graphics library like stb_truetype sits on the other side of, and the example images in the README are all rendered with stb_truetype, which is the library drawing what this one positions.

Segmentation and shaping, described as ICU-like and HarfBuzz-like

The three capabilities are described by reference to the two libraries that already do this well, which is the clearest way to state a compatibility target. The segmentation is ICU-like text segmentation, meaning breaking Unicode text by direction, line, script, word and grapheme. The shaping is HarfBuzz-like text shaping for OpenType fonts, which the README says means it is capable of handling complex script layout and ligatures, among other things. The third capability is font coverage checking, so you can know if a font can display a given string, which is the question you need answered before you select a fallback. The examples in the images directory show Arabic, Hindi, Khmer, Myanmar and Gunjala Gondi shaping alongside a smallcaps font feature toggle, and those five scripts are a reasonable indication of the range that motivated the library.

The API: a shape context, a run iterator and a glyph iterator

The usage example in the README shows a three phase API. You call kbts_ShapeBegin with a direction and a language, then kbts_ShapeUtf8 with the text and a generation mode, then kbts_ShapeEnd, and the result is read out through two iterators. The run iterator, kbts_ShapeRun, walks the shaped output one run at a time, and each run carries flags, a paragraph direction, a run direction, a script and a font. Inside a run, kbts_GlyphIteratorNext walks the glyphs, and each glyph carries an id, offsets and advances. The flags matter: the example tests for KBTS_BREAK_FLAG_LINE_HARD and calls NextLine when it is set, which is how a hard line break inside a run is communicated to the caller. The generation mode in the example is KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX, which is about how user identifiers are generated for the glyphs.

c
void HandleText(kbts_shape_context *Context, const char *Text, kbts_language Language)
{
  kbts_ShapeBegin(Context, KBTS_DIRECTION_DONT_KNOW, Language);
  kbts_ShapeUtf8(Context, Text, (int)strlen(Text), KBTS_USER_ID_GENERATION_MODE_CODEPOINT_INDEX);
  kbts_ShapeEnd(Context);

  kbts_run Run;
  while(kbts_ShapeRun(Context, &Run))
  {
    if(Run.Flags & KBTS_BREAK_FLAG_LINE_HARD)
    {
      NextLine();
    }

    kbts_glyph *Glyph;
    while(kbts_GlyphIteratorNext(&Run.Glyphs, &Glyph))
    {
      DrawGlyph(Glyph->Id, Glyph->OffsetX, Glyph->OffsetY, Glyph->AdvanceX, Glyph->AdvanceY,
                Run.ParagraphDirection, Run.Direction, Run.Script, Run.Font);
    }
  }
}

You supply the drawing callback, and that is the whole contract

The example opens with a comment marking the functions you have to provide, and they define the integration surface. DrawGlyph takes a glyph id, x and y offsets, x and y advances, the paragraph direction, the run direction, the script and the font, and it is yours to implement. NextLine is a line advance hook. CreateRenderFont takes a font path and returns a pointer, and the example assigns the result to Font->UserData, which is how the font object and the thing that can actually rasterize it are connected. The direction passed to kbts_ShapeBegin in the example is KBTS_DIRECTION_DONT_KNOW, meaning the library works it out from the text, and the language is passed explicitly as a kbts_language, with KBTS_LANGUAGE_ARABIC used in the sample. The model is a pull model. The library hands you positioned glyphs and you decide what to do with them, which is what makes the library usable with stb_truetype as the README examples show.

Fonts are pushed onto a stack, and the UserData field is the seam

Font management in the example is a stack rather than a lookup. kbts_ShapePushFontFromFile pushes a font onto the context, given a path and a flag, and the example pushes two fonts, NotoSansMyanmar-Regular.ttf and NotoSansArabic-Regular.ttf, so that the mixed script string can be resolved to the right font per run. The UserData assignment on each font is what connects the shaped result to your own renderer, and it is the reason the library needs no knowledge of your rasterizer at all. Since it explicitly does not handle selection and loading of system fonts, a path to a file is the only way in, which keeps the library's surface small and its dependencies smaller. For an in-depth usage example, the README points to refpad, a separate repository by the same author, which is the place to see what a real integration looks like rather than a fragment.

What to check before depending on a single-header library

A single-header library is a convenient distribution format with consequences that are worth naming. You are copying a file into your project rather than adding a dependency, which means there is no version resolution, no patch queue and no upstream security fix arriving automatically. The remedy is to keep the file in your tree and check upstream for changes yourself, which is fine for a header of this size and annoying for anything larger. The licence is Zlib, which is permissive and compatible with closed source distribution, so there is no licensing obstacle. The repository carries no releases, so there is no tag to pin to, and the example images are the only demonstration of correctness beyond the code, so the practical verification step is to run the refpad example and compare against the shapes in the images directory. The library is young enough that the API may still move, and the header is the API.

Editorial conclusion

kb_text_shape.h suits a C or C++ project that already has a rasterizer and needs correct handling of Arabic, Indic and Khmer text, and that wants to drop in one header rather than take a dependency on ICU and HarfBuzz together. It is the wrong choice if you need a complete text stack, because the header explicitly does not rasterize, does not do paragraph layout and does not load system fonts, and a poor fit if you need font discovery or selection. Before adopting it, read the three sentences of what it does not do in the README rather than the list of what it does, and budget for the fact that the repository currently ships a single library with no tagged releases, so the header is copied rather than versioned through a package manager.

Frequently asked questions

What does kb_text_shape.h provide?

It provides ICU-like text segmentation, meaning breaking Unicode text by direction, line, script, word and grapheme, and HarfBuzz-like text shaping for OpenType fonts, handling complex script layout and ligatures. It also offers font coverage checking, so you can know if a font can display a given string.

What does kb_text_shape.h not do?

The README states that it does not handle rasterization, does not handle paragraph layout, and does not handle selection and loading of system fonts. It will only help you know which glyphs to display where on a single, infinitely-long line, using the fonts you have provided.

How do I use the kb shape context in C?

Create a context with kbts_CreateShapeContext, push fonts with kbts_ShapePushFontFromFile, then call kbts_ShapeBegin, kbts_ShapeUtf8 and kbts_ShapeEnd. Walk the result with kbts_ShapeRun for each run and kbts_GlyphIteratorNext for each glyph, and call your own DrawGlyph function with the glyph id, offsets, advances, direction, script and font.

How do I connect kb_text_shape.h to my own renderer?

The example assigns your render handle to Font->UserData after pushing the font onto the context, and you implement the DrawGlyph and NextLine callbacks yourself. The library does not rasterize, so it never needs to know what your renderer is.

What licence is the kb repository under?

The repository is under the Zlib licence, and the libraries are described as permissively-licensed single-header libraries for C and C++. The repository currently lists one library, kb_text_shape.h, and has no tagged releases.

Official sources

  1. Issues
  2. JimmyLefevre/kb on GitHub
  3. License: Zlib
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jimmylefevre-kb.svg)](https://hysenlabs.com/projects/jimmylefevre-kb)

Was this useful?