Vibecoded Port der ursprünglichen App von 2014
  • Svelte 54%
  • TypeScript 42.3%
  • CSS 3%
  • JavaScript 0.4%
  • HTML 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
root a190d7cb72 WIP: Sicherungsstand vom 27.09.2026
Uncommittete Änderungen gesichert (Sammel-Commit), damit der Stand auf
Forgejo liegt — ggf. noch halbfertige Arbeit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nis4Pzds5rZXdAQ8VBxKqP
2026-09-27 00:00:46 +00:00
.claude WIP: Sicherungsstand vom 27.09.2026 2026-09-27 00:00:46 +00:00
backend Configurable levels (admin CRUD), URL-based settings overrides, embed mode, notation refinements 2026-05-11 20:38:35 +02:00
src fix(exercise): Sitzungslänge und Level-ID nachziehen 2026-08-04 13:43:27 +00:00
static PWA: make app installable on Chrome (desktop + mobile) 2026-05-11 21:26:37 +00:00
.gitignore feat(embed): earTastic als einbettbare Bibliothek 2026-07-25 20:49:39 +00:00
.npmrc Initial commit: earTastic AI (SvelteKit PWA + PocketBase admin) 2026-05-11 19:28:22 +02:00
package-lock.json UI polish: Inter font, larger tile icons, white light-mode bg 2026-05-11 19:54:01 +00:00
package.json feat(embed): earTastic als einbettbare Bibliothek 2026-07-25 20:49:39 +00:00
README.md feat(audio): Samples vor der Wiedergabe laden und dekodieren 2026-08-04 11:23:25 +00:00
svelte.config.js Initial commit: earTastic AI (SvelteKit PWA + PocketBase admin) 2026-05-11 19:28:22 +02:00
tsconfig.json Initial commit: earTastic AI (SvelteKit PWA + PocketBase admin) 2026-05-11 19:28:22 +02:00
vite.config.lib.ts feat(embed): earTastic als einbettbare Bibliothek 2026-07-25 20:49:39 +00:00
vite.config.ts No direct repeats: filter previous question out of the random pool 2026-05-11 21:34:57 +00:00

earTastic AI

Eine vollständig neu geschriebene, moderne Webapp-Version der Gehörbildungs-App earTastic Pro (ursprünglich 2014/15 als Cordova-App entstanden). Dieses Repo ersetzt jQuery + RequireJS + Raphael + FullCalendar + Cordova durch einen schlanken, native-platform-freien Stack:

Bereich Stack
Framework SvelteKit 2 · Svelte 5 Runes · TypeScript strict
Styling Tailwind CSS v4 (CSS Variables, OKLCH-Theme)
Audio Web Audio API (eigene AudioEngine, kein Media)
Notation VexFlow 5
Persistenz IndexedDB via idb
PWA vite-plugin-pwa + Workbox
Tests Vitest (Music-Theory-Logik)
Build Vite, Static-Adapter (@sveltejs/adapter-static)
Distribution Plain static hosting (Netlify, Vercel, GH Pages, S3 …)
Einbettung ES-Modul-Bibliothek (build:lib) für fremde Apps

Nicht nur eine App — auch eine Bibliothek

earTastic lässt sich ohne seine Oberfläche benutzen. npm run build:lib erzeugt ein ES-Modul mit den Fragen-Generatoren, den Musikdaten, der AudioEngine und den Beschriftungen — gedacht für Anwendungen, die earTastics Musiktheorie und Klang brauchen, aber eine eigene Oberfläche mitbringen.

import * as ear from '/eartastic/build/lib/eartastic.js';

ear.configure({ audioBase: '/eartastic/build/audio' });   // Pflicht, s. u.

const q = ear.generateIntervalQuestion({
  enabled: ['k3', 'g3', '4', '5', '8'],
  mode: 'asc', rangeLow: 24, rangeHigh: 48,
});
await ear.audioEngine.playSequence('juno', q.playOrder, 750);
ear.label(q.key);                                          // → „Quinte"

Erster Abnehmer ist das Gehörbildungs-Widget der Unterrichtstafel (/var/www/piano): Die Lehrkraft spielt ein Intervall vor, die Klasse antwortet per Handy. Alles Musikalische daran kommt von hier — ändert sich in diesem Repo die Musiktheorie, zieht das Widget automatisch mit.

Details, Umfang und die Stolperstellen: Einbetten in andere Anwendungen.

Setup

Diese Maschine hat noch kein Node — installiere zuerst Node ≥ 20:

sudo pacman -S nodejs npm

Dann im Projekt-Root:

npm install
npm run dev          # http://localhost:5173
npm run build        # build/ enthält das deploybare Static-Bundle
npm run build:lib    # build/lib/eartastic.js — Einbettungs-Bibliothek
npm run build:all    # beides, in der richtigen Reihenfolge
npm run preview      # build lokal mit /preview-Server testen
npm run check        # svelte-check + TypeScript
npm test             # Vitest (Music-Engine-Tests)

Reihenfolge beachten: npm run build leert build/. Wer die Bibliothek mit ausliefern will, nimmt npm run build:all — sonst ist build/lib/ nach dem nächsten Build weg.

Einbetten in andere Anwendungen

Einstieg und Kurzbeispiel stehen oben; hier der Umfang und die drei Stellen, an denen man sonst hängenbleibt.

Der Einstiegspunkt ist src/lib/embed/index.ts, gebaut über vite.config.lib.ts (getrennt von vite.config.ts, weil dort SvelteKit, Tailwind und das PWA-Plugin hängen — nichts davon wird gebraucht, und sveltekit() akzeptiert den Bibliotheks-Einstiegspunkt gar nicht).

Enthalten

Generatoren generateIntervalQuestion, generateChordQuestion, generateScaleQuestion samt Fehlertypen
Musikdaten TONES, ALL_INTERVALS, INTERVAL_SEMITONES, CHORDS, SCALES, INSTRUMENTS, …
Klang audioEngine (playTone, playSequence, playChord, preload, playFx)
Beschriftungen label(key, locale), DICTIONARIES, LOCALES — vier Sprachen
Konfiguration configure({ audioBase, volume }), EMBED_API_VERSION

Nicht enthalten — bewusst: Svelte-Komponenten, Stores, IndexedDB-Zustand, VexFlow. Die einbettende App bringt ihre eigene Oberfläche mit.

Stolperstellen

1. audioBase ist Pflicht, sobald earTastic nicht an der Domain-Wurzel liegt. Die AudioEngine lud die Samples früher fest von /audio/…. Unter eartastic.krg.li stimmt das; unter einem Unterpfad wie /eartastic/build/ bekommt jedes Sample einen 404 — ohne sichtbaren Fehler, es bleibt einfach still. configure({ audioBase: '…/audio' }) setzt den Pfad um; der Standard /audio lässt das Verhalten der App unverändert.

2. Die Intervall-Schlüssel sind deutsch abgekürzt, nicht englisch: '1', k2, g2, k3, g3, '4', tr, '5', k6 … (siehe INTERVAL_SEMITONES in src/lib/data/music.ts). Ein englisches 'p5' oder 'M3' führt nicht zu einem Fehler, sondern zu einem irreführenden RangeTooNarrowError: unbekannte Schlüssel fallen bei der Halbton-Prüfung heraus, und übrig bleibt eine leere Auswahl.

3. build/ ist gitignored und npm run build leert es. Die gebaute Bibliothek liegt also nicht im Repo, und ein reines npm run build löscht sie beim nächsten Deployment wieder. Für Installationen, die sie mit ausliefern: npm run build:all.

Verzeichnis-Layout

src/
├── app.css                          # Tailwind v4 Tokens + Komponenten-Klassen
├── app.html                         # HTML-Shell
├── lib/
│   ├── audio/AudioEngine.ts         # Web Audio Fassade + Sample-Cache
│   ├── audio/Tuner.ts               # 440 Hz Sinus-Oszillator
│   ├── audio/Metronome.ts           # Look-Ahead-Scheduler (Chris-Wilson-Pattern)
│   ├── components/                  # Header, Toaster, Piano, Heatmap, AnswerScreen
│   ├── data/music.ts                # Typisierter Datensatz aus data.json
│   ├── diary/practiceTimer.ts       # visibilitychange-gesteuerter Sessions-Tracker
│   ├── i18n/                        # DE/EN/FR/ES-Dictionary + Store
│   ├── music/intervals.ts           # Generator + Test
│   ├── music/chords.ts              # Generator
│   ├── music/scales.ts              # Generator
│   ├── notation/Stave.svelte        # VexFlow-Wrapper
│   ├── settings/store.ts            # Settings-Store + IndexedDB-Persistenz
│   ├── stats/store.ts               # Stats-Counter
│   └── utils/{db,wakeLock,vibrate}.ts
├── routes/
│   ├── +layout.svelte               # globaler Header, Toaster, Sample-Vorladung
│   ├── +page.svelte                 # Overview
│   ├── exercises/{intervals,chords,scales,functions,melodies}/+page.svelte
│   ├── theory/{intervals,chords,scales,hauptstufen,notenlesen,klaviatur}/+page.svelte
│   ├── levels/+page.svelte          # Übungen nach Lernstufe
│   ├── admin/levels/+page.svelte    # Level-Verwaltung (PocketBase)
│   ├── piano/+page.svelte
│   ├── metronome/+page.svelte
│   ├── stats/+page.svelte
│   ├── diary/+page.svelte           # Heatmap (12 Wochen)
│   └── settings/+page.svelte
static/
├── audio/{juno,nylon,homechurch}/   # 60+ WAV-Samples pro Instrument
├── audio/fx/                        # 440hz.mp3, welcome.mp3 etc.
├── img/composers/                   # 17 JPGs für Antwort-Screens
├── favicon.svg
└── icons/                           # PWA-Icons (siehe icons/README.md)

Was funktioniert

  • Overview, Settings (vollständig, inkl. Tonumfang, Instrumenten- und Intervall-/Akkord-/Skalenauswahl), Stats, Diary (Heatmap, Aggregation), Piano (60 Tasten, Sample-Wiedergabe via Web Audio, optionale Vibration, Stop-on-release), Metronom (Look-Ahead, akzentuierter Downbeat), Stimmgabel (440 Hz Sinus über OscillatorNode), Theorie-Seiten (Hör-Demo aller Intervalle/Akkorde/Skalen ausgehend von C).
  • Intervall-Übung end-to-end: 4 Modi (asc / desc / sim / sim+Noten), Antwort- auswahl per Multiple-Choice, Stats werden persistiert, Vibration, Wake-Lock, Practice-Timer mit Pause/Resume.
  • Akkord-Übung und Skalen-Übung funktional analog zu Intervallen.
  • i18n DE/EN/FR/ES — Locale persistiert in localStorage.
  • PWA: Manifest, Service Worker mit Cache-First-Strategie für Audio-Samples.
  • Sample-Vorladung (src/lib/audio/preload.ts): Beim Start werden alle 61 Töne des aktiven Instruments plus die FX-Sounds geladen; beim ersten Antippen dekodiert AudioEngine.unlock() sie in einem Zug. Zwei Stufen, weil Autoplay-Regeln keinen AudioContext ohne Nutzer-Interaktion erlauben. Die übrigen Instrumente wandern danach still in den Cache — bewusst ohne Dekodieren, alle drei Sätze zusammen wären einige Dutzend Megabyte im Speicher.

Erweiterungspunkte

Was Wie
Adaptive Aufgabenwahl Generatoren in src/lib/music/{intervals,chords,scales}.ts würfeln gleichverteilt. Gewichtung nach Trefferquote aus src/lib/stats/store.ts einziehen.
Übungssitzung mit festem Umfang Aufgabenzähler in den Übungsseiten + Ergebnisbildschirm neben src/lib/components/AnswerScreen.svelte.
Tastatur-Shortcuts Bisher kein Keyboard-Handling in der App; gemeinsamer Helfer für 1–9, Leertaste (erneut abspielen), Enter (weiter).
Level-Fortschritt /levels ist eine Linkliste; Versuche/Bestquote pro Level in kv (siehe utils/db.ts) und Rückkanal aus den Übungsseiten.
Charts in Stats chart.js oder eigenes SVG-Bar-Chart in src/lib/components/Bars.svelte.
Pieces / Komponisten-Diary Eigene IDB-Tabelle pieces in utils/db.ts ergänzen, Route /diary/pieces.

Was bewusst weggelassen wurde

  • Cordova/PhoneGap, Media-Plugin, device.platform, backbutton, alles was an window.analytics, navigator.app oder cordova.js hing.
  • jQuery, Raphael, FullCalendar, OwlCarousel, Modernizr, RequireJS, FastClick — durch Svelte-Komponenten und Web-Plattform-APIs ersetzt.
  • Google Analytics. Wenn Analytics gewünscht, einfach Plausible/Umami als <script>-Tag in src/app.html einfügen.