feat: add sound effects, improved stroke recognition, instant locale switching with scramble text animation
Release Build / build-docker (push) Successful in 1m9s
Release Build / build-android-and-release (push) Successful in 7m14s

- Add SoundManager with Web Audio API synthesized sounds (stroke error, drawing complete, session complete)
- Add sound effects toggle in settings (persisted via localStorage)
- Improve stroke recognition: curvature similarity, max point deviation, stroke length ratio checks
- Loosen thresholds for long strokes and first-stroke positioning
- Implement instant locale switching (no save required)
- Add ScrambleText component with character-by-character morphing animation
- Apply ScrambleText globally across all views, widgets, and dialogs
- Add i18n keys for sound effects settings (EN/DE/JA)
This commit is contained in:
2026-04-18 22:19:36 +02:00
parent 979f8fc5e1
commit 049eaa1807
18 changed files with 907 additions and 166 deletions
+36
View File
@@ -44,8 +44,13 @@ const messages = {
learned: "You've learned {n} new kanji.",
components: 'Components',
observe: 'Observe Stroke Order',
replay: 'Replay',
trace: 'Trace',
drawStep: 'Draw ({n}/{total})',
sectionMeaning: 'Meaning',
sectionMnemonic: 'Memory Aid',
sectionReadings: 'Readings',
learnedKanji: 'Kanji Learned',
backToDashboard: 'Back to Dashboard',
},
hero: {
@@ -70,6 +75,7 @@ const messages = {
next24: 'Next 24h',
availableNow: 'Available Now',
inHours: 'In {n} hour | In {n} hours',
inDays: 'In {n} day | In {n} days',
noIncoming: 'No reviews incoming for 24 hours.',
items: 'items',
reviewsCount: '{count} reviews',
@@ -96,6 +102,9 @@ const messages = {
strict: 'Strict',
loose: 'Loose',
save: 'Save & Close',
soundEffects: 'Sound Effects',
on: 'On',
off: 'Off',
},
review: {
meaning: 'Meaning',
@@ -109,6 +118,9 @@ const messages = {
next: 'NEXT',
sessionComplete: 'Session Complete!',
levelup: 'You leveled up your Kanji skills.',
levelsUp: '{n} leveled up',
levelsDown: '{n} leveled down',
results: 'Results',
back: 'Back to Collection',
caughtUp: 'All Caught Up!',
noReviews: 'No reviews available right now.',
@@ -174,8 +186,13 @@ const messages = {
learned: 'Du hast {n} neue Kanji gelernt.',
components: 'Komponenten',
observe: 'Strichfolge beobachten',
replay: 'Wiederholen',
trace: 'Nachzeichnen',
drawStep: 'Zeichnen ({n}/{total})',
sectionMeaning: 'Bedeutung',
sectionMnemonic: 'Merkhilfe',
sectionReadings: 'Lesungen',
learnedKanji: 'Gelernte Kanji',
backToDashboard: 'Zurück zur Übersicht',
},
hero: {
@@ -200,6 +217,7 @@ const messages = {
next24: 'Nächste 24h',
availableNow: 'Jetzt verfügbar',
inHours: 'In {n} Stunde | In {n} Stunden',
inDays: 'In {n} Tag | In {n} Tagen',
noIncoming: 'Keine Reviews in den nächsten 24h.',
items: 'Einträge',
reviewsCount: '{count} Reviews',
@@ -226,6 +244,9 @@ const messages = {
strict: 'Strikt',
loose: 'Locker',
save: 'Speichern & Schließen',
soundEffects: 'Soundeffekte',
on: 'An',
off: 'Aus',
},
review: {
meaning: 'Bedeutung',
@@ -239,6 +260,9 @@ const messages = {
next: 'WEITER',
sessionComplete: 'Sitzung beendet!',
levelup: 'Du hast deine Kanji-Skills verbessert.',
levelsUp: '{n} aufgestiegen',
levelsDown: '{n} abgestiegen',
results: 'Ergebnisse',
back: 'Zurück zur Sammlung',
caughtUp: 'Alles erledigt!',
noReviews: 'Gerade keine Reviews verfügbar.',
@@ -304,8 +328,13 @@ const messages = {
learned: '{n}個の新しい漢字を覚えました。',
components: '構成要素',
observe: '書き順を見る',
replay: 'もう一度',
trace: 'なぞる',
drawStep: '書く ({n}/{total})',
sectionMeaning: '意味',
sectionMnemonic: '覚え方',
sectionReadings: '読み方',
learnedKanji: '学んだ漢字',
backToDashboard: 'ダッシュボードに戻る',
},
hero: {
@@ -330,6 +359,7 @@ const messages = {
next24: '今後24時間',
availableNow: '今すぐ可能',
inHours: '{n}時間後',
inDays: '{n}日後',
noIncoming: '24時間以内のレビューはありません。',
items: '個',
reviewsCount: '{count} レビュー',
@@ -356,6 +386,9 @@ const messages = {
strict: '厳しい',
loose: '甘い',
save: '保存して閉じる',
soundEffects: '効果音',
on: 'オン',
off: 'オフ',
},
review: {
meaning: '意味',
@@ -369,6 +402,9 @@ const messages = {
next: '次へ',
sessionComplete: 'セッション完了!',
levelup: '漢字力がアップしました。',
levelsUp: '{n}個昇格',
levelsDown: '{n}個降格',
results: '結果',
back: 'コレクションに戻る',
caughtUp: '完了しました!',
noReviews: '現在レビューするものはありません。',