Regalia v1.0.8
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
transformupdate — zero pixel ops. A single staticfilter: drop-shadowis 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.
Kxg1with the king on f1) was silently destroying pieces. Fixed with an empty-destination guard. importPGNdata-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 validatingstartStatebefore any side effects.onHintMoveapplied 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 anisHintLoadingstaleness guard mirroringonBestMove's pattern.- Worker-pool Blob URL leak —
new Worker(url)failures leaked the Blob URL forever. Fixed by hoistingurland 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
@mediarule (.dlg-sec > div[style*="display:flex"]) was converting the button containers fromdisplay: flextodisplay: gridwithgrid-template-columns: 1fr auto— a layout designed for label+input rows. The buttons became grid items, and grid items ignore allflexproperties. The fix: a.btn-rowmarker class + a higher-specificity override (0,3,1>0,2,1, later source order) that restoresdisplay: flexand neutralizesgrid-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
EngineServicekeeps 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 detection —
prefers-color-schemealone is unreliable on HyperOS 3, so we also readUiModeManageron the Java side and mirror it to adata-themeattribute - 6-step WebView destroy prevents render-process crash loops
onRenderProcessGonerecovery- APK signed with v1 + v2 + v3 schemes — all three verified ✅
♟️ Full Feature List
Click to expand the complete feature list
Engine & Play
- Stockfish 18 —
arm64-v8a-dotprodnative 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_Chess960option - 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–$19NAGs; 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()+vwscaling - 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— EnglishRegalia-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 assembleReleasePrerequisites: 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 44 — width: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 40 — computeVisibleCastleMarks/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 33 — isDeadPosition knight-guard; 42 stale comments cleaned.
Phase 32 — _escJs XSS fix; StabilizationHelper dt; worker-pool queue cap; parseInt radix.
Phase 31 — getCtrlMap 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