Microsoft Fluent Emoji がずっと好きだ。

Microsoft が Fluent Emoji を含む Windows 11 の開発プレビューを出したとき、僕はすぐにシステムをアップグレードした ✨。
それからすぐ、Web 上でも Fluent Emoji を表示したいと思うようになり、rehype-fluent-emoji が生まれた。
コピーという小さなこと
オープンソース emoji の先駆けである Twemoji のおかげで、Web ページ上の emoji を Twemoji に置き換えるためのエコシステムはすでにある。
ただ、多くの実装は emoji をそのまま画像に置き換える。
画像に置き換えると、コピーの挙動が少し変になる。たとえば選択したテキストに含まれる emoji がうまくコピーできなかったり、選択中の文字と画像のスタイルを合わせる必要が出てきたりする。

JavaScript で copy イベントを監視して、コピー内容を動的に書き換える方法でも実現はできる。でも、それはかなり汚い。
僕は、一文をコピーしただけなのに中に著作権表示を差し込まれるような挙動がずっと嫌いだ。本質的には、クリップボードを乗っ取る怪しいソフトウェアとあまり変わらない。
emoji はそもそも文字だ。僕の記事の一文をコピーして別の場所に貼り付けたら、そこには同じ一文があるべきで、中の表情だけ消えていてほしくない。
最終的に良かったのは、テキストレイヤーとビジュアルレイヤーを分ける実装だった。
- テキストレイヤーには Unicode を残し、選択とコピーに参加させる。
- ビジュアルレイヤーは Fluent Emoji の表示を担当する。
- 選択状態では共有 CSS によって Unicode の字形を透明に保ちつつ、ページ自身の選択背景は奪わない。
画像はどこから来るのか
レイアウト設計の問題が解けたら、次は Fluent Emoji の画像をどこから持ってくるかだ。
Microsoft はたしかにとても寛大に Fluent Emoji を提供してくれている。ただ、そのリポジトリ構造は直接使うにはあまり向いていない。
オープンソースコミュニティには fluent-emoji-webfont もあるが、まだ互換性の問題があるので、最初には選ばなかった。

そこで LobeHub、emoji-regex-xs、unicode-emoji-json などを見ていったあと、ようやく fluentui-emoji-unicode にたどり着いた。
これは期待にかなり近かった。Fluent Emoji リポジトリ内の画像を、Unicode 文字コードにもとづくファイル名へ変換してくれる。
ただ、ひとつ問題があった。このリポジトリは基本的にリネームだけを行っているため、多くのファイルはまだ SVG 形式のままだ。そして Safari は、filter を含む Fluent Emoji の SVG 画像をかなり苦手としていて、表示結果が期待ほど良くなかった。

そこで僕は fork して形式変換を追加し、画像形式を WebP に統一した。
何をするか、何をしないか
unified の中では remark と rehype の役割がかなりはっきりしているので、これは rehype プラグインとして作る方が意味に合っている。
画像をローカルの public 配下にダウンロードしたいという需要もある。CDN に強く依存したくないからだ。
ただ、それは rehype の仕事の範囲を超えているので、別のコマンドとして作った。
rehype-fluent-emoji sync content --out public/emoji --style 3d明示的に同期コマンドを実行すると、記事の中で使われている emoji アセットが指定したディレクトリにダウンロードされる。
その後、レンダリング時にはプラグインをこう設定するだけでいい。
{ assetBase: '/emoji'}つまり、プラグインが担当するのは URL を生成すること だけだ。画像をどこに置くか、いつ同期するか、CDN に載せるかどうかは、使う側が自分で決める。
これによって少し自由度も生まれる。僕の fluentui-emoji-unicode を自分のサーバーにデプロイしてもいいし、GitLab や Gitee に fork してもいい。
もちろん、ローカルに取得する工程を省いて、https://raw.githubusercontent.com や https://cdn.jsdelivr.net を直接参照してもいい。
試してみる
GitHub でソースを見てもらってもいいし、npmx.dev からこの rehype プラグインをインストールしてもらってもいい。
pnpm add -D rehype-fluent-emojiAstro では、おおよそこんな設定になる。
import rehypeFluentEmoji from 'rehype-fluent-emoji'
export default { markdown: { rehypePlugins: [ [ rehypeFluentEmoji, { assetBase: '/emoji', style: '3d', }, ], ], },}このサイトでの使い方
今このサイトでは、まず記事で使われている Emoji 画像をローカルへ同期している。
{ "emoji:sync": "rehype-fluent-emoji sync content --out public/emoji --style 3d"}その後、MDX の中で rehype-fluent-emoji を使い、記事内の emoji をレンダリングしている。
Fluent Emoji レンダリングテスト では、段落、リスト、リンク、コードブロックの中でどう表示されるかを確認できる。
さようなら 👋
このプラグイン自体は複雑ではない。でも、細部を少しずつ改善していく過程がとても好きだったし、最終的な仕上がりにも満足している。
この解き方も気に入っている。見た目は楽しくしつつ、デフォルトの挙動は壊さない。
もっと面白いものを作っていけたらいいな〜