Skip to content

feat: color emoji rendering (epaint + swash) with clean app chrome - #204

Merged
aydiler merged 5 commits into
mainfrom
feature/color-emoji
Sep 15, 2026
Merged

aydiler merged 5 commits into
mainfrom
feature/color-emoji

Conversation

@aydiler

@aydiler aydiler commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • Color emoji in document content: vendored epaint 0.33.3 (crates/epaint, [patch.crates-io]) with a ~90-line patch that rasterizes color-bitmap glyphs (CBDT/CBLC, sbix, COLR) via swash and stores RGBA pixels in the font atlas; colored glyphs tessellate with a white vertex color so text-color tinting doesn't destroy them.
  • FontData.emoji_only gate: the system NotoColorEmoji face only claims characters with Emoji_Presentation=Yes (compact range table), so UI symbols (▶ ⚠ ✔ → …) always come from regular text faces.
  • Bundled monochrome NotoEmoji (Google Fonts VF) as last-resort fallback for emoji codepoints the color font lacks (e.g. it also fills 🟢 which epaint's built-in face misses).
  • App chrome contains no emoji: explorer uses vector-painted file/folder icons (egui painter, theme-aware); welcome screen and menus use plain text; theme toggle uses text-presentation ☀/☾.

Verification

  • Unit test rasterizes the doc's emoji through the full chain and asserts real color in the atlas: 🟢 green peak 207, 🔴 red peak 252.
  • Regression test: ▶▼⚠✔→✓ are not claimed by the color face; 🟢🔴⚪✅ are.
  • Full suite green (82 tests).

Notes

  • The epaint patch is intentionally minimal and a candidate for upstreaming to emilk/egui; if merged upstream, the vendoring can be dropped.
  • Slight startup cost: NotoColorEmoji.ttf (~10 MB) is read once at font setup (58 ms total font selection on this machine).

egui/ab_glyph cannot rasterize color-emoji fonts (CBDT/CBLC, COLR/CPAL);
system NotoColorEmoji.ttf loads but renders blank. The bundled monochrome
NotoEmoji (Google Fonts VF release) has vector outlines and covers all
modern emoji codepoints, including U+1F7E2 which epaint's built-in
NotoEmoji-Regular lacks. Appended last to Proportional and Monospace
chains so it only supplies glyphs nothing else covers.

Verified by a new unit test that rasterizes the doc's emoji through the
full chain and asserts real ink in the atlas (cmap hit + empty outline
would fail).
Vendored epaint 0.33.3 (crates/epaint, [patch.crates-io]) with a minimal
color-glyph patch:
- UvRect gains a 'colored' flag
- FontImpl keeps raw font bytes; when ab_glyph has no outline for a glyph
  (CBDT/CBLC, sbix, COLR fonts), allocate_glyph falls back to swash
  (Source::ColorBitmap/BestFit then ColorOutline) and writes RGBA pixels
  straight into the texture atlas
- tessellate_glyphs uses a white vertex color for colored glyphs so the
  atlas RGB is not tinted by the text color

App side: install_emoji_fonts() inserts the system NotoColorEmoji face
AHEAD of epaint's built-in monochrome emoji faces (which would otherwise
claim the glyph first), with the bundled monochrome NotoEmoji still last
for codepoints the color font lacks.

Verified by unit test: 🟢 green peak 207, 🔴 red peak 252 in the atlas.
NotoColorEmoji's cmap covers general symbols (▶ ⚠ ✔ → …), so after
inserting it ahead of the text faces it hijacked nav/UI glyphs into
blob-style emoji. FontData gains an emoji_only flag; when set, the face
only supplies characters with Unicode Emoji_Presentation=Yes (compact
range table in epaint). UI symbols fall through to the regular text
faces exactly as before.

Regression-tested: ▶▼⚠✔→✓ are NOT claimed; 🟢🔴⚪✅ still render in
color (atlas peaks 207 green / 252 red).
The explorer/search/welcome/theme UI used emoji literals (📄 📂 📁 🔍 🌙)
that predated color support and previously rendered as near-invisible
monochrome glyphs. With color emoji live they turned into colorful blob
icons, clashing with the clean UI design. Color emoji are for document
content only; app chrome now uses plain text glyphs: ▪ file marker,
expand arrows for folders (emoji removed), text buttons on the welcome
screen, and ☀/☾ (text-presentation symbols) for the theme toggle.
Paint small document (page with folded corner) and folder (tab + body,
lighter fill when expanded) icons with the egui painter — theme-aware,
no font or emoji dependence. Replaces the ▪ text marker from the emoji
cleanup; color emoji remain reserved for document content only.
@aydiler
aydiler merged commit b2a371c into main Sep 15, 2026
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant