Symptom

On the WASM/web build, ExecutorActionButton (and other EmojiText callers) rendered mixed emoji+text labels wrong: the emoji glyph showed correctly (e.g. the 🔍 magnifying glass) but the adjacent Latin text (“Source”, “Target”, “Add Input Node”) rendered as broken squares (tofu). Desktop, Android, and iOS were unaffected.

Root cause

EmojiText (composeApp/…/EmojiSupport.kt) applied the WASM emoji font to the entire text run: val effectiveFontFamily = EmojiSupport.emojiFontFamily ?: fontFamily, then Text(fontFamily = effectiveFontFamily). On WASM emojiFontFamily is NotoColorEmoji — an emoji-only font with no Latin glyphs — so every letter in the string fell through to a missing glyph and rendered as tofu. Only the emoji codepoints had glyphs, which is why the magnifying glass looked fine while the word next to it did not. On other platforms emojiFontFamily is null, so the whole-run override was a no-op and the bug was invisible there.

Fix

EmojiText now builds an AnnotatedString and applies SpanStyle(fontFamily = emojiFontFamily) only to the emoji codepoint spans, computed by a new pure helper emojiCharRanges(text). Latin text keeps the caller/default font (no tofu); emoji still get NotoColorEmoji explicitly (no reliance on skiko auto-fallback). When emojiFontFamily is null (desktop/Android/iOS) no spans are added, so behavior on those platforms is byte-for-byte identical to before.

Prevention