Skip to content

Regalia v1.0.8

Choose a tag to compare

@YDW99 YDW99 released this 02 Jul 06:27
· 24 commits to main since this release
8e530f4

What's Changed

Full Changelog: v1.0.7...v1.0.8


Regalia v1.0.8 — Personified Chess, Reimagined ♔

A standalone, open-source chess app for Android — play offline against Stockfish 18, analyze your games, and explore openings. No account, no network, no tracking.

versionCode 108 · versionName 1.0.8 · 30 development phases (Phase 22 → Phase 51)


🎯 What's New in v1.0.8

This is the biggest release in Regalia's history. v1.0.8 completely redesigns the move-animation and sound system around a single idea: every piece has a personality. A pawn shouldn't sound or move like a queen. Combined with full light/dark theme support and the Stockfish 18 arm64-v8a-dotprod engine, v1.0.8 is both the most expressive and the most robust version ever shipped.

✨ Headline Features

Feature What it does
🎬 Personified Move Animations Each of the 6 piece types has a unique motion characteristic via the Web Animations API — the pawn hesitates then darts, the knight traces an L-shape parabola, the queen glides in an elegant arc, the king steps with solemn weight. GPU-composited for sustained 120fps.
🔊 Personified Sound Effects A pure Web Audio API synth engine (zero audio files) gives every piece a matching timbre: pawn = triangle 3-stage, knight = sine sweep + ding, bishop = sawtooth + filter sweep, rook = square + noise + impact, queen = 3-freq harmony + LFO vibrato, king = bell partials + 4 footsteps.
📳 Personified Haptics Six dedicated haptic signatures (PAWN_MOVE → KING_MOVE) plus CASTLE and PROMOTION, each with its own throttle, amplitude, and temporal pattern. A single turn produces exactly one haptic (mutually-exclusive if/else if chain) — never a muddy double-buzz.
🌓 Light / Dark Theme Auto-switches with the system setting via dual-channel detection (Java UiModeManager + JS data-theme + CSS prefers-color-scheme). Light mode uses an elegant silver palette; dark mode keeps the warm brown-red + bright gold. The ♔/♚ king icon flips to match the on-board pieces.
🧠 Stockfish 18 dotprod The arm64-v8a-dotprod variant (ARMv8.6-A DOTPROD instructions for NN inference acceleration) — the strongest Stockfish build available for modern ARM devices.

🎬 The Six Piece Personalities

Every piece now has a coherent animation + sound + haptic triad designed to feel like that piece's "character."

Piece Motion Sound Haptic Duration
Pawn Timid — hesitate back, then dart forward Triangle wave, 3-stage Three micro-trembles (low) 260 ms
Knight Agile — L-shape parabolic jump Sine sweep + crisp ding Lift-off + landing (mid) 380 ms
Bishop Sharp — quick diagonal glide Sawtooth + filter sweep Smooth bell curve (mid-low) 270 ms
Rook Fierce — charge → dash → impact + light shake Square + noise + impact thud Charge + heavy impact (mid-high) 290 ms
Queen Elegant — graceful arc + heavy shake 3-freq harmony + LFO vibrato Massive slam (highest) 520 ms
King Solemn — heavy single step + heavy shake Bell partials + 4 footsteps Four solemn thuds (high) 560 ms

Engineering note: Every animation frame is a pure transform update — zero pixel ops. A single static filter: drop-shadow is cached on the composited layer, so the shadow travels with the piece "for free." Result: 120fps sustained even on mid-range devices.


🛡️ Robustness & Stability

v1.0.8 went through 5 independent first-principles code reviews (Phase 24, 28, 30, 46, 49), culminating in a 5-parallel-subagent audit of all ~27,000 lines. Every "避坑" (pitfall-avoidance) item is verified correct.

Bug fixes that mattered (Phase 49 highlights)

  • Chess960 king-capture misclassified as castling — a king capturing to column 6/2 (e.g. Kxg1 with the king on f1) was silently destroying pieces. Fixed with an empty-destination guard.
  • importPGN data-loss on malformed [FEN] — an invalid FEN tag destroyed all persisted review evals across all games and corrupted the Chess960 mode, even though the import failed. Fixed by validating startState before any side effects.
  • onHintMove applied to the wrong position — if you moved between requesting a hint and the engine responding, the stale hint landed on the new position. Fixed with an isHintLoading staleness guard mirroring onBestMove's pattern.
  • Worker-pool Blob URL leaknew Worker(url) failures leaked the Blob URL forever. Fixed by hoisting url and revoking on failure.
  • Heatmap cache-key collision — a 10-move variation and a 10-move mainline selection could produce identical cache keys → stale heatmap. Fixed with a content-based key.

The button-width saga (Phase 44 → 50)

A single UI bug — compact buttons stretching to full row width — survived seven fix attempts before the true root cause was found:

Phase Approach Why it failed
44 width: fit-content Ignored in flex containers
47 Inline flex: 0 0 auto Correct for flex items — but the buttons were grid items
48 .btn-compact + !important flex Same flex approach, same failure
49 Added .btn-compact to click selector Robustness, not the root cause
50 .btn-row opts out of the grid transform The real fix

Root cause: A portrait @media rule (.dlg-sec > div[style*="display:flex"]) was converting the button containers from display: flex to display: grid with grid-template-columns: 1fr auto — a layout designed for label+input rows. The buttons became grid items, and grid items ignore all flex properties. The fix: a .btn-row marker class + a higher-specificity override (0,3,1 > 0,2,1, later source order) that restores display: flex and neutralizes grid-template-columns.

Lesson: When flex properties have no visible effect, check whether the parent is secretly a CSS Grid.


🔧 Phase 51 — Three Final Fixes

After the button-width fix, three remaining issues were addressed:

1. PGN round-trip castling failure (HIGH)

Symptom: A game exported as PGN and re-imported would silently drop moves after any castling move (O-O / O-O-O). For example, a game ending 6.O-O O-O 7.Re1 a6 would import as 6.O-O O-O 7. _ a6 — the Re1 move vanished.

Root cause: pseudoMoves() attaches the castle flag to the to object ({row, col, castle}), and legalMoves() builds the full move as {from, to:{row,col,castle}, piece}. So mv.castle (top-level) is undefined for moves from legalMoves(). The UI path (executeMove) copies the flag to mv.castle before calling makeMv, but the PGN-replay path (_applySANMove) calls makeMvInPlace directly — mv.castle was undefined, so _castleSide() fell through to a heuristic that read the wrong board state. Result: castling only moved the king, not the rook. Subsequent rook moves failed to parse.

Fix: _castleSide() now checks both mv.castle (top-level, set by executeMove) and mv.to.castle (set by pseudoMoves). Verified: full Italian Game round-trips perfectly.

2. Move-classification label: "Book" → "Mediocre"

The review-mode move classification label for near-equal moves (eval delta < 50cp) was "Book"/"开局库". Changed to "Mediocre"/"平常" per user request — "Book" was misleading (it doesn't mean the move came from an opening book). The CSS class .book is unchanged.

3. Eval-chart dark-mode line invisibility

The review eval-trend chart's negative-eval line color (--chart-fill) was #1A1A2E (near-black) in dark mode — invisible against the #1a0a0a background. Changed to #5dade2 (light blue) for dark mode, clearly visible and hue-distinct from the positive-eval line (#E8E8F0 light cream). Light mode unchanged.


📱 Xiaomi HyperOS 3 Compatibility

Regalia is tested on Xiaomi HyperOS 3 and hardened against its aggressive process management:

  • Foreground EngineService keeps the Stockfish subprocess alive when the app goes to background
  • 5-second engine heartbeat detects zombie processes fast (OEM process killers are ruthless)
  • Dual-channel theme detectionprefers-color-scheme alone is unreliable on HyperOS 3, so we also read UiModeManager on the Java side and mirror it to a data-theme attribute
  • 6-step WebView destroy prevents render-process crash loops
  • onRenderProcessGone recovery
  • APK signed with v1 + v2 + v3 schemes — all three verified ✅

♟️ Full Feature List

Click to expand the complete feature list

Engine & Play

  • Stockfish 18arm64-v8a-dotprod native build (ARMv8.6-A DOTPROD for NN acceleration)
  • 8 difficulty levels — 800 ELO (beginner) → 2800+ ELO (max strength) + Skill Level mode
  • Chess960 / Fischer Random Chess — all 960 starting positions, proper castling rules, SP-ID selector, Shredder-FEN, UCI_Chess960 option
  • Ponder mode — engine thinks on your opponent's time
  • WDL display — Win/Draw/Loss probability alongside the eval
  • MultiPV analysis — 1–8 lines simultaneously

PGN & Analysis

  • Standardized PGN — strict 1994-spec import/export, Seven-Tag Roster, [%eval] / [%clk] / [%emt] annotations
  • NAG & visual annotations$1$19 NAGs; auto-cached [%csl] highlights + [%cal] arrows
  • Time-Control chess — Sudden Death / Fischer / Bronstein / US Delay, live clocks, auto-emit [%clk]
  • Review mode — full replay, eval trend chart, move classification (brilliant / good / blunder), engine eval cache with LRU eviction
  • ECO opening classification — 500+ openings, search, category filter, book recommendations
  • Syzygy 7-piece tablebases — via Lichess Tablebase API (auto-disables offline)
  • PGN cache manager — save / import / rename / tag / search / filter / batch-delete cached games

UI / UX

  • Control heatmap — per-square control visualization with SVG arrows from each attacker
  • 🌿 Lines — engine variations (MultiPV) + PGN import variations (RAV), toggleable
  • Board anti-shake — OIS-style sensor-fusion translation compensation (StabilizationHelper)
  • Quick toolbar — Undo / Redo / Flip / Hint / Control-Range moved below the board (thumb-friendly)
  • Setup-mode manual markers — 🔁 castle-rights + ⚡ en-passant placed manually (no auto-grant), validated against Chess960 rules
  • Bilingual UI — full Chinese / English toggle, auto-detects system language
  • Landscape + portrait — adaptive responsive layout with clamp() + vw scaling
  • Notch / cutout / R-corner — full env(safe-area-inset) support

📥 Download & Install

APK

Download Regalia-v1.0.8-release.apk from the Releases page.

  • Requirements: Android 5.0+ (API 21), ARM64 device (arm64-v8a), ~200 MB storage
  • Signing: v1 + v2 + v3 APK Signature schemes (all verified)
  • Install: Enable "Install from unknown sources" in system settings, then tap the APK

Source Code

The source tarball Regalia-v1.0.8-src.tar.gz contains the complete source minus the Stockfish engine binary (to keep the tarball small — the 114 MB engine is downloadable separately). See BUILDING.md in the repo for build instructions.

Documentation

Self-contained HTML user manuals are included:

  • Regalia-v1.0.8-manual-en.html — English
  • Regalia-v1.0.8-manual-zh.html — 中文

Each contains wireframe diagrams of every screen, a full feature walkthrough, and a complete version changelog (newest-to-oldest).


📜 Licensing

Regalia is a combined work under dual licensing:

Component License
Original application code (UI, WebView, services, build scripts) AGPL v3
DroidFish-derived code (engine mgmt, game logic, PGN parsing, UI patterns) GPL v3
Stockfish 18 engine binary (libstockfish.so) GPL v3
ECO opening data CC0 (data) / AGPL v3 (code)

Per GPL v3 Section 13, these licenses are compatible for combination. Since AGPL v3 imposes stricter network-interaction provisions, its obligations effectively extend to the entire combined work.

Third-Party Attribution

  • DroidFish — Engine management, game logic, PGN parsing, UI patterns (© Peter Österlund, GPL v3)
  • Stockfish 18 — Chess engine (© T. Romstad, M. Costalba, J. Kiiski, G. Linscott, GPL v3)
  • lichess-org/chess-openings — ECO classification data (CC0)
  • Lichess Tablebase API — 7-piece endgame lookup (public API)

See NOTICE for the full, file-by-file license classification.


🏗️ Build From Source

# 1. Place the Stockfish 18 engine binary
#    Download from: https://github.com/official-stockfish/Stockfish/releases/download/sf_18/stockfish-android-armv8-dotprod.tar
cp stockfish-android-armv8-dotprod src/main/jniLibs/arm64-v8a/libstockfish.so
chmod +x src/main/jniLibs/arm64-v8a/libstockfish.so

# 2. Build the chess.html asset (merges 8 JS modules into the HTML template)
python3 build-chess.py

# 3. Build the release APK
./gradlew assembleRelease

Prerequisites: JDK 21, Android SDK (API 35, Build-Tools 34.0.0, NDK 27.2.12479018, CMake 3.22.1), Gradle 8.11.1 (wrapper included).


🔬 Development Phases (Phase 22 → 51)

v1.0.8 evolved through 30 development phases. Here's the arc:

Phase 22  Move animations + sound redesign + light mode          ████████████████████
Phase 23  ⚡ marker fix + Stockfish 18 dotprod integration        ██████████████
Phase 24  First-principles review (7 subagents, 135 issues)       ████████████████████
Phase 25  Web Worker pool rewrite (Blob-URL, 30s timeout)         ████████████
Phase 26  Personified animation/sound/haptic upgrade              ██████████████████████
Phase 27  Knight / bishop / rook dedicated haptics                ██████████
Phase 28  Re-review (8 bug fixes + haptic fallback)               ██████████████
Phase 29  Setup ⚡ normalization + castle sound + WebView robust   ████████████████████
Phase 30  Thorough review (2 high + 8 medium bugs)                ██████████████
Phase 31  Deep performance (getCtrlMap hidden-class, ECO index)   ██████████
Phase 32  Robustness hardening (_escJs, dt, parseInt radix)       ████████████
Phase 33  Robustness re-review + comment cleanup                  ██████████
Phase 34  worker-pool officially enabled                          ████████
Phase 35  Phase 34 robustness review                              ██████
Phase 36  GPL v3 reclassification (partially reverted P37)        ████
Phase 37  License reconciliation (final classification)           ██████
Phase 38  PGN cache UI + captured-pieces + toggle-exit            ██████████
Phase 39  PGN cache tag-filter buttons + engine config layout     ██████████
Phase 40  Castle-rights root-cause fix + button width attempt #1  ████████████
Phase 41  Haptic / sound matching audit                           ██████████
Phase 42  "Save PGN? → No" castle-rights root-cause fix           ████████
Phase 43  Reset-board castle markers + redundancy cleanup         ██████████
Phase 44  Button width fit-content (failed)                       ████
Phase 45  Fix Phase 44 broken attribute                           ████
Phase 46  Final review (sound-haptic decoupling)                  ██████████
Phase 47  Button width flex:0 0 auto (failed)                     ████
Phase 48  Button width .btn-compact + !important (failed)         ██████
Phase 49  5-parallel-subagent review (6 bugs + 12 robustness)     ██████████████████████
Phase 50  Button width TRUE root-cause (.btn-row vs grid) ✅       ████████████
Phase 51  PGN castling fix + "Mediocre" label + chart visibility   ████████████
Full Phase-by-Phase Changelog

See README.md § "Version History" and the HTML manuals' Appendix A for the complete, detailed changelog with every fix, optimization, and design decision.

Phase 51 — Three final fixes: (1) PGN round-trip castling failure — _castleSide() now checks mv.to.castle (set by pseudoMoves) in addition to mv.castle (set by executeMove); the PGN-replay path was calling makeMvInPlace directly with a move object whose top-level castle flag was undefined, so castling only moved the king and subsequent rook moves failed to parse. (2) Move-classification label "Book"→"Mediocre" / "开局库"→"平常". (3) Eval-chart dark-mode negative-eval line color #1A1A2E (invisible) → #5dade2 (light blue).

Phase 50 — Button-width TRUE root-cause fix: .btn-row opts out of the portrait grid transform. The buttons were grid items, not flex items — which is why every flex-based fix (Phase 44/47/48/49) failed.

Phase 49 — Comprehensive 5-parallel-subagent review: 6 bugs (Chess960 king-capture, importPGN data-loss, onHintMove staleness, Blob URL leak, PGN comment truncation, heatmap cache collision), 12 robustness hardenings (parseInt radix, HapticManager re-init, volatile fields, ChessApp stack-trace sanitization, chmod zombie cleanup), redundancy removal (dead lastRec.variation, dead CSS rules, dead worker round-trip), and NOTICE/README.license license-classification reconciliation.

Phase 48.btn-compact CSS class with 7 !important declarations.

Phase 47 — Inline display:inline-flex;flex:0 0 auto;width:auto.

Phase 46 — Sound-haptic decoupling (sound = independent if, haptic = exclusive if/else if); importPGNAsync success detection via gameState reference comparison.

Phase 45 — Fixed Phase 44's sed-eaten closing quote.

Phase 44width:fit-content (ineffective in WebView flex).

Phase 43♻️ Reset Board seeds setupCastleMarks; Phase 38-42 redundancy cleanup.

Phase 42_exitSetupImpl castle-rights re-validation root cause.

Phase 41 — Haptic/sound matching audit; single-haptic-per-turn invariant; CASTLE/PROMOTION throttle entries.

Phase 40computeVisibleCastleMarks/computeVisibleEpMark check setupMode flag.

Phase 39 — PGN cache "Tagged"/"Untagged" filter buttons; engine config compact layout.

Phase 38 — PGN cache horizontal button layout; getCapturedPieces empty-on-no-history.

Phase 37 — Final license classification (6 files → AGPL v3, 3 files → GPL v3).

Phase 36 — GPL v3 reclassification (partially reverted by Phase 37).

Phase 35 — Phase 34 robustness: terminateWorkerPool rejects pending + queued.

Phase 34 — Worker-pool officially enabled for async PGN import.

Phase 33isDeadPosition knight-guard; 42 stale comments cleaned.

Phase 32_escJs XSS fix; StabilizationHelper dt; worker-pool queue cap; parseInt radix.

Phase 31getCtrlMap hidden-class stabilization; ECO pre-indexing.

Phase 30 — 2 high + 8 medium bugs (XSS hardening, dead code, header consistency).

Phase 29 — Setup ⚡ normalization; castle sound/haptic redesign; light-mode contrast; Safe Browsing; onRenderProcessGone; 6-step WebView destroy.

Phase 28 — 8 bug fixes (_reattachActiveAnimations, pawn-rank formula, _checkPVDivergence field name, Chess960 FEN corruption, stats dark palette, heatmap cache, PWLE fallback, landscape safe-area).

Phase 27 — Knight / bishop / rook dedicated haptics; all six pieces now have personality.

Phase 26 — Personified animation/sound/haptic upgrade; notch adaptation; shake/anti-shake coexistence; landscape board shrink; Worker race fix.

Phase 25 — Worker-pool rewrite (N workers, Blob-URL, 30s timeout, taskId map).

Phase 24 — First-principles review: 7 subagents, ~135 issues, 21 bug fixes, dead worker-pool.js removed.

Phase 23 — ⚡ marker CSS selector fix; WAAPI overlay retention; Stockfish 18 dotprod.

Phase 22 — Full move-animation + sound redesign; light mode.


🙏 Acknowledgements

Regalia stands on the shoulders of giants:

  • Peter Österlund for DroidFish — the engine management, game logic, and PGN parsing foundations
  • The Stockfish team — T. Romstad, M. Costalba, J. Kiiski, G. Linscott — for the strongest chess engine in the world
  • Lichess — for the Tablebase API and the CC0 opening data
  • Everyone who reported bugs, especially the button-width issue that took 7 phases to truly solve — your persistence made the fix possible

📊 Stats

Metric Value
Source lines (JS + Java + native + config) ~27,000
Development phases (Phase 22 → 51) 30
First-principles code reviews 5
Bug fixes shipped in v1.0.8 40+
Piece personalities (animation + sound + haptic) 6
APK signature schemes v1 ✅ v2 ✅ v3 ✅
Minimum Android 5.0 (API 21)
Target Android 15 (API 35)
Engine Stockfish 18 (arm64-v8a-dotprod)

Source code: https://github.com/YDW99/Regalia

Regalia v1.0.8 — where every piece has a soul.


AI-GEN