diff --git a/src/forest/scene.ts b/src/forest/scene.ts index 40e29b8..d573284 100644 --- a/src/forest/scene.ts +++ b/src/forest/scene.ts @@ -1,6 +1,55 @@ import type { Progress, LevelStatus } from "../types"; import { levels } from "../game/levels"; -import { getProgress } from "../storage/db"; +import { getProgress, getForestElements } from "../storage/db"; + +let activeObjectUrls: string[] = []; + +export async function renderForestScene( + db: IDBDatabase, + newElementId?: number, +): Promise { + const grid = document.getElementById("forest-grid"); + if (!grid) return; + + // Revoke old object URLs to prevent memory leaks + for (const url of activeObjectUrls) { + URL.revokeObjectURL(url); + } + activeObjectUrls = []; + + const elements = await getForestElements(db); + grid.innerHTML = ""; + + // Render up to 12 elements (4x3 grid) + const maxSlots = 12; + const toRender = elements.slice(0, maxSlots); + + for (const element of toRender) { + const slot = document.createElement("div"); + slot.className = "forest__element"; + + const img = document.createElement("img"); + const objectUrl = URL.createObjectURL(element.imageBlob); + activeObjectUrls.push(objectUrl); + img.src = objectUrl; + img.alt = element.description; + + // Random offset +-10-20px for natural placement + const offsetX = + (Math.random() > 0.5 ? 1 : -1) * (10 + Math.random() * 10); + const offsetY = + (Math.random() > 0.5 ? 1 : -1) * (10 + Math.random() * 10); + img.style.transform = `translate(${Math.round(offsetX)}px, ${Math.round(offsetY)}px)`; + + // Animate newly added element + if (element.id === newElementId) { + slot.classList.add("forest__element--new"); + } + + slot.appendChild(img); + grid.appendChild(slot); + } +} export function getLevelStatus( levelNum: number, @@ -62,6 +111,7 @@ export async function initForestScreen( if (!progress) return; renderLevelMap(mapContainer, progress, onStartLesson); + await renderForestScene(db); const allComplete = levels.every((l) => progress.completedLevels.includes(l.level),