> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grounds.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Native obfuscated text

> Understand render-frame glyph replacement, width classes, motion controls, native evidence, and font limits.

Use the obfuscated decoration (`§k`, `<obfuscated>`, or JSON
`"obfuscated": true`) for the native changing-glyph effect. The saved text and
its formatting remain intact. Only the viewer's displayed replacement ink
changes.

> [!NOTE]
>
> This page describes the correction in [library PR
> \#110](https://github.com/groundsgg/library-motd/pull/110), after package
> 0.3.0. Version 0.3.0 uses an 80 ms interval. Check the changelog and your
> installed package version before relying on the corrected behavior.

## Replacement behavior

The viewer chooses replacements on its owning window's render frames, within
the audited 60-FPS Vanilla menu budget. A 120/144-Hz browser does not speed up
the effect. Slower rendering and missed frames do not trigger a burst of hidden
catch-up replacements. Actual browser and Java-client frame rates can still
differ; the upper bound does not guarantee exactly 60 changes each second or
an identical random sequence.

[Browser frame timestamps have limited precision](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame).
The budget tolerates small rounding differences, bounded by half of the observed
frame gap, rather than skipping otherwise valid 60-Hz frames.

Candidates come from the selected profile's `font.advances`. A candidate must be
one Unicode code point. Width classes use the ceiling of the original non-bold
advance; bold still contributes its separate layout advance. Spaces can occur
in a replacement class. An original U+0020 space stays unchanged, while another
space-like code point does not receive that special exemption.

Changing a replacement does not change the stored text, glyph positions, line
breaks, selection, source offsets, or undo history. The viewer retains its source
accessibility label. The inline editor keeps its source text and editing state.

## Pause motion

Set `context.animations` to `false` when you need a static view. Updating this
setting does not edit the document. Re-enabling it resumes replacement without
creating an undo transaction.

The viewer follows live `prefers-reduced-motion: reduce` changes. Each instance
owns its callback and preference listener; replacing or destroying a viewer
cancels its previous work. A viewer mounted in an iframe uses that document's
window for scheduling and rendering resources.

This control also affects other supported client-owned motion such as the
[menu panorama](https://docs.grounds.gg/reference/development/motd/panoramas.md). It does not enable
simulated MOTD frames, scrolling, blinking, or animated gradients.

## Native evidence

The independent 2026-10-27 sessions used official Java 1.21.1 and 26.3, isolated
Linux Xvfb displays, default resources, an 854×480 viewport, and GUI scale 2.
The controlled status contained separate regular, bold, italic, and bold/italic
runs, mixed widths, ordinary/non-breaking spaces, unsupported input code points,
and a non-obfuscated white `STATIC` control.

| Client | Samples | Consecutive masks per animated color | Median detected transition | Static-control masks |
| - | - | - | - | - |
| 1.21.1 | 240 | 84 | 24.998 ms | 1 |
| 26.3 | 240 | 89 | 16.723 ms | 1 |

Each sequence spans approximately two seconds. Exact foreground-color masks
change more often than the old 80 ms browser interval. Screen polling can miss
rendered frames or sample near a buffer swap. These are detected image
transitions, not timestamps instrumented inside the client renderer, and a
random glyph can repeat.

The [versioned manifests](https://github.com/groundsgg/library-motd/tree/main/tests/fixtures/client/native-obfuscation)
record the complete supplied status, client/font/resource hashes, crop,
monotonic before/after sample times, per-color mask hashes, and driver hash.
They contain numerical evidence and checksums; raw crops and client resources
stay local.

### Source audits are separate evidence

Audits of the same official class files identify these paths:

* 1.21.1: `Font.StringRenderOutput.accept` selects an obfuscated glyph while
  rendering. `FontSet.getRandomGlyph` chooses from a width group using the
  ceiling of the original non-bold advance.
* 26.3: `Font.getGlyph` selects the replacement during text preparation, using
  the same non-bold ceiling class. The prepared glyph carries its styles and
  shadow rendering.
* Both paths exclude an original code point 32 from replacement. Provider
  selection can include blank glyphs in candidate groups; missing groups use
  native missing-glyph behavior.

The 1.21.1 menu loop and 26.3 `FramerateLimitTracker` both cap out-of-level
menus at 60 FPS. Modern inactivity/window throttling can reduce that further.

Those audits explain the implementation path. They do not substitute for the
actual sampled client output or certify the browser's complete raster.
The attempted 30-FPS settings control was rejected: the audited 1.21.1 menu loop
returns a 60-FPS cap when no world is loaded, independently of its world FPS
setting. It is not evidence of a 30-FPS obfuscation clock.

## Reproduce a reference

Follow the [native reference procedure](https://docs.grounds.gg/reference/development/motd/verification.md#native-client-reference-procedure)
with an authorized local client installation. Use an owned, dedicated Linux
Xvfb `:96`, a separate game directory and default resources. Keep downloads,
credentials, raw captures, and temporary execution notes outside Git.

**1. Serve the exact status**

Extract `status` from the selected manifest into a temporary JSON file and
serve it with `tools/reference/status-server.py` on localhost port 25594.
Add that address in the isolated client's server list. Wait for the solid
blue generated icon and verify all colored runs and the white `STATIC`
control before capturing.

**2. Capture a fresh sequence**

From a source checkout with a JDK installed, use a new output directory
outside the checkout. For 1.21.1, the MOTD crop starts at y=94; for 26.3,
use y=96.

```sh theme={null}
mkdir -p /tmp/motd-capture-classes
javac -d /tmp/motd-capture-classes tools/reference/CaptureObfuscation.java
DISPLAY=:96 java -cp /tmp/motd-capture-classes CaptureObfuscation /tmp/motd-native-1.21.1-samples 94
```

The helper refuses other displays and existing output directories. It
samples 240 crops with monotonic timestamps, then encodes PNGs and hashes
after sampling so image compression does not pace the capture.

**3. Interpret the result**

Compare consecutive `masks` hashes by color in `frames.json`. The white
control should remain stable; animated colors should change. Record actual
resource identities and the environment. A fresh random run need not have
identical hashes or transition times.

## Font and timing limits

The default client has more glyph providers than the independent bundled OFL
font. Its entire random pool, glyph overhangs, unsupported-code-point behavior,
and arbitrary resource-pack rasterization are not reproduced by that font.
A separate read-only inspection of the active default font maps quantifies
that difference:

| Candidate map | Total code-point entries | Entries in ceiling-width class 6 |
| - | - | - |
| Java 1.21.1 | 114,581 | 4,563 |
| Java 26.3 | 114,432 | 4,659 |
| Bundled profile | 194 | 130 |

These are candidate code-point entries, not distinct glyph outlines. Both
native width-4 classes contain U+0020 as a possible replacement. The
[pool audit metadata](https://github.com/groundsgg/docs/blob/main/reference/development/motd/evidence/native-font-pools-2026-10-27.json)
records counts and sorted-membership hashes. The debugger-enabled inspection
is separate from the timing captures and reads only
`FontManager.fontSets["minecraft:default"].glyphsByWidth`; the older mapped
field names are recorded in the metadata.

The cadence/class correction does not close that provider-coverage gap.
[Native calibration #106](https://github.com/groundsgg/library-motd/issues/106)
retains the remaining pool/fallback scope; broader local resource-pack font
support is tracked in [#8](https://github.com/groundsgg/library-motd/issues/8).

If a profile has no replacement class for an advance, the viewer retains its
existing fallback rather than choosing an unrelated width. This is not a
simulation of the native missing-glyph raster.

The painter reuses a render canvas and a separate color parser per document.
Its CSS/bitmap and parsed-color caches stay bounded. Sustained rainbow text
does not allocate a new backing surface for every glyph on every frame.

Browser regressions cover native frame budgets at 30/60/120/144/500-Hz browser
refresh and rounded timestamps, normal/bold/italic paint, width
classes, blank and supplementary-code-point candidates, stable geometry and
editing state, live reduced motion, disposal, and iframe ownership. They do not
certify an independent Windows Java client or shipping Safari.

All bundled profiles remain `verified: false`. Continue with
[font/profile evidence](https://docs.grounds.gg/reference/development/motd/profiles.md) and
[known limits](https://docs.grounds.gg/reference/development/motd/limitations.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.