Repository navigation
Releases: ChimeraAnt-DEV/GlowberryClient
Release list
OFFICIAL FIRST RELEASE
Context Confirmed
- Repo:
ChimeraAnt-DEV/GlowberryClient(slug is stillGlowberryClient; docs/URLs still point at the oldChimeraLauncherslug). V7tag = merge commit of PR #72 ("mcpe-planet source + Hitboxes/Select Hit"), tagged 2026-09-25.- The "copied PR description" is the
BETArelease ("Biggest update so far…", 2026-09-27). Its body is the PR #78 description verbatim (.AntEgg+ proximity voice + in-game pack changer + cape/overlay fixes), including the "created by Malice" sign-off. - Since
V7: 91 commits, 486 files changed, +47,801 / −1,529, and 24 merged PRs (#73–#95). - Font angle is real, not a red herring: the repo actually ships a bundled font catalogue —
LauncherFonts.java+ 29 TTFs inapp/src/main/res/font/— added in commit86eefbd(part of PR #89), which is after V7. So "fonts since V7" is a genuine change too.
Part 1 — What changed since the V7 release
Everything below landed after tag
V7(PR #72). TheBETArelease is PR #78; PRs #79–#95 came after it.
1. Rebrand & identity
- Chimera Client → GlowberryClient (PR #86): app name, ~11 locale strings, OAuth user agents, backup folder, voice join-code prefix
CHIMERA-→GLOWBERRY-, docs/release/news JSON. Java package staysorg.chimeramc.*deliberately. - New launcher icon (PR #87): golden glowberry on a dark-purple gradient tile, full-bleed adaptive + themed (mono) icon, recoloured adaptive background.
- README/docs refresh (PRs #84, #85): removed fork lineage, added rights/shared-account footer; EN + zh-CN docs site updated.
2. Proximity voice chat (the biggest new subsystem)
- PR #78 — LAN-multicast voice between Chimera users in the same world, raw 16 kHz PCM, mic capture +
RECORD_AUDIO. - PR #79 — voice channels: public/private, shareable join codes (
GLOWBERRY-XXXX), live client-side directory, dedicated Voice tab, pixel-art mic meter. Protocol v2. - PR #82 — per-channel controls, advisory capacity, viewer-only per-member mute, in-world nametag mic icon; protocol v3.
- PR #83 — real local-player feed (position + view rotation via
ClientInstancevtable slot 31) so the nametag icon actually renders. - PR #88 — internet voice: a standalone Go UDP relay server (
server/voice-relay), Opus codec, jitter buffer, mixer, relay address setting, token auth + bans, Docker/systemd/Fly.io deploy; protocol v4; proximity distance rule fixed.
3. Mod packaging & porting
- PR #78 —
.AntEggformat: ZIP container,egg.jsonmanifest, native or Lua-script mods, sandboxed atomic extraction, import wired throughFileHandler. - PR #95 — JavaBridge: import a Java Edition
.jar, assess portability locally, decompile with CFR, and have a user-configured LLM generate a Bedrock.AntEggmod (with consent gating + AI-port provenance). Rewrites, never runs, Java mods.
4. Cosmetics
- PR #78 / #75 / #76 — in-game cape via a texture-override resource pack, real applied skin in the preview.
- PR #81 — depth-layering fix (wings → cape → body → head accessories), ore-loader art fix.
- PR #89 — Cosmetics status diagnostic (pure, unit-tested) + PNG skin import.
5. UI / UX
- PR #78 — Mod Menu full-screen white-overlay fix.
- PR #80 — splash & in-launcher motion overhaul (crystal-ore loader, staggered arrival, count-up stats).
- PR #81 / #91 — Mod Menu focus-wash hardening.
- PR #89 — 3D controller illustrations, nav-bar wordmark collision fix, ~30-font app-wide font picker (
LauncherFonts), controller-connected toast, per-button CPS. - PR #92 — VIP Mod Menu (Screen B) opened by the in-game bind, with keyboard illustration.
- PR #93 — Replay system (capture/review/export) shared by both Mod Menu screens.
- PR #94 — PvP Suite V1.1: four overlay-only modules; Modules → General tab rename.
6. Combat / PvP modules
- PR #91 — Hitboxes un-greyed, peer boxes + aim lines (protocol v5 yaw/pitch), chest-height target-box toggle, combo/item limitations documented.
- PR #94 — Reach Indicator, Trajectory Prediction, Hit Prediction, Custom Kill Effects (all fail-closed, overlay-only).
7. Controller
- PR #89 / #90 — 3D controller illustrations, CPS limiter, connection notification, remap layers, rumble strength, radial dead zone as default, illustration perf fix.
8. Performance / input hardening
- PR #90 — Enter-in-chat crash fix (
TextInputSanitizer), shader autofix, FPS optimizer (launcher-side only, honest scope). - PR #89 — CPS window fix, firework touch layer, "add server" fix.
9. Testing
- 381 tests at V7 → 1,037 at PR #95 (0 failures, no mocks). Intermediate: 510 (PR #78), 597 (PR #83), 845 (PR #91), 901 (PR #93).
Part 2 — Best fonts
First, the honest constraint
GitHub sanitizes <style> blocks and inline style attributes in READMEs and release bodies, so you cannot reliably force a custom font on the text itself — it renders in the reader's system stack. Two practical consequences:
- For the description's live text: pick from system stacks (they render everywhere) — don't try to load a webfont.
- For fonts you actually control: use them in embedded banner/heading images (PNG/SVG), where any font renders exactly as designed.
So the list below is split accordingly, and I've starred the fonts your launcher already bundles (LauncherFonts), so release art and the app can share a face.
A. Live text — recommended system stacks
| Role | Stack | Why |
|---|---|---|
| Body | -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif |
GitHub's own default; maximum legibility on every OS |
| Headings | same as body, font-weight: 600 |
Weight, not a new face, is what separates headings on GitHub |
| Code / commands | ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace |
GitHub's code stack; aligns version strings and flags |
B. Banner / heading-image fonts (ranked for a GitHub release description)
| # | Font * | Type | Best for | Why it works |
|---|---|---|---|---|
| 1 | Inter * | Sans | Headings, body, UI mockups | Neutral, superb at small sizes, huge weight range — the safest "modern tech" face |
| 2 | Montserrat * | Sans | Section headings, banners | Geometric, confident; great for ALL-CAPS feature titles |
| 3 | Space Grotesk * | Sans | Wordmark, hero headings | Slightly quirky, very "gaming-tech"; pairs with Inter body |
| 4 | Poppins * | Sans | Feature chips, badges | Round geometric; friendly, reads well in pills |
| 5 | Manrope * | Sans | Sub-headings, stat labels | Tight, modern, excellent numerals for "1,037 tests" callouts |
| 6 | Sora * | Sans | Headings, nav art | Techy and crisp; strong at medium weights |
| 7 | Outfit * | Sans | Hero banner | Clean variable geometric; great for large display text |
| 8 | Orbitron * | Display | Version tag / "V8" badge | Sci-fi; use only for short accents, never body |
| 9 | Bebas Neue * | Display | Big ALL-CAPS section bars | Condensed impact; ideal for "WHAT'S NEW" strips |
| 10 | Press Start 2P * | Display | Minecraft-flavoured accents | Pixel font; perfect for a single playful badge, unreadable in bulk |
| 11 | JetBrains Mono * | Mono | Code blocks, version numbers, terminal shots | Ligatures, clear 0/O and 1/l; ideal for ./gradlew commands |
| 12 | Fira Code * | Mono | Inline code art | Same clarity, slightly softer than JetBrains |
| 13 | Merriweather * | Serif | Long-form release prose | High readability in body text; good "changelog document" feel |
| 14 | Lora * | Serif | Quotes / callouts | Warm, editorial contrast against sans headings |
| 15 | Playfair Display * | Serif | Hero heading (elegant mode) | High-contrast display serif for a premium banner |
* = bundled in this repo under app/src/main/res/font/ (29 faces total).
C. Pairings that look deliberate
- Modern gaming (recommended for GlowberryClient):
Space Grotesk(headings) +Inter(body) +JetBrains Mono(code). - Clean corporate:
Montserrat(headings) +Open Sans(body) +Fira Code(code). - Premium/elegant:
Playfair Display(hero) +Manrope(subheads) +JetBrains Mono(code). - Playful Minecraft accent:
Bebas NeueorPress Start 2Pfor one badge only, withInterfor everything else.
D. Copy-paste stacks for embedded banners / external rendering
/* Headings */
font-family: "Space Grotesk", "Montserrat", -apple-system, "Segoe UI", sans-serif;
/* Body */
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
/* Code / versions */
font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;Biggest update so far....
Summary
Implements the .AntEgg multi-language mod packaging format, adds a proximity voice chat module and an opt-in in-game resource-pack changer, and fixes the cosmetics/3D-preview/paper-cape defects plus the Mod Menu white-overlay bug.
Dependency: the preloader submodule pointer moves to
preloader-android@antegg-mod-loader(commit1ff3721). The submodule branch must be merged (or its commit made reachable) before this PR's pointer resolves.
Changes
.AntEgg mod packaging (core.antegg + preloader AntEggLoader)
- ZIP container with a custom extension;
egg.jsonmanifest at the archive root (name,version,author,type,entry_point, optionaldependencies,description). - Strict validation (Java
AntEggManifestand C++pl::runtime::AntEggManifestparse the same grammar): required fields, semantic version,typemust agree with the entry-point extension,entry_pointmay not escape the package. - native: extracted
.so's absolute path is handed to the preloader's existing native-mod injection entry point (ModManager.initializeLoadedMod)..AntEggadds packaging/validation, not a second injection mechanism. The original spec calls this API "ApexAntLamina"; no class/symbol by that name exists in this tree — theplpreloader bridge is the API in question. - script: entry
.luaruns on an embedded Lua VM (LuaJ, Lua 5.2) viaAntEggScriptHost, which exposes amodtable (name,version,author,id,dir,sandbox,dependencies). Failures are returned, not thrown. - Sandboxed atomic extraction to
getExternalFilesDir()/AntEggs/<mod-id>/(internal fallback). Every ZIP entry is resolved and checked to stay inside the sandbox; the archive is staged in a temp sibling and moved into place only when complete, so a failed import leaves no partial mod. - Import wired through
FileHandler;.anteggintent-filter path patterns/suffixes added; template + format docs atexamples/antegg-template/. - Native uses zlib raw inflate (no new third-party ZIP dependency); JNI bound via
AntEggBridgewithJava_org_chimeramc_client_core_antegg_*symbols.
Proximity voice chat (core.voice + VoiceChatOverlay)
- Peer link between Chimera users in the same world over LAN multicast UDP (
VoiceTransport), raw 16 kHz mono PCM framing (VoiceProtocol), mixing (VoiceRegistry+VoiceChannel), device (VoiceAudioEngine). - Multi-channel support: a listener hears their own channel plus the open
worldchannel in both directions, so switching to a private channel never cuts off someone standing next to you; two different private channels do not hear each other. - Mic capture with a runtime
RECORD_AUDIOrequest; a denied permission still starts listen-only.ensureCapture/stopCapturehandle a mic toggled on after a listen-only start. - Honest scope: distance/range needs a world position that lives in
libminecraftpe.so(see the native-feed notes inAGENTS.md), so the module runs in channel mode — everyone on a reachable channel is audible. The overlay states this rather than pretending a range applies.
In-game pack changer (InGamePackChanger + PackChangerPanel)
- Per-instance opt-in toggle in Instance Settings (
GameVersion.inGamePackChangerEnabled, persisted inVersionProfileMetadata). - When enabled, the in-game Mod Menu's Packs section lists the instance's resource packs with a per-pack on/off toggle that rewrites
minecraftpe/global_resource_packs.json, across every candidate game-data root.
Cosmetics / 3D preview / paper cape
- Fixed the left arm and left leg base/overlay UVs (they pointed at neighbouring strips, so one side of the body sampled the wrong atlas region). Pinned by new
SkinModelTestcases. - The built-in placeholder now paints from the same UV table the renderer samples, so it cannot drift from the model.
- The cape texture now paints every face (back panel, front panel, side columns, edge rows) — previously the transparent strips showed as holes when the cape swung, reading as flapping paper.
- The cape mesh is now depth-sorted per quad with two-sided shading; the old row-major paint order let a fold's far side paint over its near side.
Mod Menu white overlay
- The full-screen translucent white wash was Android's default focus highlight: the overlay root is
clickable, hence focusable, so a controller stick/d-pad input moved focus onto it and the framework painted the highlight. Fixed by making the rootfocusable="false"+defaultFocusHighlightEnabled="false"(XML and programmatically), while keeping children focusable for controller nav.
Testing
./gradlew :app:assembleDebug— BUILD SUCCESSFUL../gradlew :app:testDebugUnitTest— 510 tests, 0 failures, 0 errors.- Verified the three
Java_org_chimeramc_client_core_antegg_AntEggBridge_*symbols are present in the packagedlibpreloader.soinside the debug APK. - New tests:
AntEggScriptLoadingTest,VoiceChannelTest,VoiceProtocolTest,VoiceModuleGroupingTest,InGamePackChangerTest, plus expandedSkinModelTest/CapeResourcePackBuilderTest.
Not done (deliberately, with reasons)
- Hitboxes / Crystal Optimizer / Armor HUD live data. These need a native entity/camera feed. As documented at length in
AGENTS.md(verified against the reallibminecraftpe.so), game classes are stripped of exported symbols and the reachable RTTI vtables are pure-virtual interface bases, so there is no way to obtainLevel*/ClientInstance*without per-build byte-pattern signatures. The modules keep their honest "awaiting game data" state rather than fabricating readings. - Lint:
lintDebugalready fails on ~355 pre-existingMissingTranslationerrors unrelated to this change; not addressed here.
This change was created by Malice 🤔🤔
Bug fixes + 2 new mod menu modules
Switches the Installations tab to mcpe-planet.com, fixes three combat-module defects (settings not saving, and hit registration / aim settings adding input delay), and adds two new PvP modules: Hitboxes and Select Hit.
- Installations source → mcpe-planet.com
McpePlanetSource is added and registered first in SourceRegistry, so it becomes the active source out of the box. mcpedl.org is retained as an alternative — adding a mirror remains the documented two-step process (implement BedrockSource, add to all()), with no change to the UI, download client or import pipeline.
Verified against the live site rather than a hand-written fixture: 12 versions parsed (1.26.60.28/24, 26.51, 26.50) and the full POST download flow resolved end-to-end to a real wp-content/uploads/version/...apk.
2. Module settings not saving
Root cause: configNode() mapped every non-toggle config type to slider_int. Consequences:
The Crystal keybind rendered as a 0–100 slider and wrote a small integer over the stored key code.
The Aim Settings style radio lost its options entirely.
Fixed with schemaTypeFor(), which covers every ConfigType, plus InbuiltModuleProviderTypeTest pinning the mapping (including that a keybind must never collapse to a slider).
While there I found the _desc help strings and all the module scope notes had no consumer in code or layout — they were dead strings. They are now wired into the dialog, including an info node per combat module carrying its scope note. configDescriptionRes is an explicit switch rather than a name lookup, so a renamed key cannot silently bind to an unrelated string.
3. Hit registration / aim settings adding delay
A real bug, and the exact opposite of the module's stated purpose:
BURST_GAP_MS was 16L, just under one 60 Hz frame (16.7 ms). The smoothing filter therefore classified nearly every frame as a new gesture and reseeded constantly.
The reseed zeroed the filter, discarding (1 − smoothing) of each gesture's opening delta.
Both fixed in HitRegistrationMod and AimSettingsMod: window raised to 120 ms, and the filter is seeded with the frame instead of zero, so steady motion passes 1:1 and smoothing only damps frame-to-frame jitter. Tests updated to assert the first frame of a gesture is not attenuated and that 60 Hz frame pacing stays within one burst.
4. New: Hitboxes
Entity boxes plus an aim line. Players additionally get a red critical-hit line and a red best-combo box, both turning blue when aimed at.
HitboxProjector is pure (no Android/game types) and holds all the arithmetic: camera basis, box projection, crit band, combo box, and a crosshair slab test so the blue highlight cannot disagree with the geometry actually drawn. 18 tests.
The tests caught a real bug: Camera.forward() used the naive spherical form (sin yaw, …), which is counter-clockwise, while the documented Minecraft convention is clockwise from +Z. That would have mirrored every projected box horizontally once a real feed supplied yaw. Fixed, with new tests pinning the up vector too.
HitboxMod.EntitySource is the game-data seam. With no provider nothing is drawn — an invented box is worse than no box, because the player would aim at it.
The overlay is FLAG_NOT_TOUCHABLE and non-draggable, since boxes are world-positioned and the whole screen is the canvas.
- New: Select Hit
A small top-centre green/red pill (96×26 dp, deliberately clear of the crosshair and hotbar) showing when the next hit will land, with a combo count and a slim progress bar.
HitTimingSolver is pure; 13 tests. A click inside the window must not advance the combo or push the window out — counting a discarded click would make the indicator lie about both the streak and the next hit. A backwards clock is treated as a fresh engagement rather than producing a negative remaining time.
The window is clamped (50..2000 ms) and exposed as a slider, because the real cooldown varies by version.
Attack input is recorded from the paths that actually send an attack (mouse primary, and the controller mouse-button path in dispatchKeyEvent), before the preloader may consume the press — the player pressed attack either way, so the timing is the real input timing.
Honest limitations
Armor HUD still cannot display real durability, and Hitboxes cannot display real entity positions. I investigated rather than assuming: the preloader submodule exports only menu/HUD hooks, input handling and mod loading — there are no game-state entry points for entities, armor or position. Any values would have to be fabricated. Both DataSource/EntitySource are left as honest seams that render nothing (or a dimmed -), and the dialog now states this in-app rather than the feature appearing silently broken.
Fixing this needs new native hooks in the preloader submodule, which is a separate change.
Testing
381 unit tests, 0 failures, 0 errors (baseline on main: 322).
:app:compileDebugJavaWithJavac, :app:compileDebugKotlin and a full :app:assembleDebug all pass.
APK verified: lib/arm64-v8a/libgxcore.so present, and all six new classes present in the dex.
No mocks — every new test exercises real code paths.
Lint is unchanged: the project has no lint baseline and lintDebug already fails on ~355 pre-existing MissingTranslation errors, which is not a regression from this change.
Notes for reviewers
New modules are in ModIds.PVP_MODULES so they land in the PvP tab, and ModIds.requiresGameData() now marks three modules (armor, crystal, hitbox).
AGENTS.md updated with the new modules, the yaw convention, the config-description wiring, and the input-delay root cause.
BIG UPDATES
Changes since V6
Rebrand to Chimera Client (PR #66) — org.chimeramc.launcher → org.chimeramc.client across ~318 files, including namespace, applicationId and app name. The preloader submodule's JNI symbols were renamed to match. org.levimc.* classes and the prebuilt libgxcore.so/libinbuiltmods.so were left alone since they have no source and would UnsatisfiedLinkError. The org.chimeramc.xal.crypto pref key and games/org.chimeramc storage root were preserved so existing data isn't stranded.
Installations tab (PRs #61, #62) — new tab that lists Bedrock versions a mirror publishes and installs one as its own instance. Started on monster-mcpe.com (Cloudflare-gated, WebView required), then refactored to a pluggable BedrockSource/SourceRegistry abstraction defaulting to mcpedl.org (plain HTTP, no challenge — browser demoted to a 403 fallback). Failed installs keep the downloaded package for "Retry Import".
UI/branding overhaul (PR #63) — violet/magenta palette replacing the inherited green/cyan, shared card system (Widget.Chimera.Card* driven by dimens.xml), new splash and original ant-vector icon.
Navigation restored to top bar (PRs #64, #65) — the overhaul's vertical side rail could only fit ~2 of 6 tabs in landscape, so it was reverted and the original top bar brought back.
PvP Mod Menu tab (PR #67) — a PvP filter/section grouping Aim Settings, CPS Display and Snaplook, via ModIds.isPvpModule() + GROUP_PVP.
Combat modules (PR #68) — Armor HUD, Crystal Optimizer and Hit Registration, each built as decision logic behind an explicit game-data seam (no live game state is readable in this repo, so nothing fabricates a reading).
News push notification (PR #60) — FCM notification now uses a fixed "New Version Available" message instead of echoing the news item's own title/summary.
BIGGEST PVP/STABILITY/PREFORMANCE/FEATURE UPDATE !!!
BIGGEST UPDATE LOTS OF BUGS FIXES, FEATURES FOR CONTROLLER PLAYERS, BETTER UI CUSTOMIZATION, ANTI STICK DRIFT TOGGLE
More UI improvements, bug fixes, fps and overall launcher boost
V5 Merge pull request #55 from ChimeraAnt-DEV/feature/ui-glass-dynamic-c…
UI Improvements, illegal devamp
What this changes
Two things: fixing version imports for the bundles people actually have, and filling the two gaps in the top-level navigation.
Import fixes
.xapk/.apkmbundles now import. The extension gate only accepted.apk/.apks, so valid bundles for older Bedrock builds were refused before they were ever opened — even though the file picker advertisesapplication/zipand the version-manager layout names.xapk. Bundle handling is now centralised inGameBundle, shared by the installer and the version-name lookup.- XAPK base-APK detection. XAPK bundles name their base APK after the package rather than
base.apk, so the old check never found a base and the ABI gate then saw no native libraries and rejected the import. - Re-signed and older APKs are no longer rejected as "Not a Minecraft APK". When the package manifest cannot be read, Minecraft is now also identified by the presence of
libminecraftpe.so, and the version name falls back to the file name.
Navigation
- Mods is now a nav tab. It was previously reachable only from a home-screen card.
- Controller bumper/D-pad tab switching (L1/R1, L2/R2, D-pad left/right, wrapping at both ends).
LauncherTabis the single source of truth for tab order, activity mapping and key handling. - Two guards on that behaviour:
ControllerActivityopts out viashouldHandleNavKeys()because it needs raw presses for button highlighting, and switching is suppressed during a game session. - Nav tabs gained press feedback via the existing
DynamicAnim.applyPressScale, which respects the "show animations" setting and cancels cleanly when a tap becomes a scroll. - The nav bar itself already existed and is runtime-injected by
BaseActivity; this extends it rather than adding a competing bar. A prototypefocus_ringtoken was dropped, since no focus system consumed it.
Docs
AGENTS.mddocuments the nav architecture and its guards, and records that Java Edition is an unimplemented stub (see below), so these non-obvious constraints survive the next session.
Verification
./gradlew :app:testDebugUnitTest :app:compileDebugKotlin :app:compileDebugJavaWithJavac— BUILD SUCCESSFUL, 100 tests, 0 failures (9 newLauncherTabTest, 5 newGameBundleTest)../gradlew :app:assembleDebug— full APK builds;libgxcore.sopresent inlib/arm64-v8a/.- There is no emulator or device in this environment, so on-device behaviour is unverified.
GameBundleTestcovers bundle detection against real archives.
Notes
- The ABI/dual-ABI work is already in
main(merged via #51), so it is not part of this PR. This branch was originally based on that work; the PR diff correctly shows only the changes above. - Java Edition is not implemented and is deliberately not added here.
core/javaedition/JavaEditionModManagerreturnstruefromisJavaEditionSupported()unconditionally and points at/system/bin/java, which does not exist on Android; nothing consumes its launch config, and its strings are referenced by no layout or activity. It is documented as a stub so it is not mistaken for a working feature. Real support would require a bundled per-architecture JRE, a custom LWJGL, and a GL→GLES/Vulkan translation layer, and it conflicts with this project's Apache-2.0 license (PojavLauncher is GPL-3.0, Amethyst-Android is LGPL-3.0). Out of scope for this PR.
Major launcher Improvements
- Touch reactivity — two real bugs, not just new animation
applyPressScale was silently destroying other touch listeners. It called a bare setOnTouchListener. ModsAdapter had installed a drag-handle listener that begins an ItemTouchHelper drag on ACTION_DOWN, then asked for press feedback on the same view. The feedback call replaced that listener, so drag-to-reorder was broken with no error and no crash — it just stopped responding. Added a delegate overload; the delegate runs after the press effect and its return value is honoured. Confirmed no other call site in the tree attaches both (57 applyPressScale call sites audited).
Press animation was being cut off at the start. setStartVelocity was called after animateToFinalPosition, which begins the animation immediately, so the velocity was discarded and every press eased in from a standstill. Now set before starting. Springs are also built once per view and cached in a view tag (R.id.dynamic_anim_press_state, new res/values/ids.xml) instead of allocating four objects per touch event, and are re-targeted rather than rebuilt.
Presses that turn into a scroll snap back to full size past touch slop, so rows don't stay shrunk while flinging.
Known caveat, documented: a press state cached on a recycled view carries a delegate closed over the previous holder. It's currently safe because the delegate resolves the holder at call time via itemTouchHelper, but that's fragile — noted in AGENTS.md so it gets re-checked if a rebound delegate ever captures the holder directly.
2. Launcher UI — the text clipping was a real bug, in 45 more places
The home-screen cut-off text was one instance of a general defect: text-bearing buttons pinned android:layout_height to a hardcoded dp value. A fixed height does not grow with the user's font scale, so labels clip at any accessibility text size.
Converted 45 text-bearing buttons across 20 layouts to wrap_content + android:minHeight (original dp preserved as the minimum, so the default-scale appearance is unchanged).
Only views carrying android:text were touched. The remaining fixed heights are icon-only touch targets where a fixed square is correct and wrap_content would collapse them. All XML re-validated as parseable.
3. Low Input Delay — was paying a lock on every input event
ControllerInputProcessor read path was synchronized, and it runs on the UI thread inside MinecraftActivity.dispatchKeyEvent / dispatchGenericMotionEvent. Every controller event paid for a monitor enter/exit before the game saw it, and because the old code locked per-method rather than per-read, a profile swap from the UI thread could be observed mid-event.
Now the active state is a single immutable volatile ControllerResponse:
Readers take no lock and cannot see a half-applied profile.
Dead-zone division folded into a multiply.
Stick remaps are a flat int[] indexed by key code, not a HashMap lookup.
Response curve is a polynomial, not Math.pow.
The toggle now also tightens the dead zone and applies an ease-out curve, so the same physical stick travel produces more look output — a measurable change rather than a relabel. Applied via reload() so it takes effect without restarting the session.
Also fixed: isWithinDeadZone returning true for an all-zero event swallows controller button presses, which also arrive through dispatchGenericMotionEvent.
18 unit tests (ControllerResponseTest, no mocks) cover dead-zone boundaries, monotonicity, sign, clamping, drift snapping, the remap table and null-profile fallback. Verified by mutation — disabling the curve or the sign handling fails them.
4. Reduce Network Latency
Socket buffers were 256 KiB, which is backwards for request/response traffic and lets the stack hold back small writes. Now 64 KiB.
Warm ConnectionPool(8, 5min) so TCP+TLS handshakes are already done on the next request.
DNS prefetch and the game-session quiet zone retained.
Deliberately does not override connect/read timeouts — each caller sets its own (CurseForgeClient 30s, PreloaderSignatureRulesManager 10s).
- 32-bit instances — cannot be done, and I did not pretend otherwise
The request was to run 32-bit instances from a 64-bit launcher. This is not achievable from inside the app, and nothing shipped claims otherwise.
Android fixes a process's bitness at install time from the app's own native libs. This APK ships arm64-v8a only, so the process is 64-bit.
32-bit libraries cannot dlopen in a 64-bit process. Confirmed against Android NDK docs.
android:use32bitAbi does not help. It only tells the installer to prefer 32-bit libs an app already ships — a packaging choice, not a runtime switch. There is no API to run part of an app 32-bit and part 64-bit.
Since MinecraftActivity runs in-process, a separate-process workaround is not available either.
Real support requires shipping armeabi-v7a natives (including the prebuilt libgxcore.so, which is arm64-only by design) as a second APK.
What shipped instead is a clear, actionable preflight message. GamePackageManager.abiCompatibility() now returns an explicit result and abiMismatchMessage() distinguishes "your device supports 32-bit, you need a 32-bit launcher build" from "this device is 64-bit only". This replaces a confusing mid-launch dlopen failed: is 32-bit instead of 64-bit.
Not shipped: "10–0 ping". A launcher cannot move a game server closer, change ISP routing, or make a third-party server reply sooner. What it removes is latency the device itself adds — Nagle, delayed-ACK, buffer bloat, cold DNS, redundant handshakes. That's real (often tens of ms on request/response) but it is not the ping number the user sees. Both toggle strings now describe what the code actually does, including what it cannot do: "Cannot change the distance to a game server or its own response time."
6. Aim Settings
Built per the earlier request as the renamed Hit Registration module. Kept honestly scoped: Bedrock hit registration is server-authoritative, so a client-side module cannot improve it. What it genuinely tunes is look-delta quality. I did not add anything that claims to fix registration it cannot touch. If you'd rather it be labelled differently, that's a quick change.
Verification
Check Result
:app:testDebugUnitTest 65 tests, 0 failures (18 new)
:app:compileDebugKotlin / JavaWithJavac pass
:app:assembleDebug BUILD SUCCESSFUL, APK produced
XML validity (all layouts/drawables/values) 0 invalid files
Mutation check on new tests regression correctly fails
Working tree clean. No new external dependencies. Only warning is the pre-existing Gradle 9.0 deprecation notice.
UI layout revamp, improvements, and updates
Upgrades the Chimera Launcher with four workstreams:
-
Client-side hit registration (Bedrock)
New inbuilt mod (ModIds.HIT_REGISTRATION) with configurable Aim Smoothing (0–95%), center crosshair overlay, and hit flash feedback.
Exponential-moving-average look smoothing that only eases large swipes (keeps fine aim 1:1); nonzero delta passthrough untouched.
Hooked into the real input pipeline: MinecraftActivity.pojavSendLookDelta (smoothing) and pojavSendMouseButton (flash). Overlay is a non-touchable window so no input is stolen. -
UI layout revamp + touch reactiveness
Press-scale velocity-kicked springs + elevation + haptic feedback (UiTouchFeedback) on hero card, all quick-action cards, launch/version buttons, sign-in, mods/news/content view-all links., account avatars.
Hero-card pulse + glow gated via isShowAnimations() / isEnableGlowEffects().
Press feedback skips entirely when animations are disabled (reduced motion respect.
-
Low Input Delay — stronger
Replaced the idle 250 ms GPU redraw poll (4fps) with a near-free 500 ms menu-state flag check that only repaints on real pause-menu/HUD transitions in low-latency mode.
Every touch (surface/button/joystick) now does an instant menu-state check that fires visibility refresh the moment the state flips (no stale overlay buttons after opening/closing the pause menu).
PojavControls.setLowLatencyMode(...) now live-pokes the overlay on toggle so no path remains stalled..
-
64-bit + 32-bit instance support
ABI badges (32-bit amber / 64-bit green) on the hero card, instance list, and version picker..
Bitness-aware preflight (requireLauncherSupportsVersion / abiMismatchMessage) that surfaces a clear explanation before any loadLibrary instead of a mid-launch dlopen crash..
64-bit-only prebuilts (gxcore, mtbinloader2, PlayFab/MSDK) are excluded/treated optional on 32-bit devices so a 32-bit launcher build no longer aborts..Note: Android locks each process to one bitness at install, so a 64-bit process cannot dlopen a 32-bit minecraftpe.so. The launcher handles this explicitly: detects, surfaces a clear error, and refuses to attempt an impossible load (rather than crashing) while running every 64-bit variant fully..
-
Reduce Network Latency — stronger
TCP_NODELAY + TCP Quick ACK + interactive buffer sizing (LowLatencyNetworkManager.configure(...)) now apply to every launcher OkHttp client: CurseForge, preloader signature rules, avatar fetches (Main/Base/Accounts/About), content downloads, GitHub release updater/news polls..
DNS prefetch covers GitHub/CurseForge/Google + popular Bedrock multiplayer endpoints; background polls pause during active game sessions.
Validation
./gradlew :app:assembleDebug → BUILD SUCCESSFUL (includes CMake/native packaging; APK verified: lib/arm64-v8a/libgxcore.so, libinbuiltmods.so, libmtbinloader2.so)..
Testing notes
No Android emulator/KVM in dev — validated via full assemble + APK contents check.. On-device spots to check: hit-reg smoothing feel, crosshair/flash, low-latency overlay visibility after pause menu toggles, ABI badges/preflight for a imported 32-bit version, Wireshark/strace TCP_NODELAY on launcher sockets..
UI REVAMP + NEW PING STABLIZATION TOGGLE
-
UI revamp — visual richness and motion pass
Richer accent palette: per-section gradient drawables for the hero card, launch, versions, mods, and content cards (card_*_gradient.xml), plus dark-theme variants in values-night/colors.xml, so screens feel visually distinct rather than re-skinned copies. Section headers gain a 3dp accent bar (section_accent_bar.xml).
Micro-interactions: DynamicAnim.applyPressScale now adds spring elevation feedback on press alongside the existing scale, and instance cards already use it recursively. Card glow/elevation is applied via applyGlowEffects (hero card) and gated by the glow toggle.
Live/animated elements: a subtly pulsing last-played hero card, a smooth ValueAnimator progress indicator for file imports (revealed on progress, hidden on completion/error), and animated stat counters (instances/mods pop-scale).
Toggle compliance: all motion honors isShowAnimations() (pulse is stopped/started in onResume based on the flag); glow/elevation honors isEnableGlowEffects(). Dark/light theming respected throughout. -
Playtime tracking on the last-played instance card
New PlaytimeManager persists per-instance accumulated playtime (SharedPreferences, 15s heartbeat, crash/interrupted-session cleanup in Application.init()).
Wired into MinecraftActivity.kt session lifecycle (start from EXTRA_STORAGE_PROFILE_ID, heartbeat, stop in onDestroy).
Displayed on the last-played hero card ("Xh Ym played") and per-instance in the instances list. Time accumulates across sessions and tracks real wall time (within one heartbeat interval). -
"Reduce Network Latency" toggle in Settings → Basic
Labeled honestly — a launcher can't control server distance/ISP routing.
LowLatencyNetworkManager:
TCP_NODELAY socket factory for the launcher's own connections (News + GitHub release updater). Note: the socket factory deliberately delegates to SocketFactory.getDefault() — the inherited abstract SocketFactory.createSocket() is not callable directly.
Background DNS prefetch of known endpoints (triggered when the toggle is enabled).
A game-session quiet zone: non-essential news/update polling is paused while a session runs (NewsRepository.refreshIfStale, GithubReleaseUpdater, LauncherNewsMessagingService).