Skip to content

Multilingual OG Images: CJK, Arabic, and Emoji

If your product serves users who write in Japanese, Arabic, Chinese, Korean, or who use emoji in titles — your OG image generator probably has bugs you haven’t noticed yet.

Most OG image solutions use one of two approaches:

  1. HTML/CSS in headless Chrome — works for all scripts, but costs 850ms and 200MB per render
  2. Simple Canvas text drawing — fast, but breaks on:
    • CJK line wrapping (breaks mid-word or at wrong characters)
    • Arabic bidirectional text (renders backwards or disconnects letter forms)
    • Emoji sequences (splits multi-codepoint emoji into broken symbols)
    • Mixed scripts (Japanese + English in one title)

OG Engine handles all of these correctly because it uses Pretext for text segmentation rather than naive string splitting.

CJK text doesn’t use spaces between words. Line breaking follows specific rules:

  • Can break between most CJK characters
  • Cannot break before punctuation like , , ),
  • Cannot break after opening punctuation like (,
  • Mixed text (CJK + Latin) requires break opportunities at script boundaries

OG Engine ships with Noto Sans JP pre-loaded, covering all CJK Unified Ideographs, Hiragana, and Katakana.

{
"format": "og",
"title": "サーバーサイドの画像生成 — ブラウザ不要",
"description": "Pretextエンジンによる高速テキストレイアウト。2msでPNG生成。",
"style": { "font": "Noto Sans JP" }
}

Arabic text is right-to-left (RTL), but numbers and Latin text within Arabic are left-to-right. This creates bidirectional runs that must be reordered for display.

Additionally, Arabic letters change shape based on position:

  • Isolated: ع
  • Initial: عـ
  • Medial: ـعـ
  • Final: ـع

Pretext handles the Unicode Bidirectional Algorithm (UAX #9), and the font shaping is handled by the Canvas text renderer (Skia via @napi-rs/canvas).

OG Engine ships with Noto Sans AR pre-loaded.

{
"format": "og",
"title": "إنشاء صور OG بدون متصفح",
"description": "محرك تخطيط النص بدون Chrome — 2 مللي ثانية لكل صورة",
"style": { "font": "Noto Sans AR" }
}

Modern emoji are surprisingly complex:

  • Flag emoji: 🇫🇷 = two regional indicator symbols
  • Skin tone: 👋🏽 = hand + skin tone modifier
  • Family: 👨‍👩‍👧‍👦 = four people joined by zero-width joiners (7 codepoints, 1 glyph)
  • Compound: ❤️‍🔥 = heart + ZWJ + fire

Naive string operations (like str.length or str.slice()) break these sequences. Pretext uses grapheme cluster segmentation (UAX #29) to treat each visual emoji as a single unit for line breaking and measurement.

{
"format": "og",
"title": "Ship Features, Not Browsers 🚀",
"description": "From Tokyo 🇯🇵 to Cairo 🇪🇬 — pixel-perfect text in every language."
}

Real-world titles mix scripts: “新機能: OG Engine v0.2 リリース” contains Japanese, Latin, numbers, and punctuation. Pretext handles script boundary detection and applies appropriate break rules for each segment.

OG Engine ships with 8 font families covering major script systems:

FontScriptsUse Case
OutfitLatinDefault, modern geometric
InterLatinTechnical, neutral
Noto Sans JPLatin + CJKJapanese content
Noto Sans ARLatin + ArabicArabic content
Playfair DisplayLatinEditorial, elegant
SoraLatinFriendly, rounded
Space GroteskLatinDeveloper-focused
JetBrains MonoLatinCode, monospace

Test multilingual rendering in the Playground — no API key needed. Switch fonts, paste CJK or Arabic text, and see the result instantly.