mcpField
F
fonts

fonts

github.com/decentraland设计与 UI469 次安装1 天前更新
代码仓库

关于 fonts

面向 Decentraland 场景开发的字体使用指南,说明内置字体、自定义 .ttf 字体及 fontSrc 的版本要求,并涵盖移动端回退和字体测试。

主要功能

  1. 01说明内置字体与文本组件字段
  2. 02检查 SDK 版本后使用 fontSrc
  3. 03为自定义字体设置内置回退
  4. 04说明字体文件与许可要求
  5. 05涵盖客户端差异及测试方式

适用场景

  1. 01为 Decentraland 场景配置自定义字体
  2. 02确保移动端回退字体下的文字可读
  3. 03排查字体未加载或格式不受支持

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/fonts确认已加载。

详细介绍

Decentraland 中的字体

每个文本组件都有两个字体字段:

字段接受的值组件
font内置字体。对于 TextShape / UiText:Font.F_SANS_SERIF(默认)、Font.F_SERIF、Font.F_MONOSPACE。对于 React-ECS 属性:'sans-serif'(默认)、'serif'、'monospace'全部
fontSrc场景内容中的 .ttf 文件路径,相对于场景根目录TextShape、UiText、UiInput、UiDropdown,以及 React-ECS 的 Label、Button、Input、Dropdown 和 UiEntity uiText

仅有这三种内置字体。除此之外没有其他字体名称列表。

规则:编写 fontSrc 前先检查 SDK 版本

fontSrc 需要 @dcl/sdk 7.31.0 或更高版本。更早的版本中不存在此字段:它会导致 TypeScript 错误,即使强行绕过类型检查,SDK 也不会将其发送给浏览器。

编写前,请从 node_modules/@dcl/sdk/package.json(或 package.json)读取已安装的版本。如果场景使用的是旧版本,请升级 @dcl/sdk,或继续使用内置的 font。切勿修改 node_modules 中 SDK 生成的序列化器,否则下次安装时改动就会丢失。

规则:始终将 font 与 fontSrc 一起设置

当自定义字体无法使用时,font 会作为回退字体:在移动端始终如此;在桌面端,则会持续使用回退字体,直到字体的资源包准备就绪(参见“测试”)。选择最接近的内置字体,让回退后的显示效果仍符合预期:衬线字体或展示字体使用 'serif',代码或终端字体使用 'monospace',其他情况使用 'sans-serif'。

规则:移动应用会忽略 fontSrc

Decentraland 移动应用不支持自定义字体:它始终使用 font 回退字体渲染,且仅支持 Noto Sans、Noto Serif 和 Noto Sans Mono 及其粗体变体(截至 2026-11 的观察结果)。所有使用 fontSrc 的场景都必须确保使用回退字体时仍然显示正确且布局合适:

  • 谨慎选择回退字体(见上一条规则),并且在为移动端目标设计文本密集型 UI 之前就选好,而不是设计后再选:一次复盘发现,有三个屏幕是在读到这条规则之前,围绕展示字体设计的。
  • 切勿依赖自定义字体的宽度,让文本适应固定尺寸的框。调整框的尺寸,确保回退字体也能容纳文本。
  • 切勿只通过自定义字体的外观来传达含义(例如图标字体、符号字体或“手写”线索)。在移动端,它们会变成普通文本。

用户添加自定义字体时,请告知他们该字体不会在移动端显示。

必须在移动端正常显示的展示字体需要使用图像文本:按字形制作位图字体,每个字符使用一个 UiEntity,将字形绘制为图集中的 uvs 裁剪区域(build-ui → references/ui-components.md → Texture UVs)。它在所有客户端上的渲染效果都相同,但有两项代价:

  • 每种颜色需要一个图集。 移动端会忽略 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 行为准则,第 2 项)。无论哪种方式,字体许可证都必须允许将字体随场景一同再分发:大多数 Google Fonts 使用 SIL Open Font License,该许可证允许这样做。

Unity explorer 不支持其他任何格式。所有其他值都会在其中静默回退到 font:

fontSrc 值Unity explorerBevy explorer
场景内容中的 .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'。

一个文件对应一种字型。若标题使用粗体、正文使用常规字重,请随场景一并提供这两种字重,并让每段文本分别指向对应的文件。

成本:使用相同 fontSrc 的所有文本实体共享同一份已加载副本,因此在场景中重复使用一种字体的成本不高于使用一次。每个不同的字体文件都会生成独立的资源包(约 700 KB,包含两个纹理图集),并占用其自身的内存纹理。场景中请控制在一到两个字体文件。

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……)都会在首次出现时渲染,这会造成短暂卡顿。对于这些文字,应尽早显示(例如在加载或介绍画面中),不要等到关键时刻才显示。
  • 任何文本值中都不能使用 emoji,无论使用什么字体。Unity explorer 没有 emoji 字形(见 build-ui)。
  • 装饰性字体和展示字体仅用于简短标题和标牌。正文以及移动时需要阅读的内容,应使用 build-ui(UI)和 advanced-rendering(3D)中规定尺寸下的朴素字体。
  • 无论是内置还是自定义等宽字体,都无法让 TextShape 中的空格按列对齐。每列使用一个 TextShape(见 advanced-rendering)。

交叉引用

  • build-ui:Label、Button、Input 和 Dropdown 的属性、尺寸及禁止使用 emoji 的规则。
  • advanced-rendering:TextShape 的放置、方向、轮廓和对齐。
  • migrate-sdk6-to-sdk7:SDK6 的 font 名称映射到内置的 Font 枚举,自定义 SDK6 字体映射到 fontSrc。
  • deploy-worlds / deploy-scene:部署场景,以便服务器转换字体。
  • optimize-scene:资产包转换及其对加载时间的影响。

评论

支持 Markdown