mcpField
F
fonts

fonts

github.com/decentralandデザイン・UI469 回インストール1 日前に更新
リポジトリ

fonts について

Decentraland のシーン開発向けフォントガイドです。組み込み書体やカスタム .ttf、fontSrc に必要な SDK バージョンに加え、モバイルでのフォールバックとテスト方法を説明します。

主な機能

  1. 01組み込み書体とテキスト項目の説明
  2. 02fontSrc 使用前の SDK バージョン確認
  3. 03カスタムフォントの組み込み書体フォールバック
  4. 04フォントファイルとライセンス要件の説明
  5. 05クライアントごとの差異とテスト方法

活用シーン

  1. 01Decentraland シーンへのカスタムフォント設定
  2. 02モバイルのフォールバック書体での可読性確保
  3. 03読み込み失敗や非対応形式のフォントの調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/decentraland/sdk-skills --skill fonts

インストール後、Claude Code で/fontsを入力して読み込まれたか確認します。

詳細

Decentraland のフォント

すべてのテキストコンポーネントには、2 つのフォントフィールドがあります。

フィールド指定する値コンポーネント
font組み込みフォントです。TextShape / UiText では、Font.F_SANS_SERIF(デフォルト)、Font.F_SERIF、Font.F_MONOSPACE。React-ECS の props では、'sans-serif'(デフォルト)、'serif'、'monospace'すべて
fontSrcシーンのコンテンツ内にある .ttf ファイルへのパスです。シーンのルートからの相対パスですTextShape、UiText、UiInput、UiDropdown、および React-ECS の Label、Button、Input、Dropdown、UiEntity uiText

組み込みフォントは、この 3 種類だけです。これ以外のフォント名の一覧はありません。

ルール:fontSrc を設定する前に SDK のバージョンを確認する

fontSrc を使うには、@dcl/sdk 7.31.0 以降が必要です。それ以前のバージョンにはこのフィールドが存在しないため、TypeScript エラーになります。型チェックを強制的に通しても、SDK はこのフィールドをエクスプローラーに送信しません。

設定する前に、node_modules/@dcl/sdk/package.json(または package.json)からインストール済みのバージョンを確認してください。シーンが古い場合は、@dcl/sdk をアップグレードするか、組み込みの font を使ってください。SDK が生成した node_modules 内のシリアライザーには、決してパッチを当てないでください。次回のインストール時に問題が発生します。

ルール:fontSrc と一緒に必ず font を設定する

カスタムフォントが使えない場合、常に font がフォールバックになります。モバイルでは常に、デスクトップではフォントのアセットバンドルが準備できるまで適用されます(テストを参照)。フォールバックでも意図した見た目になるよう、最も近い組み込みフォントを選んでください。セリフ体またはディスプレイ体には 'serif'、コードまたはターミナル向けのフォントには 'monospace'、それ以外には 'sans-serif' を指定します。

ルール:モバイルアプリは fontSrc を無視する

Decentraland のモバイルアプリはカスタムフォントに対応していません。常に font のフォールバックで描画され、使用できるのは Noto Sans、Noto Serif、Noto Sans Mono と、それぞれの太字のみです(2026-11 時点で確認)。fontSrc を使うシーンはすべて、フォールバックでも見た目と収まりが適切になるようにしてください。

  • フォールバックは意図的に選んでください(前述のルールを参照)。モバイル向けのテキスト量の多い UI を設計する前に対応してください。ある事後分析では、このルールを読む前にディスプレイフォントを前提として 3 つの画面が設計されていました。
  • 固定サイズのボックスにテキストを収めるために、カスタムフォントの幅を当てにしないでください。フォールバックでも収まるサイズのボックスにしてください。
  • カスタムフォントの見た目に意味を持たせないでください(アイコンフォント、記号フォント、「手書き」の手がかりなど)。モバイルでは通常のテキストになります。

ユーザーがカスタムフォントを追加した場合、モバイルでは表示されないことを伝えてください。

モバイルでも表示する必要があるディスプレイ体には、画像テキストが必要です。グリフごとのビットマップフォントを使い、各文字につき 1 つの UiEntity を用意して、アトラスから uvs で切り抜いたグリフを描画します(build-ui → references/ui-components.md → テクスチャ UV)。どのクライアントでも同じように描画されますが、次の 2 つのコストがかかります。

  • 色ごとに 1 つのアトラス。 モバイルでは uvs の切り抜きに対する uiBackground.color の色合いとアルファが無視されるため({baseDir}/../sdk-scenes/references/mobile-parity.md)、色のバリエーションごとに事前に着色し、影や輪郭線をグリフ画像に焼き込んでください。
  • ノード数。 グリフごとにノードが必要で、重ねて配置するとノード数が倍増します。輪郭線を 17 個の Label を重ねて再現したところ、画面のフレームレートは約 6 FPS まで低下しました。一方、影をグリフ画像に焼き込むと、画面のフレームレートは約 23 FPS から約 45 FPS になりました。画像テキストはタイトルと短いラベルに限定してください。

ルール:カスタムフォントはシーン内の .ttf ファイルです

fontSrc はファイルパスであり、フォント名ではありません。カスタムフォントは使用できますが、ユーザーが指定したフォント(「Playfair Displayを使って」など)は、その .ttf ファイルがシーンのフォルダー内にあり、fontSrc がそのファイルを指している場合にのみ機能します。ユーザーがカスタムフォントを希望していて、シーンにそのフォントの .ttf がまだない場合は、カスタムフォントに対応していることを伝え、.ttf ファイルを提供してもらうか、アセットのダウンロードと同様に、事前に確認してからダウンロードを申し出てください(sdk-scenes → Agent Behavioral Guidelines、項目2)。いずれの場合も、シーンに同梱して再配布できるライセンスである必要があります。ほとんどの Google Fonts は SIL Open Font License を採用しており、再配布が認められています。

Unity エクスプローラーが対応しているのは、これ以外にありません。ほかの値はすべて、Unity エクスプローラーではエラーなしに font にフォールバックします。

fontSrc の値Unity エクスプローラーBevy エクスプローラー
シーンのコンテンツ内にある .ttfアセットバンドルが存在すれば使用できます(デプロイ済みの場合、またはフォントをローカルで変換するデスクトッププレビューの場合)使用できます
CFF アウトラインを使用する OpenType(通常は .otf)、コレクション(.ttc)、Web フォント(.woff、.woff2)フォールバックしますドキュメントに記載なし — 依存しないでください
16 MB を超える、または非常に複雑なグリフアウトラインを含む .ttfフォールバックします(コンバーターによって拒否されます)ドキュメントに記載なし
.ttf への URLフォールバックします使用できます
フォントファミリー名('Playfair Display')フォールバックします使用できます
ファイルがない、無効なファイル、空文字列フォールバックしますフォールバックします

エディターのツールチップに表示されるプロトコルのドキュメントコメントには、フォントファミリー名が使えると記載されています。これは Bevy のみを指します。Unity はセキュリティ、コードサイズ、実行時のグリフラスタライズを理由に、外部フォントのサポートを意図的に廃止しました。fontSrc にファミリー名や URL を指定しないでください。

デスクトップクライアントが fontSrc の値を拒否すると、理由を示す SDK_FONTS の行がログに出力されます。URL の場合は警告(font_src "…" cannot be an external URL)、シーン内のファイルではない値(ファミリー名を含む)の場合は通常のログ行(font_src "…" is not a content file of the scene …)です。フォントがフォールバックした場合は、まず警告以外の行も含めてコンソールを確認してください。

シーンへのフォントの追加

  1. .ttf を assets/fonts/ 以下に配置します。例:assets/fonts/BungeeShade-Regular.ttf。静的な .ttf を使ってください。ファミリーが可変フォントとしてのみ提供されている場合は、静的インスタンスを使用します。
  2. フォントのライセンスをその隣に配置します(assets/fonts/BungeeShade-OFL.txt)。デプロイするとファイルが公開コンテンツサーバーに公開されるため、ライセンスで再配布と埋め込みが認められている必要があります。OFL および Apache のフォントは認められています。ほとんどの商用デスクトップライセンスでは認められていません。
  3. テクスチャの src と同じように、シーンのルートからのパスで参照します:fontSrc: 'assets/fonts/BungeeShade-Regular.ttf'。

1 ファイルにつき 1 書体です。太字のタイトルと通常の本文を使う場合は、両方のウェイトを用意し、それぞれのテキストに対応するファイルを指定します。

コスト:同じ fontSrc を使うすべてのテキストエンティティで、読み込み済みのコピーが共有されます。そのため、シーン内でフォントを再利用しても、1 回だけ使う場合よりコストは増えません。異なるフォントファイルごとに約 700 KB のアセットバンドル(2 つのテクスチャアトラス)が作成され、さらにそれぞれのテクスチャがメモリに保持されます。シーンで使うフォントファイルは 1~2 個にしてください。

3D テキスト(TextShape)

import { engine, Transform, TextShape, Font } from '@dcl/sdk/ecs'
import { Vector3, Color4, Color3 } from '@dcl/sdk/math'

const sign = engine.addEntity()
Transform.create(sign, { position: Vector3.create(8, 3, 8) })

TextShape.create(sign, {
  text: 'OPEN',
  fontSize: 6,
  textColor: Color4.White(),
  outlineColor: Color3.Black(),
  outlineWidth: 0.1,
  font: Font.F_SERIF,
  fontSrc: 'assets/fonts/AbrilFatface-Regular.ttf'
})

// Switching font at runtime is a plain field write
TextShape.getMutable(sign).fontSrc = 'assets/fonts/BungeeShade-Regular.ttf'

UI テキスト(React-ECS)

<Label
  value="Score: 100"
  fontSize={24}
  font="sans-serif"
  fontSrc="assets/fonts/BungeeShade-Regular.ttf"
  uiTransform={{ width: 240, height: 40 }}
/>

<Button value="Play" variant="primary" font="sans-serif" fontSrc="assets/fonts/BungeeShade-Regular.ttf" />

<Input placeholder="Your name" font="serif" fontSrc="assets/fonts/PTSerif-Regular.ttf" />

<Dropdown options={['Easy', 'Hard']} font="serif" fontSrc="assets/fonts/PTSerif-Regular.ttf" />

<UiEntity uiText={{ value: 'Coded-only text bag', font: 'monospace', fontSrc: 'assets/fonts/AzeretMono-Medium.ttf' }} />

編集可能な UI(build-ui):要素に fontSrc を手動で記述します。Creator Hub UI Designer では表示も編集もできませんが、保存時に変更した props だけを差し替えるため、手動で記述した fontSrc は保持されます(Prettier によって行のインデントが変わる場合があります)。キャンバスでは font のフォールバックがレンダリングされます。カスタムフォントを使うことだけを理由に、UI をコードモードに切り替える必要はありません。

カスタムフォントのテスト

デスクトップクライアント(Unity explorer)は、シーンのフォントをアセットバンドルからのみ読み込み、フォントファイルそのものから読み込むことはありません。そのため、カスタムフォントが表示されるのはバンドルがある場所だけです。

  • ローカルプレビュー(npm run start または Creator Hub Play、フラグは不要):Desktop Explorer はシーンの読み込み前にシーンのアセットを自動で変換します。.ttf フォントも変換されるため、フォントが表示されます。変換されるのは .ttf のみです。それ以外のフォント形式では font のフォールバックが使われます。それでもフォールバックが表示される場合は、変換処理が実行されなかったか、このシーンを配信できませんでした。Explorer のデバッグメニューにある AB パネルに理由が表示されます(optimize-scene → ローカルアセットバンドルプレビュー)。
  • **デプロイ済みシーン:**サーバーによるアセットバンドルの変換が完了すると、フォントが表示されます。それまではフォールバックが表示されます。フォント変換が導入される前にデプロイされたシーンでは、再度デプロイしたときにのみフォントバンドルが作成されます。
  • Bevy explorer は .ttf を直接読み込むため、変換しなくてもプレビューにフォントが表示されます。
  • **モバイルアプリ:**常にフォールバックが表示されます(モバイルのルールを参照)。
  • 「フォントが動作しない」と報告される前に、上記のどれに該当するかユーザーに伝えてください。
  • 期待される動作を確認できるリファレンスシーンは、decentraland/sdk7-test-scenes の scenes/84,-6-font-src(zone 上の realm sdk7testscenes.dcl.eth)です。各フォールバックのケース、コンポーネント間で共有されるフォント、コンポーネントの再作成、シーン境界を扱っています。

グリフと読みやすさ

  • カスタムフォントで描画できるのは、そのフォントに含まれる文字だけです。含まれていない文字は、単語の途中でも組み込みのサンセリフ体で描画されるため、表示が崩れます。アクセント付き文字、キリル文字、CJK などを使う場合は、対象の文字体系を含むフォントを選んでください。
  • フォントのバンドルには、ASCII、スマート句読点(引用符、ダッシュ、省略記号、箇条書き記号)、€、一般的な Latin-1 の文字があらかじめ描画されています。フォントに含まれるそれ以外の文字(キリル文字、ギリシャ文字、CJK など)は、初めて表示されるときに描画されるため、一時的な遅延が発生します。これらの文字体系のテキストは、重要な場面ではなく、読み込み画面やイントロ画面などで早めに表示してください。
  • フォントの種類にかかわらず、テキスト値に絵文字は使わないでください。Unity explorer には絵文字のグリフがありません(build-ui を参照)。
  • 装飾的な書体やディスプレイ書体は、短いタイトルや看板に使ってください。本文や、移動中に読むテキストには、build-ui(UI)および advanced-rendering(3D)に記載されているサイズで、シンプルな書体を使ってください。
  • 等幅書体は、組み込みかカスタムかにかかわらず、TextShape 内でスペースを使って列を揃えることはできません。列ごとに TextShape を使ってください(advanced-rendering を参照)。

関連項目

  • build-ui:Label、Button、Input、Dropdown の props、サイズ設定、絵文字を使わないルール。
  • advanced-rendering:TextShape の配置、向き、アウトライン、配置設定。
  • migrate-sdk6-to-sdk7:SDK6 の font 名は組み込みの Font enum に対応し、カスタム SDK6 フォントは fontSrc に対応します。
  • deploy-worlds / deploy-scene:サーバーがフォントを変換するようにデプロイする方法。
  • optimize-scene:アセットバンドルの変換と、読み込み時間にとって重要な理由。

コメント