Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Ligature Support in STM? - EDIT: Workaround in replies

A topic by Draque created Mar 05, 2025 Views: 95 Replies: 5
Viewing posts 1 to 5
(2 edits)

Is there a way to activate/use ligatures in Super Text Mesh? I just spent a bunch of time perfecting a font that uses ligatures heavily, and I am really hoping to show it off.


EDIT: This is a fundamental flaw in UNITY. OOG. I am exploring my options, as I REALLY want this feature. If I end up making something which can scrape an OTF for its ligature definitions then apply them by force (just removing/injecting characters via direct unicode manipulation) to all text not within tags, would you be interested in incorporating it into STM? If I end up making it, you can just have it so everyone benefits from it.

Partial solution for anyone out there out finds this thread:

Because I could not force ligatures down Unity's wretched throat any other way, I made a last minute processing system to bypass the problem. I took all the glyphs for correctly rendered ligatures and pasted them over top of unicode characters that I am not using. After this, I made a text file of this format:

AA=¢
Aa=¢
aa=£
CH=¤
Ch=¥
ch=¦
EE=§
Ee=§
ee=¨
GH=©
etc...

This solution covers only two character glyphs. Sorry to not have something better, but I already wasted way too much time on this. With some work, the system could be adapted for arbitrarily lengthed ligatures. The order in this list also represents the PRIORITY of the ligatures. Earlier ones are checked first. They are applied in a left to right fashion. Tags are ignored and unmodified, so you don't need to worry about those. The code to apply this is below. I realize that it is not optimized, but again. Already over-engineered for the a feature as tiny as this one in my game. Some of the code in here is specific to my game, but I feel like anyone looking for this kind of solution will have no trouble with that.

private static string ApplyLigatures(string target, string ligatureFile)
{
        var ligatureAsset = Resources.Load<UnityEngine.TextAsset>($"STMFonts/{ligatureFile}_lig");
       if (ligatureAsset == null)
              return target;
       // capture ligatures (dummied to unused unicode positions)
        var ligatureMap = new Dictionary<string, string>();
        foreach (var line in ligatureAsset.text.Split('\n'))
       {
               var values = line.Split('=');
               // currently each ligature must be exactly 2 characters long (may upgrade later) - dummy character MUST be single character
               if (values.Count() != 2 || values[0].Length != 2 || values[1].Length != 1)
                     throw new Exception($"Improperly formatted ligature file: {ligatureFile}: {line}");
               ligatureMap[values[0]] = values[1];
        }

        // iterate over length of string...
        var result = "";
        for (int i = 0; i < target.Length; i++)
       {
       // capture tags
        if (target[i] == '<')
       {
               var tag = target.Substring(i, target.IndexOf('>', i) - i + 1);
               result += tag;
               i += (tag.Length - 1); // account for the +1 on loop
               continue;
        }

        // test if the character should be replaced with a ligature
        if (i < target.Length - 1)
        {
               var testPair = target.Substring(i, 2);
               if (ligatureMap.ContainsKey(testPair))
              {
                      result += ligatureMap[testPair];
                      i++; // only add 1 (account for the +1 on loop)
                      continue;
              }
       }

        // if nothing else fired off, just add the character
        if (i < target.Length)
               result += target[i];
        }

        return result;
}

Developer

Hey! 

Can dig into this later, but I remember that the Arabic support script did something like this to get ligatures working.

My RTL support script: https://pastebin.com/h9fyzJcq

Arabic support for Unity by Konash: https://github.com/Konash/arabic-support-unity

STM Emoji Support: https://pastebin.com/qr9me3GA


Essentially, the Unity inspector and other aspects just fail when it comes to ligatures, languages with connected scripts, rendering RTL text, and emoji. 

I think if you go through the source code for Konash's Arabic support script and my Emoji support script, you'll be able to find a way to take the original string, and send that in a way that renders correctly. But it would have to skip anything related to Unity's inspector, so... a replacement script like what you wrote or something that fixes these problems on the fly is probably the way to go. Check out STM's "PreParse" event too, that method is meant for doing things like this, taking text sent to STM, and modifying it before it's actually processed by STM. (My Emoji script shows how to do this) That will let you just have this as a component you can put on any STM object you want to have ligature support. (Or any other custom processing code you can imagine)

All great suggestions, thank you! I explored the built in PreParse event, and it probab;y would have been where I put this stuff if I had been using STM from the get go in my development. As it stands, I have a significant amount of code devoted to building/validating/massaging text before it gets to STM, and it makes the most sense for it to go there.

I checked out Konash's solution, and at the end of the day, it's very similar to mine. It maps directly to the glyphs of final ligature forms. The big difference is that everything is hard coded in their solution, while I'll be needing different ligature sets/mappings for each different language in my game.

I DO think it would be possible to make a truly generalized solution to this, but that would be a project unto itself.  Ultimately it would look very similar to either my code or Konash's, but it would build its mapping tables by opening and consuming the OTF files directly.

Ultimately I am just flabbergasted that Unity has not implemented this and has no plans to. Ligatures are... just fundamental.

Also, if I need a break from my game, I might follow your suggestion and put something together for the PreParse so that it is more neatly packaged (and extend character support from two to an arbitrary number). At that point I think it would be suitable to be put in the Useful Scripts post.

Developer

That would be cool to see as a standalone script! But just do what you need for your project, if you want to make it a generalized script, it can always be done later!