RecursiveAI.OneFont 1.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package RecursiveAI.OneFont --version 1.1.0
                    
NuGet\Install-Package RecursiveAI.OneFont -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RecursiveAI.OneFont" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RecursiveAI.OneFont" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="RecursiveAI.OneFont" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RecursiveAI.OneFont --version 1.1.0
                    
#r "nuget: RecursiveAI.OneFont, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RecursiveAI.OneFont@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RecursiveAI.OneFont&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=RecursiveAI.OneFont&version=1.1.0
                    
Install as a Cake Tool

OneFont

A font and text-shaping library for .NET with no dependency beyond .NET itself. Load a TrueType or OpenType font, shape a run of text, and get glyphs, advances, offsets and clusters back, with the Unicode bidirectional, line breaking and grapheme algorithms and font fallback alongside. Pure C#, safe code only, NativeAOT and trimming clean.

CI .NET 10 License

What it does

  • Fonts. TrueType (glyf), OpenType with CFF outlines and TrueType Collections: cmap, head, hhea, hmtx, OS/2, name, post, kern, GDEF. Every read is bounds-checked; damaged fonts raise FontFormatException or, for layout tables, are ignored.
  • Shaping. The OpenType GSUB (types 1 to 8) and GPOS (types 1 to 9) engine with every lookup flag, features and BCP 47 language, and script shapers for Arabic (with Syriac and N'Ko), the Indic scripts, the Universal Shaping Engine scripts (Khmer, Myanmar, Sinhala, Tibetan, Balinese, Javanese and more), and Thai and Lao. Work, depth and growth budgets keep hostile fonts cheap.
  • Unicode. UAX #9 bidi (levels and visual order), UAX #14 line break opportunities and UAX #29 grapheme boundaries, on Unicode 17 data, passing the official conformance files.
  • Fallback. A chain of faces; each grapheme cluster is shaped with the first face that has its character, using that face's own tables.
  • Outlines. Glyph outlines as move, line, quadratic and cubic segments through a small sink interface.

Not in this package: WOFF and WOFF2, colour glyphs, hinting, vertical layout, and drawing text. OneFont shapes; laying out lines and painting glyphs is up to you.

Use

using OneFont;

FontFace arabic = FontFace.Load(File.ReadAllBytes("NotoSansArabic-Regular.ttf"));

foreach (ShapedCluster cluster in TextShaping.ShapeRun("\u0627\u0644\u0633\u0644\u0627\u0645", arabic, rightToLeft: true))
{
    // Start and Length index the text; Advance and the glyphs' advances and offsets are in font units.
    foreach (ShapedGlyph g in cluster.Glyphs)
    {
        GlyphOutline outline = arabic.GetOutline(g.GlyphId);
        // outline.Write(sink, transform) replays move/line/quad/cubic segments.
    }
}

// Mixed-direction paragraph: levels, then display order of the runs or clusters.
byte[] levels = TextShaping.GetBidiLevels("abc \u05E9\u05DC\u05D5\u05DD def", TextDirection.Auto, out int paragraphLevel);
int[] visual = TextShaping.GetVisualOrder(levels);

// Where a line may end, and where a user-perceived character ends.
LineBreakOpportunity[] breaks = TextSegmentation.GetLineBreakOpportunities("well-known words");
int[] graphemes = TextSegmentation.GetGraphemeBoundaries("e\u0301a");

// A face chain shapes each cluster with the first face that has its character.
var chain = new FontFallbackChain([latin, cjk]);
IReadOnlyList<ShapedCluster> clusters = chain.ShapeRun("abc \u65E5\u672C");   // cluster.FaceIndex says which face

Sizes are never involved: advances, offsets and metrics are in the face's design units, so scale by size / face.UnitsPerEm. Features and language go in ShapingOptions:

var options = new ShapingOptions { Language = "tr", Kerning = KerningMode.None };
options.Features.Add(FontFeature.On("smcp"));
TextShaping.ShapeRun("Small Caps", face, options: options);

Shaping many runs (a paragraph engine, a table) can reuse one result and allocate nothing per call:

var run = new ShapedRun();
TextShaping.ShapeRun("Small Caps", face, run, options: options);
foreach (ShapedClusterRange cluster in run.Clusters)
{
    ReadOnlySpan<ShapedGlyph> glyphs = run.GlyphsOf(cluster);
}

A run is one face, one direction and one paragraph's worth of text. Splitting a paragraph into runs (by bidi level, by face) and placing them on lines is the caller's job; tests/OneFont.Tests/MiniLayout.cs is a short worked example.

More detail on the shaping rules, the limits, and where the output deliberately differs from SixLabors.Fonts is in docs/shaping.md.

Install

dotnet add package RecursiveAI.OneFont

Targets net10.0. No runtime dependencies.

Quality

  • The shaper is compared with SixLabors.Fonts 2.1.3, used as a black box through its public API in the tests, on Latin, Greek, Cyrillic, Arabic, Hebrew and 17 complex scripts (1,042 cases); every difference is listed with its reason.
  • LineBreakTest.txt, GraphemeBreakTest.txt, BidiTest.txt and BidiCharacterTest.txt of Unicode 17 pass in full.
  • Hand-assembled GSUB and GPOS tables test every lookup type, format and flag.
  • A fuzz target (fuzz/) runs hostile fonts and text through the whole public surface under libFuzzer.

Build and test

dotnet build
dotnet test

The test project needs nothing but the committed test data. tools/ holds the generators for the Unicode tables and the scripts that cut the test fonts.

License

MIT OR Apache-2.0, Copyright (c) Recursive AI, LLC. See LICENSE-MIT, LICENSE-APACHE and THIRD-PARTY-NOTICES.md.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on RecursiveAI.OneFont:

Package Downloads
RecursiveAI.OneImage.Text

Fonts and text for OneImage: loads TrueType, OpenType (CFF), TrueType Collection, WOFF and WOFF2 fonts, measures and lays out text, and draws it onto images and canvases through the vector drawing layer.

RecursiveAI.OneGame.Text

Text for the UI: font library, shaping, measurement and the glyph atlas.

RecursiveAI.OneGame.UI.Kit

Base UI component kit: buttons, tables, lists, tabs, text input and more, themed with tokens.

RecursiveAI.OneRender

HTML and CSS layout and rendering engine: styled nodes in, box tree, incremental layout and a retained display list out.

RecursiveAI.OnePdf.Layout

Fluent page layout for OnePDF: write documents in code with containers, tables, lists, shaped and bidirectional text, images, headers, footers and page numbers, and get a tagged PDF. Built on RecursiveAI.OneFont and RecursiveAI.OnePdf. No dependencies beyond .NET and the OneFont and OnePDF packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 1,792 10/24/2026
1.2.0 2,059 10/24/2026
1.1.0 624 10/24/2026
1.0.0 104 10/24/2026

See CHANGELOG.md in the repository.