A tool for skeleton + marks Arabic font workflows — would love your feedback

Hi everyone,

My name is Aziz Mohseny. I've built a personal tool called FFB (Font Feature Builder), and I've now reached a stage where technical feedback from this community would be really valuable to me.

The idea:
Instead of drawing a separate glyph for every dotted Arabic letter, we decompose the font into dotless skeletons and separate mark glyphs (dots and diacritics). At runtime, GSUB composes the skeleton and marks, and GPOS positions the marks from anchors.

The goal is to keep glyph counts manageable, let the designer focus only on skeletons, marks, and anchors, and allow them to develop the font without needing a font engineer.

What FFB currently does:

  • Generates GSUB for isol / init / medi / fina

  • Generates GPOS for mark and mkmk

  • Generates curs from Ex / _Ex anchors

  • Includes a browser-based tool (no install) for syncing anchor coordinates from a UFO

I've just published v0.1.0. The code is MIT-licensed, but the sample font glyphs are proprietary and for demonstration only.

In the next stage, I plan to add alternate glyph handling (features like calt and rclt), and also a tool for adjusting kerning of glyphs, dots, and marks. Ideally, I want the dots and marks to be fluid — all emerging from a single, shared fixed origin, while taking their best position relative to neighboring glyphs (contextual GPOS).

What I'm looking for:

  • General feedback on the approach and the generated feature code

  • Reports on any technical issues when compiling or testing

  • Thoughts on whether this method aligns with how you actually build Arabic-script fonts

You can try the tool here:
https://ffb-flame.vercel.app

Repository and release notes:
https://github.com/AzizMohseny/FFB/releases/tag/v0.1.0

I know this is an early version and I'm not claiming it's production-ready. My goal is to understand where this approach breaks down and what you actually need.

Thanks for your time.
— Aziz Mohseny

Note: AI was used to translate and edit this post. All technical content, project details, and design decisions are my own.

Comments

  • Simon Cozens
    Simon Cozens Posts: 880
    edited 7:01AM
    The approach is right. I don't know why anyone wouldn't do that. (Actually, I do: they open a font editor like Glyphs, select "Arabic" and it gives them a big grid of glyphs that they "need" to fill. They don't.) Khaled seems to have removed his classic "just take the dots off" blog post, but it's been the obvious way to make Arabic fonts for years.

    However, the idea behind the tool seems odd:
    • Generates GSUB for isol/init/medi/fina - any font editor which doesn't do that for you is broken and should be fixed.
    • Generates GPOS for mark/mkmk / generates curs from entry and exit anchors - any font compiler which doesn't do that for you is broken and should be fixed.
    • Syncs anchors into the feature file - again unnecessary because the font compiler already does this.
    So I'm not sure what problem you're actually solving.
  • Azizmohseny
    Azizmohseny Posts: 10

    Thanks Simon, this is a really useful point, and I think you're right that I didn't explain the "why" well enough.

    You're absolutely right that any competent font editor or compiler handles isol/init/medi/fina, mark/mkmk, and curs automatically. And for a conventional font — where each encoded letter has its own glyph — that's exactly the right thing to do, and FFB would be pointless.

    But the workflow FFB is built for is different: decomposed fonts. In this model, the encoded letters stay empty, and at runtime GSUB replaces them with a dotless skeleton plus separate mark glyphs. The point is to avoid the glyph explosion you get when every dotted letter, every positional form, and every diacritic combination needs its own glyph.

    The problem is that the moment you go decomposed, the font editor's automatic features stop working — because there's nothing to attach init/medi/fina to. The editor sees an empty glyph and has no idea that this glyph should actually decompose into skeleton + marks. So the feature code has to be generated from somewhere else, and that somewhere is the decomposition table.

    I work in FontLab 8, and I should say upfront that I have no experience with Glyphs — maybe the story is different there. Here's what I've found:

    • FontLab's component feature lets you define a glyph's parts and their anchors, and then it composes a single composite glyph from those anchors. So it's doing essentially what FFB does — but it produces one glyph, not a feature rule. FFB does the same thing, but instead of building a glyph, it builds a feature rule. That's the opposite of decomposition, where what you need at the end is a substitution rule, not a merged glyph. Is there a way for FontLab — or any other font editor — to do this instead?

    • I have never been able to get mark/mkmk to work correctly for Arabic fonts in FontLab. Whatever it generates, it doesn't work.

    • FontLab generates isol/init/medi/fina using Lookup Type 1 (single substitution), but for decomposed fonts you need Lookup Type 2 (multiple substitution) — because the output is not one glyph, it's a sequence of glyphs.

    • Many Arabic type designers I've spoken to do their glyph shapes in FontLab but write the features manually and painfully in VOLT instead. That's the workflow I'm trying to replace.

    I haven't found any documentation showing how to make FontLab produce the correct lookup type for a decomposed Arabic font — or how to set up Arabic kerning in FontLab, or how GPOS features are supposed to be built there. There are checkboxes for the last one, but the result isn't what you'd expect, and what gets generated doesn't actually work. Maybe I'm missing something. Do you know of a way to make FontLab do this — to add a feature rule instead of building a glyph? Maybe there's a path I don't know about. If you know of a way, or a document that explains it, I'd be genuinely grateful.

    That's what FFB does: it reads a decomposition table and writes the fea code that the editor would have written if the font weren't decomposed. It's not replacing the compiler — it's feeding it.

    You're also right that anchor syncing is redundant in a normal workflow. But in the decomposed workflow, the anchors live on the skeleton glyphs, and the generated feature code needs to reference those anchors by name. When the designer moves an anchor in the UFO, that change has to propagate into the .fea before compiling. Without that, the two drift apart. It also lets us use kerning to make dots and diacritics fluid — so they pick the best position relative to their neighboring glyphs.

    Thanks again for taking the time. I'd genuinely love to hear your thoughts on whether this is a real problem worth solving, or whether I'm mistaken and just reinventing the wheel.

  • Simon Cozens
    Simon Cozens Posts: 880
    But the workflow FFB is built for is different: decomposed fonts. In this model, the encoded letters stay empty, and at runtime GSUB replaces them with a dotless skeleton plus separate mark glyphs. The point is to avoid the glyph explosion you get when every dotted letter, every positional form, and every diacritic combination needs its own glyph.
    This is not something that you need to explain to me. :) By the way, having empty encoded letters sometimes mess up "glyph picker" palette windows. It's better to use components in those cases. I do it for some of the minority letters in Noto Nastaliq Urdu, but I should probably use components for those as well. (Especially for those, come to think of it, because they're often hard to keyboard.)
    • I have never been able to get mark/mkmk to work correctly for Arabic fonts in FontLab. Whatever it generates, it doesn't work.

    • FontLab generates isol/init/medi/fina using Lookup Type 1 (single substitution), but for decomposed fonts you need Lookup Type 2 (multiple substitution) — because the output is not one glyph, it's a sequence of glyphs.

    I think this may be the crux of the problem. For the first point, if you can't get mark/mkmk working properly, then... get it working properly! The anchors should just work. If they don't, I think you're probably not driving FontLab properly, but I don't have enough FontLab experience to confirm. I would be amazed if FontLab was unable to attach marks to arbitrary glyphs. I feel pretty sure that something else is wrong.

    The usual way to do it is to take the dots off in ccmp, then fix up the forms in the init/medi/fina (no need for isolation) features. But because you have things like jeem/noon/dad/etc. you do still need to have some multiple substitution rules in there. I agree that a font editor script to help generate those rules would be useful. But it can't be entirely data-driven. For example, in some fonts I prefer to also decompose the gaf sarkash and just deal with gaf as though it were kaf; but in others, I don't do that. Designer preference comes into it.

    But in the decomposed workflow, the anchors live on the skeleton glyphs, and the generated feature code needs to reference those anchors by name.

    I can see this is necessary if you need to write a separate feature file. But you shouldn't need to be doing that. The editor should be handling it. If it isn't, that's the problem that you need to fix.

  • John Hudson
    John Hudson Posts: 3,833
    edited 1:19PM
    I always assume that the feature automation offered by font tools is, at best, a starting place whose results I am going to need to edit, and at worst is completely useless for my purposes because they presuppose that I am building a font in a particular way. So what I understand you to be doing is creating an alternative automation model to build Arabic fonts in a different but still particular way. That’s obviously useful for you and likely useful to some other people.
    Regarding decomposition, for a very long time I have advocated for a new cmap table format that supports one-to-many character to glyph mapping. This would mean that a font wouldn’t need to include any precomposed glyphs or empty glyphs representing encoded characters.