+
+
![]()
+
+
diff --git a/src/app.ts b/src/app.ts
index 6681f52..a648ac7 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -2,6 +2,8 @@ import type { ScreenName } from "./types";
import { openDB, getProgress, saveProgress } from "./storage/db";
import { initWelcomeScreen, initLessonScreen } from "./ui/screens";
import { initForestScreen } from "./forest/scene";
+import { getGreeting } from "./companion/companion";
+import { companions } from "./companion/characters";
let db: IDBDatabase;
let lessonCleanup: (() => void) | null = null;
@@ -89,6 +91,27 @@ export async function initApp(): Promise
{
// Returning user -- init forest and go there
await initForestScreen(db, startLessonFromForest);
showScreen("forest");
+
+ // Show companion greeting (per COMP-01, D-14)
+ const companion = companions.find(
+ (c) => c.type === progress.selectedCharacter,
+ );
+ if (companion) {
+ const greetingEl = document.getElementById("forest-greeting")!;
+ const avatarEl = document.getElementById(
+ "forest-greeting-avatar",
+ ) as HTMLImageElement;
+ const textEl = document.getElementById("forest-greeting-text")!;
+
+ avatarEl.src = companion.avatarUrl;
+ avatarEl.alt = companion.name;
+ greetingEl.style.display = "flex";
+
+ // Fetch greeting async (shows immediately with avatar, text fills in)
+ getGreeting(progress.selectedCharacter, db).then((text) => {
+ textEl.textContent = text;
+ });
+ }
} else {
// First time -- show welcome, then forest after setup
initWelcomeScreen(db, async (screen: ScreenName) => {
diff --git a/src/companion/fallbacks.ts b/src/companion/fallbacks.ts
index bbcff6c..c652ea9 100644
--- a/src/companion/fallbacks.ts
+++ b/src/companion/fallbacks.ts
@@ -163,12 +163,12 @@ export function getRandomFallbackGreeting(timeOfDay: TimeOfDay): string {
(g) => g.timeOfDay === timeOfDay || g.timeOfDay === "any",
);
const index = Math.floor(Math.random() * matching.length);
- return matching[index].text;
+ return matching[index]?.text ?? "Willkommen im Zauberwald!";
}
export function getRandomFallbackForestComment(): string {
const index = Math.floor(Math.random() * fallbackForestComments.length);
- return fallbackForestComments[index];
+ return fallbackForestComments[index] ?? "Schau mal, was im Wald passiert!";
}
export function getFallbackLetterIntro(
diff --git a/src/ui/screens.ts b/src/ui/screens.ts
index 1de9bf4..48664b9 100644
--- a/src/ui/screens.ts
+++ b/src/ui/screens.ts
@@ -5,7 +5,7 @@ import type {
Progress,
} from "../types";
import { companions } from "../companion/characters";
-import { saveProgress } from "../storage/db";
+import { saveProgress, getProgress } from "../storage/db";
import {
createExerciseState,
handleKeyPress,
@@ -88,6 +88,22 @@ export function initLessonScreen(
const backBtn = document.getElementById("lesson-back-btn") as HTMLButtonElement;
const state = createExerciseState(level);
+ // Show companion avatar (per ASST-04)
+ getProgress(_db).then((progress) => {
+ if (!progress) return;
+ const companion = companions.find(
+ (c) => c.type === progress.selectedCharacter,
+ );
+ if (!companion) return;
+ const area = document.getElementById("lesson-companion")!;
+ const avatar = document.getElementById(
+ "lesson-companion-avatar",
+ ) as HTMLImageElement;
+ avatar.src = companion.avatarUrl;
+ avatar.alt = companion.name;
+ area.style.display = "flex";
+ });
+
// Render keyboard
renderKeyboard(keyboardContainer, layout, level);