SeasonMSDF 0.1.0

dotnet add package SeasonMSDF --version 0.1.0
                    
NuGet\Install-Package SeasonMSDF -Version 0.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="SeasonMSDF" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SeasonMSDF" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="SeasonMSDF" />
                    
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 SeasonMSDF --version 0.1.0
                    
#r "nuget: SeasonMSDF, 0.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 SeasonMSDF@0.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=SeasonMSDF&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=SeasonMSDF&version=0.1.0
                    
Install as a Cake Tool

SeasonMSDF

SeasonMSDF is a fully managed C# MSDF/MTSDF generation library based on the msdfgen pipeline and bundled Typography.OpenFont outline loading.

Project repository:

Highlights

  • Pure C# backend for shape loading, edge coloring, and MSDF/MTSDF generation
  • Built-in OpenType/TrueType outline reading through Typography.OpenFont
  • API structure closely aligned with msdfgen concepts such as Shape, Projection, Range, and MSDFGeneratorConfig
  • Suitable for font atlas generation, offline tooling, and custom text renderers

Installation

dotnet add package SeasonMSDF

Minimal Example

The example below uses the pure managed backend only.

using SeasonMSDF;
using Typography.OpenFont;

static (float[] pixels, int width, int height) GenerateGlyphMtsdf(
    string fontPath,
    int codePoint,
    int fontSize = 32,
    float pixelRange = 8f,
    float angleThreshold = 3f)
{
    using FileStream stream = File.OpenRead(fontPath);
    Typeface typeface = new OpenFontReader().Read(stream)
        ?? throw new InvalidOperationException("Failed to read font.");

    ushort glyphIndex = typeface.GetGlyphIndex(codePoint);
    Glyph glyph = typeface.GetGlyph(glyphIndex);
    if (glyph.GlyphPoints == null || glyph.EndPoints == null)
        throw new InvalidOperationException("Glyph outline is not available.");

    var builder = new GlyphShapeBuilder();
    float geometryScale = 1.0f / typeface.UnitsPerEm;
    builder.Read(glyph.GlyphPoints, glyph.EndPoints, geometryScale);

    Shape shape = builder.Shape;
    if (shape.Contours.Count == 0)
        throw new InvalidOperationException("Glyph has no contours.");

    shape.OrientContours();
    shape.Normalize();
    EdgeColoring.EdgeColoringInkTrap(shape, angleThreshold, seed: 0);

    float glyphScale = fontSize * 2.0f;
    Shape.Bounds bounds = shape.GetBounds();
    double border = pixelRange / glyphScale;

    int width = (int)Math.Ceiling((bounds.R - bounds.L + 2.0 * border) * glyphScale);
    int height = (int)Math.Ceiling((bounds.T - bounds.B + 2.0 * border) * glyphScale);

    var bitmap = new Bitmap(width, height, 4);
    var projection = new Projection(
        new Vector2(glyphScale, glyphScale),
        new Vector2(border - bounds.L, border - bounds.B));
    var range = new Range(pixelRange / glyphScale);

    Msdfgen.GenerateMTSDF(bitmap.Section(), shape, projection, range, new MSDFGeneratorConfig());
    return (bitmap.GetRawData(), width, height);
}

Notes:

  • The returned float[] contains 4 channels per pixel in linear float form.
  • You can convert the result into your own texture format or preview it with your own renderer.
  • The sample intentionally uses only the managed backend and does not depend on the optional native interop path.

Root Cause Found During Validation

During validation against native msdfgen, several implementation differences were investigated. Most of them were secondary and had limited impact on the main rendering mismatch.

The actual root cause was in GlyphShapeBuilder.CloseContour().

The managed glyph importer did not always emit an explicit closing edge from the current contour endpoint back to the contour start. That caused some managed contours to remain open while the native pipeline used closed contours for the same glyphs.

The effective fix was straightforward:

  • record the contour start in MoveTo()
  • keep tracking the current point during edge construction
  • add a closing line in CloseContour() when the contour endpoint has not yet returned to the recorded start point

Once this was fixed, the managed and native outputs became highly similar both visually and in stage-by-stage pipeline logs.

Current Status

  • The major glyph-import topology mismatch has been resolved
  • Managed output is now much closer to native msdfgen
  • Remaining differences are mostly small numeric or channel-level deviations

Key File

  • SeasonMSDF/core/GlyphShapeBuilder.cs
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

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 80 7/11/2026