A while back someone half-jokingly asked if I could make a tool that turns "hello" into "๐ฑ๐ฎ๐ต๐ต๐ธ" for their Instagram bio. My first instinct was "that's just a custom font" โ but it's not. You can't swap fonts inside a plain text field on Instagram, TikTok, or Discord. So how do all those stylized bios actually work?
Turns out the trick has nothing to do with fonts. It's Unicode.
The block nobody tells you about: Mathematical Alphanumeric Symbols
Unicode reserves a whole range (U+1D400โU+1D7FF) called Mathematical Alphanumeric Symbols. It exists so mathematicians can write ๐ (bold), ๐ด (italic), ๐ (script), ๐ (fraktur) as genuinely distinct characters instead of relying on rich-text formatting. Nothing stops you from typing them into a regular text field, though โ they render exactly like normal text, no font, no app support required.
So a "fancy font converter" is really just a character-substitution cipher against a lookup table. For every style I built a 62-character string covering AโZ, aโz, 0โ9, mapped 1:1 onto the matching styled code points:
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const fontsMapping = [
{ id: "serifBold", map: "๐๐๐๐๐๐
๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐๐๐๐๐๐๐๐๐๐" },
{ id: "fraktur", map: "๐๐
โญ๐๐๐๐โโ๐๐๐๐๐๐๐๐โ๐๐๐๐๐๐๐โจ๐๐๐ ๐ก๐ข๐ฃ๐ค๐ฅ๐ฆ๐ง๐จ๐ฉ๐ช๐ซ๐ฌ๐ญ๐ฎ๐ฏ๐ฐ๐ฑ๐ฒ๐ณ๐ด๐ต๐ถ๐ท0123456789" },
// ...30 more of these
];
function convertString(str, font) {
const mapArray = Array.from(font.map); // Array.from, not split() โ more on that below
let result = "";
for (const char of str) {
const index = chars.indexOf(char);
result += index !== -1 && mapArray[index] ? mapArray[index] : char;
}
return result;
}
Two things bit me while building this:
1. Array.from() instead of .split(''). A lot of these code points live above U+FFFF, so they're encoded as surrogate pairs in JS strings. map.split('') slices a pair in half and hands you back mangled characters. Array.from() iterates by code point, which is what you actually want here.
2. Not every style has a full alphabet. Some Unicode "fonts" โ small caps, superscript, the currency-symbol style โ only exist for a subset of letters. There's no true Unicode superscript "Q," for instance, so I substituted the closest visual look-alike from a completely different block. For those styles it's not really a clean 1:1 cipher, it's closer to visual forgery.
The weird one: Zalgo text
The glitch/cursed-text effect (tฬธhฬถiฬตsฬด ฬถsฬดoฬทrฬถtฬต ฬถoฬดfฬต ฬธtฬถhฬทiฬดnฬถgฬธ) isn't from the same character block at all โ it's combining diacritical marks. Normally these stack a single accent on top of a letter (the mark that turns e into รฉ). Nothing stops you from stacking dozens of them on the same character:
const zalgoUp = ["ฬ", "ฬ", "ฬ", /* ...36 more */];
const zalgoMid = ["ฬ", "ฬ", "อ", /* ... */];
const zalgoDown = ["ฬ", "ฬ", "ฬ", /* ... */];
for (const char of str) {
result += char;
const numUp = Math.floor(Math.random() * 2) + 1;
for (let j = 0; j < numUp; j++) {
result += zalgoUp[Math.floor(Math.random() * zalgoUp.length)];
}
// same idea for the mid and down mark sets
}
Randomly stack 1โ2 marks above, 0โ1 in the middle, and 1โ2 below every character, and you get the "reality is glitching" look. It's not elegant โ it's controlled chaos โ but the randomness is exactly what sells the effect.
The other decorations are combining marks too
Strikethrough, underline, and overline use the same combining-character trick, just with a single mark appended after each letter instead of a lookup substitution:
{ id: "strikethrough", decorator: "ฬถ" },
{ id: "underline", decorator: "ฬฒ" },
"h" + "ฬถ" renders as hฬถ. No lookup table needed โ just append and skip spaces, since a combining mark attached to a space usually renders oddly or gets silently dropped by the renderer.
Why this breaks more than it should
Once you know the trick, the limitations make sense:
- These are still plain Unicode characters to a screen reader, not letters โ text-to-speech often can't pronounce them correctly.
- Search engines and in-app search generally won't match "๐ฑ๐ฎ๐ต๐ต๐ธ" against "hello," so you lose searchability the moment you use it.
- Devices or fonts missing glyphs for the rarer blocks fall back to the classic empty box (โ).
None of that stops it from being fun โ but it's worth knowing you're trading "cool font" for "no longer quite text" in the eyes of most software that touches it.
I turned the whole thing (30+ styles plus the Zalgo generator) into a small free tool if you want to play with it without building your own lookup table: Instagram Font Generator. No sign-up, it's a static page.
Available in other languages
- Instagramๅญ้ซ่ฝๆๅจ โ ็น้ซไธญๆ
- Instagramๅญไฝ็ๆๅจ โ ็ฎไฝไธญๆ
- Instagram Font Generator โ English
- Instagramใใฉใณใๅคๆใใผใซ โ ๆฅๆฌ่ช
- ์ธ์คํ ํฐํธ ๋ณํ๊ธฐ โ ํ๊ตญ์ด
- Polices Instagram โ Franรงais
- ะจัะธััั ะดะปั Instagram โ ะ ัััะบะธะน
- Instagram Schriftarten โ Deutsch
- Generator Font Instagram โ Bahasa Indonesia
- Fuentes para Instagram โ Espaรฑol
- Phรดng chแปฏ Instagram โ Tiแบฟng Viแปt
- เนเธเธฅเธตเนเธขเธเธเธญเธเธเน Instagram โ เนเธเธข
- Czcionki Instagram โ Polski
- Instagram Yazฤฑ Tipleri โ Tรผrkรงe
- Font per Instagram โ Italiano
- Fontes para Instagram โ Portuguรชs
- Instagram Lettertypen โ Nederlands
- ะจัะธััะธ ะดะปั Instagram โ ะฃะบัะฐัะฝััะบะฐ
Top comments (0)