const workspace = document.getElementById('workspace'); const spawnBtns = document.querySelectorAll('.spawn-btn'); const clearDeskBtn = document.getElementById('clear-desk-btn'); const discoveryBook = document.getElementById('discovery-book'); const discoveryProgress = document.getElementById('discovery-progress'); const atomCountEl = document.getElementById('atom-count'); const moleculeCountEl = document.getElementById('molecule-count'); // Modal Elements const infoModal = document.getElementById('info-modal'); const modalTitle = document.getElementById('modal-title'); const modalFormula = document.getElementById('modal-formula-badge'); const modalName = document.getElementById('modal-molecule-name'); const modalDesc = document.getElementById('modal-description'); const modalCloseBtn = document.getElementById('modal-close-btn'); const modalOverlay = document.querySelector('.modal-overlay'); let elementsOnDesk = []; let draggingElement = null; let offsetX = 0; let offsetY = 0; // Elemente Datenbank für Spawnen (Symbole, Farben, Namen) const elementDetails = { 'H': { color: '#ff7675', name: 'Wasserstoff' }, 'O': { color: '#74b9ff', name: 'Sauerstoff' }, 'C': { color: '#2d3436', name: 'Kohlenstoff' }, 'N': { color: '#a29bfe', name: 'Stickstoff' }, 'Na': { color: '#ffeaa7', name: 'Natrium' }, 'Cl': { color: '#55efc4', name: 'Chlor' }, 'S': { color: '#fdcb6e', name: 'Schwefel' }, 'Fe': { color: '#b2bec3', name: 'Eisen' } }; // Rezepturenbuch (die Formeln müssen genau den Kombinationen der Symbole entsprechen) const recipes = [ { id: 'h2o', ingredients: ['H', 'H', 'O'], // 2x Wasserstoff, 1x Sauerstoff result: 'H₂O (Wasser)', color: '#3498db', desc: 'Wasser ist die absolute Grundlage allen bekannten Lebens! Über 70% der Erdoberfläche sind mit Wasser bedeckt, und auch unser eigener Körper besteht zu mehr als der Hälfte daraus.' }, { id: 'nacl', ingredients: ['Cl', 'Na'], // 1x Natrium, 1x Chlor result: 'NaCl (Kochsalz)', color: '#f5f6fa', desc: 'Natriumchlorid kennen wir alle als einfaches Speisesalz. Faszinierend: Natrium ist ein explosives, hochreaktives Metall und Chlor ein giftiges Gas – zusammen ergeben sie ein absolut lebenswichtiges und leckeres Gewürz!' }, { id: 'o2', ingredients: ['O', 'O'], // 2x Sauerstoff result: 'O₂ (Sauerstoff-Molekül)', color: '#a8dadc', desc: 'Der molekulare Sauerstoff, den wir jede Sekunde atmen. Pflanzen produzieren ihn als Abfallprodukt bei der Photosynthese, während sie Kohlendioxid abbauen.' }, { id: 'co2', ingredients: ['C', 'O', 'O'], // 1x Kohlenstoff, 2x Sauerstoff result: 'CO₂ (Kohlendioxid)', color: '#7f8c8d', desc: 'Ein farb- und geruchloses Treibhausgas. Wir atmen es ständig aus. Obwohl es die Erderwärmung anheizt, ist es für Pflanzen lebenswichtig, da sie es zur Photosynthese benötigen.' }, { id: 'ch4', ingredients: ['C', 'H', 'H', 'H', 'H'], // 1x Kohlenstoff, 4x Wasserstoff result: 'CH₄ (Methan)', color: '#fdcb6e', desc: 'Methan ist das einfachste Alkan und der Hauptbestandteil von brennbarem Erdgas. Es brennt sauber ab, ist aber als Treibhausgas in der Atmosphäre rund 25-mal klimaschädlicher als CO₂!' }, { id: 'nh3', ingredients: ['N', 'H', 'H', 'H'], // 1x Stickstoff, 3x Wasserstoff result: 'NH₃ (Ammoniak)', color: '#9b59b6', desc: 'Ein stechend riechendes, farbloses Gas. Ammoniak ist extrem wichtig für die chemische Industrie, da es die Grundlage für fast alle Kunstdünger bildet (erfunden durch das Haber-Bosch-Verfahren).' }, { id: 'hcl', ingredients: ['Cl', 'H'], // 1x Chlor, 1x Wasserstoff result: 'HCl (Salzsäure)', color: '#e17055', desc: 'Chlorwasserstoff ist ein stechendes Gas. In Wasser gelöst bildet es die extrem ätzende Salzsäure – diese ist auch ein wichtiger Bestandteil unseres eigenen Magensaftes, um Nahrung zu zersetzen!' }, { id: 'naoh', ingredients: ['H', 'Na', 'O'], // 1x Natrium, 1x Sauerstoff, 1x Wasserstoff result: 'NaOH (Natronlauge)', color: '#fd79a8', desc: 'Natriumhydroxid ist eine extrem starke Base. In Wasser gelöst wird es als Natronlauge bezeichnet, die Haare und Fett auflösen kann, weshalb man sie oft in Abflussreinigern findet. Sie wird auch für echte Seife genutzt.' }, { id: 'h2s', ingredients: ['H', 'H', 'S'], // 2x Wasserstoff, 1x Schwefel result: 'H₂S (Schwefelwasserstoff)', color: '#ffeaa7', desc: 'Dieses hochentzündliche und extrem giftige Gas riecht unverkennbar nach faulen Eiern! Es entsteht bei Fäulnisprozessen von Proteinen, im Darm und in vulkanischen Gasen.' }, { id: 'fes', ingredients: ['Fe', 'S'], // 1x Eisen, 1x Schwefel result: 'FeS (Eisensulfid)', color: '#2d3436', desc: 'Ein dunkelbrauner/schwarzer Feststoff. Das Mischen und Erhitzen von Eisenpulver und Schwefelpulver ist der absolute Klassiker im Chemie-Unterricht, um eine chemische Synthese zu demonstrieren.' }, { id: 'so2', ingredients: ['O', 'O', 'S'], // 1x Schwefel, 2x Sauerstoff result: 'SO₂ (Schwefeldioxid)', color: '#b2bec3', desc: 'Ein stechend riechendes, saures Gas, das beim Verbrennen von schwefelhaltigen fossilen Brennstoffen entsteht. Es schädigt die Atemwege und trägt in Wolken zur Bildung von saurem Regen bei.' }, { id: 'co', ingredients: ['C', 'O'], // 1x Kohlenstoff, 1x Sauerstoff result: 'CO (Kohlenmonoxid)', color: '#636e72', desc: 'Ein unsichtbares, geruchloses und hochgradig tödliches Gas! Es entsteht bei der unvollständigen Verbrennung von Kohle oder Holz und blockiert die Sauerstoffaufnahme im menschlichen Blutkreislauf.' }, { id: 'h2o2', ingredients: ['H', 'H', 'O', 'O'], // 2x Wasserstoff, 2x Sauerstoff result: 'H₂O₂ (Wasserstoffperoxid)', color: '#74b9ff', desc: 'Wasserstoffperoxid ist ein extrem starkes Bleichmittel und Oxidationsmittel. Es wird zum Blondieren von Haaren, zum Desinfizieren von Wunden und industriell zum Bleichen von Papier genutzt.' }, { id: 'hcn', ingredients: ['C', 'H', 'N'], // 1x Wasserstoff, 1x Kohlenstoff, 1x Stickstoff result: 'HCN (Blausäure)', color: '#d63031', desc: 'Cyanwasserstoff ist ein extrem giftiges Gas, das gelöst in Wasser als Blausäure bezeichnet wird. Es riecht für manche Menschen charakteristisch nach bitteren Mandeln und wirkt in Sekunden tödlich.' }, { id: 'n2', ingredients: ['N', 'N'], // 2x Stickstoff result: 'N₂ (Stickstoff)', color: '#a29bfe', desc: 'Stickstoff ist ein extrem reaktionsträges (inertes) Gas und bildet fast 78% der Luft, die wir atmen! Er schützt unseren Planeten vor verheerenden globalen Bränden, die in reinem Sauerstoff wüten würden.' }, { id: 'cl2', ingredients: ['Cl', 'Cl'], // 2x Chlor result: 'Cl₂ (Chlor)', color: '#55efc4', desc: 'Chlor-Gas ist giftig, hat einen stechenden Geruch und eine grüngelbe Farbe. Es wurde im Ersten Weltkrieg als Kampfgas eingesetzt, rettet heute aber als Desinfektionsmittel in Trinkwasser und Pools Millionen Leben.' }, { id: 'h2', ingredients: ['H', 'H'], // 2x Wasserstoff result: 'H₂ (Wasserstoff)', color: '#ff7675', desc: 'Das häufigste, einfachste und leichteste Element im Universum. Wasserstoff ist hochentzündlich (Knallgas-Reaktion) und bildet den primären Kernbrennstoff für alle leuchtenden Sterne.' }, { id: 'c2h4', ingredients: ['C', 'C', 'H', 'H', 'H', 'H'], // 2x Kohlenstoff, 4x Wasserstoff result: 'C₂H₄ (Ethen)', color: '#ffeaa7', desc: 'Ethen (Ethylen) ist ein gasförmiges Pflanzenhormon, das Früchte reifen lässt. Industriell ist es der absolut wichtigste Baustein zur Herstellung des Kunststoffs Polyethylen (PE).' } ]; // Geladene Entdeckungen aus dem LocalStorage let discoveredMolecules = new Set(JSON.parse(localStorage.getItem('chem_lab_discoveries') || '[]')); // Initiales Laden updateStats(); renderDiscoveryBook(); // Button-Klicks registrieren für Spawnen spawnBtns.forEach(btn => { btn.addEventListener('click', () => { const symbol = btn.dataset.element; const color = btn.dataset.color; spawnAtom(symbol, color); }); }); // Tisch leeren Button clearDeskBtn.addEventListener('click', () => { workspace.innerHTML = ''; elementsOnDesk = []; updateStats(); }); // Modal Events modalCloseBtn.addEventListener('click', closeModal); modalOverlay.addEventListener('click', closeModal); function closeModal() { infoModal.classList.add('hidden'); } function spawnAtom(symbol, color) { const el = document.createElement('div'); el.classList.add('atom'); el.innerText = symbol; el.dataset.symbol = symbol; el.style.backgroundColor = color; // Farblich angepasster Text für dunkle Elemente if (symbol === 'C' || symbol === 'Fe') { el.style.color = '#fff'; } else { el.style.color = '#333'; } // Zufällige Position auf dem Tisch const x = Math.random() * (workspace.clientWidth - 60); const y = Math.random() * (workspace.clientHeight - 60); el.style.left = x + 'px'; el.style.top = y + 'px'; makeDraggable(el); workspace.appendChild(el); elementsOnDesk.push(el); updateStats(); // Animation beim Erscheinen el.animate([ { transform: 'scale(0)' }, { transform: 'scale(1.1)' }, { transform: 'scale(1)' } ], { duration: 250, easing: 'ease-out' }); } function makeDraggable(el) { el.addEventListener('mousedown', (e) => { draggingElement = el; const rect = el.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; el.style.zIndex = 1000; // Füge Schatten beim Ziehen hinzu el.style.boxShadow = '0 10px 20px rgba(0,0,0,0.4)'; }); } document.addEventListener('mousemove', (e) => { if (draggingElement) { const workspaceRect = workspace.getBoundingClientRect(); let newX = e.clientX - workspaceRect.left - offsetX; let newY = e.clientY - workspaceRect.top - offsetY; // Grenzen des Workspaces beachten newX = Math.max(0, Math.min(newX, workspaceRect.width - draggingElement.offsetWidth)); newY = Math.max(0, Math.min(newY, workspaceRect.height - draggingElement.offsetHeight)); draggingElement.style.left = newX + 'px'; draggingElement.style.top = newY + 'px'; } }); document.addEventListener('mouseup', () => { if (draggingElement) { draggingElement.style.zIndex = ''; draggingElement.style.boxShadow = ''; checkForReactions(); draggingElement = null; } }); function checkForReactions() { if (!draggingElement) return; // Finde alle Elemente, die sich berühren (inklusive des gezogenen Elements) let cluster = [draggingElement]; let added = true; while(added) { added = false; for (let el of elementsOnDesk) { if (cluster.includes(el)) continue; // Prüfe Kollision mit irgendeinem Element im Cluster let touches = cluster.some(cEl => { const r1 = cEl.getBoundingClientRect(); const r2 = el.getBoundingClientRect(); return !(r1.right < r2.left || r1.left > r2.right || r1.bottom < r2.top || r1.top > r2.bottom); }); if (touches) { cluster.push(el); added = true; } } } if (cluster.length > 1) { // Ignoriere Cluster, die bereits Moleküle enthalten (nur Atome fusionieren in diesem Prototyp) const hasMolecule = cluster.some(el => el.classList.contains('molecule')); if (hasMolecule) return; const symbols = cluster.map(el => el.dataset.symbol).sort(); // Prüfe gegen alle Rezepte for (const recipe of recipes) { const recipeSymbols = [...recipe.ingredients].sort(); if (JSON.stringify(symbols) === JSON.stringify(recipeSymbols)) { // REAKTION! const midX = parseFloat(draggingElement.style.left) + draggingElement.offsetWidth / 2; const midY = parseFloat(draggingElement.style.top) + draggingElement.offsetHeight / 2; // Lösche fusionierte Atome vom Tisch cluster.forEach(el => { if (workspace.contains(el)) { workspace.removeChild(el); } elementsOnDesk = elementsOnDesk.filter(e => e !== el); }); // Partikel-Explosion erzeugen triggerExplosion(midX, midY, recipe.color); // Neues Molekül erstellen const molX = midX - 60; // Zentrieren const molY = midY - 20; createMolecule(recipe, molX, molY); // Entdeckung registrieren const isNew = !discoveredMolecules.has(recipe.id); if (isNew) { discoveredMolecules.add(recipe.id); localStorage.setItem('chem_lab_discoveries', JSON.stringify([...discoveredMolecules])); renderDiscoveryBook(); } // Info-Modal anzeigen (bei neuer Entdeckung) showModal(recipe, isNew); break; } } } } function createMolecule(recipe, x, y) { const el = document.createElement('div'); el.classList.add('molecule'); el.innerText = recipe.result.split(' ')[0]; // Zeigt z.B. H₂O an el.dataset.symbol = recipe.result; el.style.backgroundColor = recipe.color; // Grenzen im Workspace einhalten const maxLeft = workspace.clientWidth - 120; const maxTop = workspace.clientHeight - 40; el.style.left = Math.max(0, Math.min(x, maxLeft)) + 'px'; el.style.top = Math.max(0, Math.min(y, maxTop)) + 'px'; makeDraggable(el); workspace.appendChild(el); elementsOnDesk.push(el); updateStats(); // Entstehungsanimation el.animate([ { transform: 'scale(0.5)' }, { transform: 'scale(1.2)' }, { transform: 'scale(1)' } ], { duration: 300, easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)' }); } function triggerExplosion(x, y, color) { const numParticles = 18; for (let i = 0; i < numParticles; i++) { const p = document.createElement('div'); p.classList.add('particle'); p.style.backgroundColor = color || '#ff7675'; p.style.left = x + 'px'; p.style.top = y + 'px'; workspace.appendChild(p); // Zufälliger Winkel und Geschwindigkeit für Explosion const angle = Math.random() * Math.PI * 2; const velocity = 40 + Math.random() * 80; const targetX = Math.cos(angle) * velocity; const targetY = Math.sin(angle) * velocity + 20; // Leichte Gravitation (nach unten gezogen) p.animate([ { transform: 'translate(0, 0) scale(1)', opacity: 1 }, { transform: `translate(${targetX}px, ${targetY}px) scale(0)`, opacity: 0 } ], { duration: 600 + Math.random() * 300, easing: 'cubic-bezier(0.1, 0.8, 0.3, 1)', fill: 'forwards' }); setTimeout(() => p.remove(), 1000); } } function showModal(recipe, isNew = true) { if (isNew) { modalTitle.innerText = "Molekül entdeckt! 🎉"; document.querySelector('.modal-emoji').innerText = "🎉"; } else { modalTitle.innerText = "Molekül-Lexikon 📖"; document.querySelector('.modal-emoji').innerText = "📖"; } // Subscripts für Formel schön rendern const prettyFormula = recipe.id.toUpperCase().replace(/\d/g, m => '' + m + ''); modalFormula.innerHTML = prettyFormula; modalFormula.style.backgroundColor = recipe.color; // Reiner Name (Text in Klammern aus z.B. "H₂O (Wasser)") const cleanName = recipe.result.substring(recipe.result.indexOf('(') + 1, recipe.result.indexOf(')')); modalName.innerText = cleanName; modalDesc.innerText = recipe.desc; infoModal.classList.remove('hidden'); } function renderDiscoveryBook() { discoveryBook.innerHTML = ''; let count = 0; recipes.forEach(recipe => { const isDiscovered = discoveredMolecules.has(recipe.id); const item = document.createElement('div'); item.classList.add('book-item'); // Formel mit tiefgestellten Ziffern const prettyFormula = recipe.id.toUpperCase().replace(/\d/g, m => '' + m + ''); if (isDiscovered) { item.classList.add('unlocked'); // Reiner Name aus Rezept const cleanName = recipe.result.substring(recipe.result.indexOf('(') + 1, recipe.result.indexOf(')')); item.innerHTML = ` ${prettyFormula} ${cleanName} 🔓 `; item.addEventListener('click', () => { showModal(recipe, false); }); count++; } else { item.classList.add('locked'); item.innerHTML = ` 🧪 ??? Unbekannt 🔒 `; } discoveryBook.appendChild(item); }); discoveryProgress.innerText = `${count}/${recipes.length}`; } function updateStats() { const atoms = elementsOnDesk.filter(el => el.classList.contains('atom')).length; const molecules = elementsOnDesk.filter(el => el.classList.contains('molecule')).length; atomCountEl.innerText = atoms; moleculeCountEl.innerText = molecules; }