@betteroffice/fonts

中文文档
0.4.2发布于 2026/10/27(Apache-2.0 AND OFL-1.1)TypeScriptES Module零依赖构建来源已验证近 30 天下载 39.8万

Bundled open fonts for the BetterOffice engine: metric-compatible Latin faces (Carlito, Caladea, Liberation, Gelasio, Comic Relief), common presentation families (Inter, Roboto, Montserrat and more) plus Noto RTL script-coverage faces, with a lazy same-or

原始使用文档
文档目录8 节
  1. Install
  2. Usage
  3. Serving the faces from a CDN
  4. Bundlers
  5. Bundled faces
  6. API
  7. Documentation
  8. Licensing

@betteroffice/fonts

Open fonts and a lazy loader for the BetterOffice layout engines: metric-compatible substitutes for the Microsoft core fonts, common presentation families, and Hebrew and Arabic coverage. The DOCX engine loads them through configureDefaultFonts; for the PPTX editor's fonts prop, loadBundledFontBytes returns the bytes of any bundled face. The CJK faces ship separately in @betteroffice/fonts-cjk.

The substitutes share the advance widths of Calibri, Cambria, Arial, Times New Roman and Courier New, so line breaks and pagination match Word. Across 813 real-world documents, configuring this package raised exact page-count agreement with Word from 46.5% to 61.9%.

Install

bun add @betteroffice/fonts
# for Chinese, Japanese or Korean text:
bun add @betteroffice/fonts-cjk

Usage

Configure the DOCX engine once, before any editor mounts:

import { configureDefaultFonts } from '@betteroffice/docx/layout';
import * as fonts from '@betteroffice/fonts';

configureDefaultFonts({ fonts });

To keep the package in its own chunk, pass load instead:

configureDefaultFonts({ load: () => import('@betteroffice/fonts') });

configureDefaultFonts is process-global. Call it at module initialization; for per-editor or per-tenant URLs, pass a provider to DocxEditor as measurementFontProvider instead.

Importing the package does not fetch or register anything. Each face is fetched the first time it is needed, from the package's own assets (same origin), so bundlers such as Vite emit the files next to the module.

Serving the faces from a CDN

The @betteroffice/fonts/cdn entry keeps the font binaries and the CJK add-on out of your bundle. It fetches faces from jsDelivr URLs pinned to the installed package versions:

import { configureDefaultFonts } from '@betteroffice/docx/layout';

configureDefaultFonts({ load: () => import('@betteroffice/fonts/cdn') });

To use your own CDN, create a provider and pass it to DocxEditor as measurementFontProvider:

import { createFontProvider } from '@betteroffice/fonts/cdn';

const measurementFontProvider = createFontProvider({
  baseUrl: 'https://cdn.example.com/fonts/latin/',
  cjkBaseUrl: 'https://cdn.example.com/fonts/cjk/',
});

Or keep the bundled entry and move only the binaries:

import { configureDefaultFonts } from '@betteroffice/docx/layout';
import * as fonts from '@betteroffice/fonts';

configureDefaultFonts({ fonts, baseUrl: 'https://cdn.example.com/betteroffice-fonts/' });
  • Serve the original filenames from the packages' assets/ directories, with CORS enabled and the origin allowed in your connect-src policy.
  • With a single baseUrl, every face, CJK included, loads from that directory. Copy the assets/ of both packages into it; the filenames do not collide.
  • A relative baseUrl resolves against the current page; outside a browser it must be absolute.
  • Each download is checked against the manifest's byte length, which detects truncation but not tampering, so use an origin you trust. A CDN can see which faces a document requests.
  • Serve the files with br or gzip encoding. The faces are raw TTF/OTF, because the browser and the WebAssembly engine must measure the same bytes; compression brings the 65 faces from 14,527 KB to 7,156 KB.

Bundlers

With rollup, esbuild or a Vite build that inlines the package, mark the font packages as external so their asset URLs survive, or configure a baseUrl:

esbuild app.js --bundle --external:@betteroffice/fonts --external:@betteroffice/fonts-cjk
// rollup.config.js
export default {
  external: ['@betteroffice/fonts', '@betteroffice/fonts-cjk'],
};

Bundled faces

Bundled familyMetric-compatible withAliases also resolvedLicenseVersion
CarlitoCalibrinoneOFL 1.11.104
SelawikSegoe UI, Light, Semilight, SemiboldnoneOFL 1.1
CaladeaCambrianoneOFL 1.11.001
Liberation SansArialHelveticaOFL 1.12.1.5
Liberation SerifTimes New RomanTimesOFL 1.12.1.5
Liberation MonoCourier NewCourierOFL 1.12.1.5

Gelasio 1.008 is metric-compatible with Georgia and Comic Relief 1.200 with Comic Sans MS (both OFL 1.1). The presentation families Inter, Roboto, Source Sans 3 (for Source Sans Pro), DM Sans, DM Serif Display, Open Sans, Montserrat, Poppins, Oswald and Heebo are the fonts themselves. Unknown families resolve to a related monospace, serif or sans face. Selawik ships Regular, Bold, Light, Semilight and Semibold upright faces. Italic Segoe UI requests keep the last-resort chain, whose italic is a real italic face.

Bundled familyCoverageScript bucketLicenseVersion
Noto Sans HebrewHebrew coveragehebrewOFL 1.13.001
Noto Sans ArabicArabic coveragearabicOFL 1.12.013
Noto Naskh Arabicserif Arabic facearabicOFL 1.12.021

Measurement never consults fonts installed on the machine: embedded document fonts come first, then the bundled substitutes, then a last-resort face, so a document measures the same everywhere.

API

Most hosts only need configureDefaultFonts. The package also exports the pieces for custom byte sources and other consumers:

exportdescription
createFontProvider({ baseUrl? })The provider the measurement engine consumes.
BUNDLED_FONTSThe face manifest.
resolveMetricCompatFamily, resolveMetricCompatFaceMap a Word family (and style) to its bundled substitute.
resolveBundledFamilyFaceBundled face for a family and style, or undefined; missing italics use browser synthesis.
resolveScriptFallbackFaceCoverage face for a script bucket such as cjk-sc or arabic.
resolveGlyphFallbackFace, createFontProvider().resolveGlyphFallbackCoverage metadata and lazy bytes for characters absent from Selawik; optional office defaults to powerpoint, with word selecting Word's fallback.
resolveLastResortFaceThe always-available fallback face.
resolveDigitAdvance, maxDigitWidthWidest digit advance, recorded or measured.
loadBundledFontBytes(face, { baseUrl? })Fetches a face's bytes, cached per face and base URL.
registerBundledFontFace(face)Registers a face with the browser FontFace API; no-op outside the DOM.

Documentation

Licensing

The loader code is Apache-2.0 (see LICENSE). The font binaries are licensed under the SIL Open Font License 1.1; the full license texts with per-family copyright notices are in LICENSES/:

  • LICENSES/OFL-Carlito.txt: Copyright 2013 The Carlito Project Authors, Reserved Font Name "Carlito". Vendored from google/fonts ofl/carlito (upstream: googlefonts/carlito).
  • LICENSES/OFL-Selawik.txt: Copyright 2015 Microsoft Corporation, Reserved Font Name "Selawik". Vendored unmodified from microsoft/Selawik.
  • LICENSES/OFL-Caladea.txt: Copyright 2012 The Caladea Project Authors. Vendored from google/fonts ofl/caladea (upstream: huertatipografica/Caladea).
  • LICENSES/OFL-Liberation.txt: Digitized data copyright (c) 2010 Google Corporation; Copyright (c) 2012 Red Hat, Inc., Reserved Font Name Liberation. Vendored unmodified from the Liberation Fonts 2.1.5 release.
  • LICENSES/OFL-NotoSansHebrew.txt: Copyright 2022 The Noto Project Authors. Hinted statics vendored from notofonts/notofonts.github.io at commit cd06befda260d2abb6e5db96cf5530f80ea5180d (fonts/NotoSansHebrew/hinted/ttf/); upstream project notofonts/hebrew.
  • LICENSES/OFL-NotoArabic.txt: Copyright 2022 The Noto Project Authors; covers Noto Sans Arabic and Noto Naskh Arabic. Hinted statics vendored from notofonts/notofonts.github.io at commit cd06befda260d2abb6e5db96cf5530f80ea5180d (fonts/NotoSansArabic/hinted/ttf/, fonts/NotoNaskhArabic/hinted/ttf/); upstream project notofonts/arabic.
  • LICENSES/OFL-Gelasio.txt, OFL-ComicRelief.txt, OFL-Inter.txt, OFL-Roboto.txt, OFL-SourceSans3.txt, OFL-DMSans.txt, OFL-DMSerifDisplay.txt, OFL-OpenSans.txt, OFL-Montserrat.txt, OFL-Poppins.txt, OFL-Oswald.txt, OFL-Heebo.txt: one per family, each with that family's copyright notice.

The CJK binaries and their OFL-NotoCJK.txt license text ship in @betteroffice/fonts-cjk.

版本与发布记录

@betteroffice/fonts 共发布 7 个版本,首次发布于 2026/08/20;过去 12 个月发布了 7 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.2latest2026/10/2712 天前
0.4.12026/10/2613 天前
0.4.02026/10/011 个月前
0.3.02026/09/291 个月前
0.2.02026/09/161 个月前
0.1.02026/08/202 个月前

关于 @betteroffice/fonts 的常见问题

@betteroffice/fonts 是什么?

Bundled open fonts for the BetterOffice engine: metric-compatible Latin faces (Carlito, Caladea, Liberation, Gelasio, Comic Relief), common presentation families (Inter, Roboto, Montserrat and more) plus Noto RTL script-coverage faces, with a lazy same-or

如何安装 @betteroffice/fonts?

在项目目录运行 npm install @betteroffice/fonts,或使用 pnpm add / yarn add / bun add。

@betteroffice/fonts 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@betteroffice/fonts 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@betteroffice/fonts 可以商用吗?

@betteroffice/fonts 使用 (Apache-2.0 AND OFL-1.1) 许可。声明的许可为 (Apache-2.0 AND OFL-1.1),请阅读许可原文确认使用条件。以上为概括,不构成法律意见,请以许可原文为准。

@betteroffice/fonts 的下载量有多少?

根据 npm 官方下载统计,@betteroffice/fonts 在 2026/10/08 – 2026/11/06 这 30 天内被下载 397,504 次,日均约 13,250 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@betteroffice/fonts 还在维护吗?

最新版本 0.4.2 发布于 2026/10/27(12 天前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/08/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。