# Fonts

Controls font loading for the Add Text and Edit Text tools. The catalog is the 3 standard PDF fonts (Helvetica, Times, Courier with bold/italic variants) plus 58 bundled OFL-licensed faces, listed in the exported `BUILTIN_FONTS`. **Delivery and privacy:** font bytes are lazy-loaded per font on first use — never at document open — from the asset store your license names, by digest, verified against a SHA-256 manifest shipped with the SDK, and kept in the browser's cache. Nothing is fetched from a font service or a third-party CDN, and the SDK makes **no requests to Google** (a request to the store does say, by digest, which bundled font a document needed; `download: false` or self-hosting removes even that). Font-picker previews render from the downloaded bytes, so previews match exactly what gets embedded into the document.

- Interface: `FontsConfig`
- Config path: `config.fonts`

## Example

```ts
// Register a custom font with pre-loaded bytes
fonts: {
  customFonts: [
    {
      id: 'brand-font',
      displayName: 'Brand Sans',
      ttfBytes: myFontUint8Array,
      category: 'sans-serif',
    },
  ],
}
```

## Options (12)

### `fontsBaseUrl`

- Type: `string`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/fontsbaseurl

Base URL for self-hosted font files — self-hosting licenses only. It relocates only the SDK's own bundled fonts, so it needs a license that includes self-hosting (today, an offline license); otherwise the first text tool the user opens is refused with `FEATURE_NOT_LICENSED`. Fetch each file once from the store by [`Kernstra.assetDigests.fonts[font.id]`](https://kernstra.com/docs/web-sdk/api/kernstra/assetdigests) and serve it under its `ttfPath` — see [Engine, binaries and fonts](https://kernstra.com/docs/web-sdk/guides/engine-assets). The SDK verifies their bytes exactly as it verifies a download, unless you turn that off with `verifyIntegrity: false`.

```ts
// Self-host all fonts (self-hosting license)
fonts: {
  fontsBaseUrl: '/assets/fonts/',
}
```

### `download`

- Type: `boolean`
- Default: `true`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/download

`false` = airgapped mode, no font downloads: the standard-14 fonts, fonts embedded in the document, and `customFonts` registered with `ttfBytes` keep working with zero network access; loading any other font — a bundled one, or a custom font registered by URL — rejects with a descriptive error.

```ts
// Airgapped deployment — no font downloads at all
fonts: {
  download: false,
}
```

### `verifyIntegrity`

- Type: `boolean`
- Default: `true`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/verifyintegrity

SHA-256 verify downloaded bundled fonts. Downloads from the store are always verified. `false` is only needed when self-hosting _modified_ font files under the same ids via `fontsBaseUrl`; exact copies of the original files pass verification.

### `subset`

- Type: `boolean`
- Default: `false`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/subset

Embed only the glyphs an edit uses. By default an edit embeds the whole font for every face it touches, so a document a customer saves today can be reopened and edited in the same faces any number of times — every glyph is still there. `true` embeds only the glyphs the edit wrote, which keeps exported files small (a few kilobytes per face instead of a few hundred, or several megabytes for CJK) at a price: a later edit of that document that needs a glyph outside the subset falls back to a bundled look-alike, exactly as it does for any subset font other tools produce. Turn it on when file size matters more than round-trip re-editability, for example single-pass workflows or size-capped uploads. Subsetting needs `pdf-subset.bin` to load (see [Engine, binaries and fonts](https://kernstra.com/docs/web-sdk/guides/engine-assets)) and falls back to full fonts, with one console warning, when it does not.

### `customFonts`

- Type: `CustomFont[]`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts

Your own fonts: the same bag [`FontRegistry.registerCustomFont()`](https://kernstra.com/docs/web-sdk/api/fontregistry/registercustomfont) takes. **Your own fonts are never gated.** `customFonts` (a URL you serve or bytes you hold) works under every license, and so do the fonts embedded in the documents you open. The license governs where _our_ fonts come from, not which fonts you use. A viewer's fonts are the ones `customFonts` names when it is created; there is no method to add one to a running viewer. [`FontRegistry`](https://kernstra.com/docs/web-sdk/api/fontregistry) is exported for loading fonts outside a viewer — fonts you register with one you construct yourself are not seen by any viewer.

```ts
// Register a custom font from URL
fonts: {
  customFonts: [
    {
      id: 'my-serif',
      displayName: 'My Serif',
      ttfUrl: 'https://cdn.example.com/fonts/MySerif-Regular.ttf',
      category: 'serif',
    },
  ],
}
```

#### `customFonts.id`

- Type: `string`
- Required
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-id

Unique font identifier.

#### `customFonts.displayName`

- Type: `string`
- Required
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-displayname

Name shown in the font picker.

#### `customFonts.ttfUrl`

- Type: `string`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-ttfurl

URL to a TTF file (fetched on demand). The file must be at most 24 MB and served as font bytes (an HTML response is refused); serve it with CORS headers when it is on another origin.

#### `customFonts.ttfBytes`

- Type: `Uint8Array`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-ttfbytes

Pre-loaded TTF bytes (skips the fetch). The only kind of custom font that works with `download: false`.

#### `customFonts.category`

- Type: `'sans-serif' | 'serif' | 'monospace' | 'display'`
- Default: `'sans-serif'`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-category

The kind of face, for matching a substitute.

#### `customFonts.cssFallback`

- Type: `string`
- Default: `the display name, then sans-serif`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/customfonts-cssfallback

CSS `font-family` stack for previews.

### `sizes`

- Type: `readonly number[]`
- Default: `8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48, 64, 72`
- Page: https://kernstra.com/docs/web-sdk/config/fonts/sizes

The list both text tools' size menus offer, in points; positive numbers only, sorted. A block whose size is not in the list still shows its own size. New text starts at 18 pt, or at the listed size nearest it when 18 is not listed.

## The catalog (BUILTIN_FONTS: 3 standard + 58 bundled faces)

| Faces | What they are |
| --- | --- |
| Helvetica, Times, Courier | The 3 standard PDF fonts, with bold/italic variants; never downloaded. |
| Noto Sans, Noto Serif (with italics), Noto Sans Mono | The bundled Latin text faces. |
| Noto CJK | Chinese, Japanese and Korean. |
| Script-specific Noto faces | Faces for 26 scripts, for full non-Latin script support. |
| Noto Sans Symbols, Symbols 2, Math | The check marks, ballot boxes, bullets, arrows and operators forms carry. |
| Arimo (with italic), Tinos, Cousine, Carlito, Caladea, Gelasio | Metric-compatible substitutes for Arial, Times New Roman, Courier New, Calibri, Cambria and Georgia. |

## Notes

All bundled fonts are SIL OFL 1.1 licensed — see `THIRD_PARTY_NOTICES.txt` in the package. Each face is downloaded on first use, never at document open.

No Google Fonts stylesheet is ever loaded (it would transmit end-user IP addresses to Google; a German court held that pattern to violate the GDPR). The one exception is opt-in: the signature dialog's script faces, see [`tools.sign.webFonts`](https://kernstra.com/docs/web-sdk/config/tools/sign-webfonts).

Self-hosting the bundled fonts needs the license: see [Engine, binaries and fonts](https://kernstra.com/docs/web-sdk/guides/engine-assets) for fetching each file once from the asset store by digest and serving it under `fontsBaseUrl`.


Web page: https://kernstra.com/docs/web-sdk/config/fonts
