I Mapped All Three Wingdings Font Tables to Unicode — Here Is What Breaks
I maintain a small Wingdings translator tool, and a few months ago I decided to do the thing properly: map every glyph in Wingdings, Wingdings 2, and Wingdings 3 to real Unicode code points so text survives copy-paste without the font installed. It sounded like a weekend project. It was not a weekend project.
Here is what broke, in roughly the order it broke.
The fonts are not what you think they are
Wingdings is not one font. It is a family of four symbol fonts Microsoft shipped in the 90s: Wingdings 1 (hands, arrows, stars, zodiac), Wingdings 2 (checkboxes, geometric shapes, circled numbers), Wingdings 3 (directional arrows, keytop symbols), and Webdings (planes, folders, smiley faces). Every one of them works the same crude way: type a letter, get a symbol. The letter A might render as a victory hand in one font and a completely different glyph in another.
That crudeness is the whole problem. The underlying text is still plain ASCII. Copy Wingdings text into Discord and your friends read your "secret message" in plain English, because the clipboard carried the bytes, not the glyphs.
Only a handful of glyphs ever got real code points
My first assumption was that most of these symbols existed somewhere in Unicode already. Wrong. A small number made it: the victory hand lives at U+270C in the Dingbats block, and a few odd ones like U+1F574 (the levitating businessman) started life as Webdings glyphs. But the vast majority of the roughly 700 combined glyphs across the four fonts have no code point at all. Microsoft never published clean mapping tables, so I built mine by rendering each glyph and matching by hand.
For the unmapped ones I had two choices: the Private Use Area (U+E900 to U+F8FF) or nothing. PUA keeps screen readers quiet and renders fine where you control the font stack, but paste PUA text into any app without your font and the user gets tofu boxes. There is no good answer here, only trade-offs you document.
Surrogate pairs will eat your decoder
The decode side walks symbol strings back to letters, and my first pass indexed UTF-16 code units. Anything outside the Basic Multilingual Plane, like the bomb and snowflake glyphs that live in the astral planes, came back as two garbage halves. Switching the decoder to iterate by code point (for...of in JavaScript) fixed it, but then I learned that code points are still not what a person sees: some glyph clusters are multiple code points for one visible symbol. If you are building any kind of symbol converter, test with astral-plane characters on day one, not day thirty.
The reverse lookup has collisions
Here is my favorite bug. In Wingdings 1, both the letters I and N map to the skull glyph. That means a naive inverted dictionary silently keeps only whichever key was reduced last, and decoding the skull can never return the other letter. A decoder needs an explicit collision policy: first wins, or return all candidates and let the user pick. A plain object inversion is a data-loss bug wearing a trench coat.
Variation selectors are invisible saboteurs
Some dingbats only render as color emoji when followed by U+FE0F, the variation selector. If a user pastes the text-form variant without it, a strict lookup misses. I normalize by stripping the selector before lookup, but you have to decide this explicitly: silently dropping a selector inside an emoji sequence is its own form of corruption. Same family of bug as invisible characters hiding in copy-pasted text, which I now check for out of pure trauma.
Why bother: the Gaster test
The reason I finished instead of abandoning it: Undertale. W.D. Gaster's Entry Number 17 is written entirely in Wingdings, and it only exists in the game files. Decoding it by hand from screenshots is a rite of passage in that fandom. Running it through a proper Unicode-mapped Wingdings Translator and watching "it will be very, very interesting" resolve out of the symbols is the single best demo of why the mapping matters: a font choice doing narrative heavy lifting, surviving thirty years because somebody finally wrote the table down.
What I would do differently
Build the collision policy and the astral-plane handling before the pretty UI. The UI took an afternoon; the tables took weeks. And if you ever map a legacy symbol font to Unicode, publish the table. Microsoft never did, and every converter author since has re-derived it from scratch. That is a lot of duplicated weekends.
The full mapping tables and the translator itself live on my little tool site. If you spot a glyph I mapped wrong, I genuinely want to know.
Top comments (0)