From 24bcbd1bba8c9f048b1a1e10985532e24e6868d2 Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Sun, 29 Mar 2026 11:53:47 +0200 Subject: [PATCH] feat(02-02): add fallback texts module with German greetings, forest comments, and letter intros - 10 time-of-day keyed greetings (morgen/mittag/abend/any) - 10 forest element discovery comments - 13 letter introductions for levels 1-6 with finger mapping - Helper functions for random selection and letter lookup Co-Authored-By: Claude Opus 4.6 (1M context) --- src/companion/fallbacks.ts | 178 +++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/companion/fallbacks.ts diff --git a/src/companion/fallbacks.ts b/src/companion/fallbacks.ts new file mode 100644 index 0000000..bbcff6c --- /dev/null +++ b/src/companion/fallbacks.ts @@ -0,0 +1,178 @@ +/** + * Static fallback content for when the Gemini API is unavailable. + * All texts are in simple German suitable for a 7-year-old. + * No performance praise. Max 25 words per text. + */ + +export type TimeOfDay = "morgen" | "mittag" | "abend"; + +export interface FallbackGreeting { + text: string; + timeOfDay: TimeOfDay | "any"; +} + +export interface LetterIntro { + letter: string; + finger: string; + text: string; +} + +// --- Fallback Greetings (10 entries) --- + +export const fallbackGreetings: FallbackGreeting[] = [ + // Morning (3) + { + text: "Guten Morgen! Der Wald hat auf dich gewartet.", + timeOfDay: "morgen", + }, + { + text: "Frueh am Morgen ist der Wald am schoensten. Schoen, dass du da bist!", + timeOfDay: "morgen", + }, + { + text: "Die Voegel singen schon. Ein neuer Tag im Zauberwald beginnt!", + timeOfDay: "morgen", + }, + // Any time (4) + { + text: "Schoen, dass du wieder da bist! Der Wald freut sich.", + timeOfDay: "any", + }, + { + text: "Willkommen zurueck! Lass uns den Wald ein bisschen wachsen lassen.", + timeOfDay: "any", + }, + { + text: "Hallo! Ich glaube, heute entdecken wir etwas Neues im Wald.", + timeOfDay: "any", + }, + { + text: "Da bist du ja! Komm, lass uns zusammen in den Wald schauen.", + timeOfDay: "any", + }, + // Evening (3) + { + text: "Guten Abend! Der Wald leuchtet im Abendlicht ganz besonders.", + timeOfDay: "abend", + }, + { + text: "Die Gluehwuermchen sind schon unterwegs. Schoen, dass du da bist!", + timeOfDay: "abend", + }, + { + text: "Am Abend wird der Wald ganz still. Lass uns leise ueben.", + timeOfDay: "abend", + }, +]; + +// --- Fallback Forest Comments (10 entries) --- + +export const fallbackForestComments: string[] = [ + "Oh schau mal! Ein neuer Bewohner ist in unseren Wald gezogen!", + "Der Wald waechst und waechst! Was wird wohl als naechstes erscheinen?", + "Siehst du das? Etwas Neues hat sich zwischen den Baeumen versteckt!", + "Unser Wald wird immer bunter. Was fuer eine Ueberraschung!", + "Ein neues Stueck Wald ist dazugekommen. Wie schoen das aussieht!", + "Hast du das gesehen? Der Wald hat sich veraendert!", + "Es raschelt im Unterholz. Etwas Neues ist da!", + "Die Waldlichtung hat Zuwachs bekommen. Kannst du es entdecken?", + "Jedes Mal passiert etwas Neues im Wald. Schau genau hin!", + "Der Zauberwald hat ein Geschenk fuer dich bereit. Schau mal!", +]; + +// --- Fallback Letter Introductions (13 entries, levels 1-6) --- + +export const fallbackLetterIntros: LetterIntro[] = [ + // Level 1: F, J, Space + { + letter: "f", + finger: "linker Zeigefinger", + text: "Das F ist da, wo dein linker Zeigefinger zu Hause ist. Spuerst du den kleinen Huegel?", + }, + { + letter: "j", + finger: "rechter Zeigefinger", + text: "Das J hat einen kleinen Strich unten. Dein rechter Zeigefinger findet ihn sofort!", + }, + { + letter: " ", + finger: "Daumen", + text: "Die grosse Leertaste ganz unten drueckst du mit dem Daumen. Einfach druecken!", + }, + // Level 2: D, K + { + letter: "d", + finger: "linker Mittelfinger", + text: "Das D liegt direkt neben dem F. Dein Mittelfinger wohnt dort wie ein Vogel im Nest.", + }, + { + letter: "k", + finger: "rechter Mittelfinger", + text: "Das K ist der Nachbar vom J. Dein rechter Mittelfinger huepft einfach hinueber.", + }, + // Level 3: S, L + { + letter: "s", + finger: "linker Ringfinger", + text: "Das S ist wie eine Schlange. Dein Ringfinger gleitet sanft dorthin.", + }, + { + letter: "l", + finger: "rechter Ringfinger", + text: "Das L klingt wie das Lied der Lerche. Dein rechter Ringfinger kennt den Weg.", + }, + // Level 4: A, Oe + { + letter: "a", + finger: "linker kleiner Finger", + text: "Das A ist ganz am Rand. Dein kleiner Finger streckt sich wie ein Ast nach links.", + }, + { + letter: "รถ", + finger: "rechter kleiner Finger", + text: "Das Oe mit den zwei Punkten oben. Dein kleiner Finger rechts tippt es ganz leicht.", + }, + // Level 5: G, H + { + letter: "g", + finger: "linker Zeigefinger", + text: "Das G liegt neben dem F zur Mitte hin. Dein Zeigefinger macht einen kleinen Ausflug.", + }, + { + letter: "h", + finger: "rechter Zeigefinger", + text: "Das H ist der Nachbar vom J zur Mitte hin. Ein kurzer Sprung fuer deinen Zeigefinger!", + }, + // Level 6: E, I + { + letter: "e", + finger: "linker Mittelfinger", + text: "Das E wohnt eine Reihe hoeher ueber dem D. Dein Mittelfinger klettert wie ein Eichhoernchen hoch.", + }, + { + letter: "i", + finger: "rechter Mittelfinger", + text: "Das I sitzt ueber dem K. Dein rechter Mittelfinger springt hoch wie ein Igel huepft.", + }, +]; + +// --- Helper functions --- + +export function getRandomFallbackGreeting(timeOfDay: TimeOfDay): string { + const matching = fallbackGreetings.filter( + (g) => g.timeOfDay === timeOfDay || g.timeOfDay === "any", + ); + const index = Math.floor(Math.random() * matching.length); + return matching[index].text; +} + +export function getRandomFallbackForestComment(): string { + const index = Math.floor(Math.random() * fallbackForestComments.length); + return fallbackForestComments[index]; +} + +export function getFallbackLetterIntro( + letter: string, +): LetterIntro | undefined { + return fallbackLetterIntros.find((intro) => intro.letter === letter); +}