§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.
This page describes the correction in library PR
#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. 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’sfont.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
Setcontext.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. 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 whiteSTATIC control.
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
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.acceptselects an obfuscated glyph while rendering.FontSet.getRandomGlyphchooses from a width group using the ceiling of the original non-bold advance. - 26.3:
Font.getGlyphselects 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.
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 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.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:
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
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
retains the remaining pool/fallback scope; broader local resource-pack font
support is tracked in #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 and
known limits.