feat: Reaktor-Box und Hauptgruppen-Elemente implementiert

This commit is contained in:
kreidler90 2026-07-04 14:43:52 +00:00
parent 508bdc1fba
commit 321de38def
4 changed files with 473 additions and 147 deletions

View File

@ -15,10 +15,10 @@ Dieses Dokument dokumentiert die erfolgreich abgeschlossenen Entwicklungsphasen
- **3D-Scherenmodell:** Atome haben durch CSS-Radial-Gradients ein plastisches 3D-Kugel-Aussehen.
### Phase 2: Das interaktive PSE-Cockpit (Option 1)
- **Periodensystem-Overlay:** Ein Klick auf "📊 Periodensystem" öffnet ein vollflächiges, dunkles Periodensystem-Interfache (CSS Grid, 18 Spalten x 4 Zeilen).
- **Periodensystem-Overlay:** Ein Klick auf "📊 Periodensystem" öffnet ein vollflächiges, dunkles Periodensystem-Interface (CSS Grid, 18 Spalten x 7 Zeilen mit allen 50 Hauptgruppen-Elementen).
- **Wissenschaftliche Steckbriefe:** Detaillierte Karten für jedes Element mit Ordnungszahl, Atommasse, Gruppenbezeichnung und Alltagsvorkommen.
- **Aktives Schalenmodell (Bohr-Modell):** Eine dynamische Schalen-Visualisierung berechnet die Kreisbahnen der Elektronen trigonometrisch und lässt sie in flüssiger Bewegung rotieren. Jedes Atom hat seine reale Elektronenkonfiguration (z. B. Natrium: 2, 8, 1 Schalen).
- **Direktes Spawnen:** Elemente können direkt aus dem PSE-Steckbrief auf den Tisch gespawnt werden.
- **Direktes Spawnen:** Alle 50 Hauptgruppen-Elemente sowie Eisen können direkt aus dem PSE-Steckbrief auf den Tisch gespawnt werden (mit intelligentem, dynamischem Kategoriemuster-Farbschema).
### Phase 3: Der Story-Modus (Missions-Zentrale)
- **Kampagnen-System:** Ein Umschalter zwischen "🧪 Sandbox" und "🏆 Story-Modus" in der Sidebar.

429
app.js
View File

@ -64,25 +64,55 @@ const elementDetails = {
const pseElements = [
{ number: 1, symbol: 'H', name: 'Wasserstoff', mass: '1.008 u', category: 'nichtmetall', row: 1, col: 1, playable: true, electrons: [1], desc: 'Das häufigste und leichteste Element im Universum. Es bildet den primären Kernbrennstoff für alle leuchtenden Sterne.' },
{ number: 2, symbol: 'He', name: 'Helium', mass: '4.003 u', category: 'edelgas', row: 1, col: 18, playable: true, electrons: [2], desc: 'Ein absolut reaktionsträges Edelgas. Es brennt nicht und ist viel leichter als Luft perfekt für Ballons und lässt Stimmen lustig hoch klingen!' },
{ number: 3, symbol: 'Li', name: 'Lithium', mass: '6.94 u', category: 'alkalimetall', row: 2, col: 1, playable: false, electrons: [2, 1], desc: 'Ein extrem leichtes, reaktives Metall. Es ist das Herzstück moderner Lithium-Ionen-Akkus für Handys, Laptops und Elektroautos.' },
{ number: 4, symbol: 'Be', name: 'Beryllium', mass: '9.012 u', category: 'erdalkali', row: 2, col: 2, playable: false, electrons: [2, 2], desc: 'Ein seltenes, hochgiftiges Erdalkalimetall. Es ist extrem steif und temperaturbeständig und wird deshalb im Weltraumteleskop-Bau (z.B. James Webb) eingesetzt.' },
{ number: 5, symbol: 'B', name: 'Bor', mass: '10.81 u', category: 'metalloid', row: 2, col: 13, playable: false, electrons: [2, 3], desc: 'Ein hartes, hitzebeständiges Halbmetall. Es wird für extrem widerstandsfähiges Glas (Borosilikatglas) und im Raketentreibstoff-Sektor verwendet.' },
{ number: 3, symbol: 'Li', name: 'Lithium', mass: '6.94 u', category: 'alkalimetall', row: 2, col: 1, playable: true, electrons: [2, 1], desc: 'Ein extrem leichtes, reaktives Metall. Es ist das Herzstück moderner Lithium-Ionen-Akkus für Handys, Laptops und Elektroautos.' },
{ number: 4, symbol: 'Be', name: 'Beryllium', mass: '9.012 u', category: 'erdalkali', row: 2, col: 2, playable: true, electrons: [2, 2], desc: 'Ein seltenes, hochgiftiges Erdalkalimetall. Es ist extrem steif und temperaturbeständig und wird deshalb im Weltraumteleskop-Bau (z.B. James Webb) eingesetzt.' },
{ number: 5, symbol: 'B', name: 'Bor', mass: '10.81 u', category: 'metalloid', row: 2, col: 13, playable: true, electrons: [2, 3], desc: 'Ein hartes, hitzebeständiges Halbmetall. Es wird für extrem widerstandsfähiges Glas (Borosilikatglas) und im Raketentreibstoff-Sektor verwendet.' },
{ number: 6, symbol: 'C', name: 'Kohlenstoff', mass: '12.011 u', category: 'nichtmetall', row: 2, col: 14, playable: true, electrons: [2, 4], desc: 'Die chemische Basis allen Lebens auf der Erde! Kohlenstoff kommt in reiner Form sowohl als weicher Graphit (Bleistift) als auch als extrem harter Diamant vor.' },
{ number: 7, symbol: 'N', name: 'Stickstoff', mass: '14.007 u', category: 'nichtmetall', row: 2, col: 15, playable: true, electrons: [2, 5], desc: 'Stickstoff bildet fast 78% unserer Atemluft! Er reagiert unter normalen Bedingungen kaum und schützt die Erde vor unkontrollierbaren Bränden.' },
{ number: 8, symbol: 'O', name: 'Sauerstoff', mass: '15.999 u', category: 'nichtmetall', row: 2, col: 16, playable: true, electrons: [2, 6], desc: 'Lebensnotwendig für fast alle Tiere. Es ist hochreaktiv und verbindet sich leidenschaftlich gern mit anderen Elementen (Rosten von Eisen, Verbrennung).' },
{ number: 9, symbol: 'F', name: 'Fluor', mass: '18.998 u', category: 'halogen', row: 2, col: 17, playable: false, electrons: [2, 7], desc: 'Das reaktivste aller chemischen Elemente! Fluor-Gas zerfrisst fast jeden Stoff sofort unter Flammenbildung. Spuren von Fluorid schützen unseren Zahnschmelz.' },
{ number: 10, symbol: 'Ne', name: 'Neon', mass: '20.180 u', category: 'edelgas', row: 2, col: 18, playable: false, electrons: [2, 8], desc: 'Ein extrem reaktionsträges Edelgas. Unter Hochspannung leuchtet es intensiv rötlich-orange, weshalb es der Namensgeber für alle Leuchtreklamen ist.' },
{ number: 9, symbol: 'F', name: 'Fluor', mass: '18.998 u', category: 'halogen', row: 2, col: 17, playable: true, electrons: [2, 7], desc: 'Das reaktivste aller chemischen Elemente! Fluor-Gas zerfrisst fast jeden Stoff sofort unter Flammenbildung. Spuren von Fluorid schützen unseren Zahnschmelz.' },
{ number: 10, symbol: 'Ne', name: 'Neon', mass: '20.180 u', category: 'edelgas', row: 2, col: 18, playable: true, electrons: [2, 8], desc: 'Ein extrem reaktionsträges Edelgas. Unter Hochspannung leuchtet es intensiv rötlich-orange, weshalb es der Namensgeber für alle Leuchtreklamen ist.' },
{ number: 11, symbol: 'Na', name: 'Natrium', mass: '22.990 u', category: 'alkalimetall', row: 3, col: 1, playable: true, electrons: [2, 8, 1], desc: 'Ein extrem reaktionsfreudiges, weiches Alkalimetall. Es reagiert explosionsartig mit Wasser und muss daher in zähem Öl (Petroleum) gelagert werden.' },
{ number: 12, symbol: 'Mg', name: 'Magnesium', mass: '24.305 u', category: 'erdalkali', row: 3, col: 2, playable: false, electrons: [2, 8, 2], desc: 'Ein leichtes Erdalkalimetall. Es brennt mit einer extrem hellen, blendend weißen Flamme und ist wichtig für die Muskel- und Nervenfunktion im Körper.' },
{ number: 13, symbol: 'Al', name: 'Aluminium', mass: '26.982 u', category: 'metall', row: 3, col: 13, playable: false, electrons: [2, 8, 3], desc: 'Das dritthäufigste Element der Erdkruste. Es ist leicht, rostfrei und wird für Flugzeuge, Alufolie, Getränkedosen und Autoteile verwendet.' },
{ number: 14, symbol: 'Si', name: 'Silicium', mass: '28.085 u', category: 'metalloid', row: 3, col: 14, playable: false, electrons: [2, 8, 4], desc: 'Das Element, das unsere Computertechnologie antreibt! Silicium ist ein Halbleiter und die absolute Basis aller Mikrochips und Solarzellen.' },
{ number: 15, symbol: 'P', name: 'Phosphor', mass: '30.974 u', category: 'nichtmetall', row: 3, col: 15, playable: false, electrons: [2, 8, 5], desc: 'Ein lebenswichtiges Element, das im menschlichen Erbgut (DNA) und in Knochen vorkommt. Roter Phosphor wird auf Streichholz-Reibflächen verwendet.' },
{ number: 12, symbol: 'Mg', name: 'Magnesium', mass: '24.305 u', category: 'erdalkali', row: 3, col: 2, playable: true, electrons: [2, 8, 2], desc: 'Ein leichtes Erdalkalimetall. Es brennt mit einer extrem hellen, blendend weißen Flamme und ist wichtig für die Muskel- und Nervenfunktion im Körper.' },
{ number: 13, symbol: 'Al', name: 'Aluminium', mass: '26.982 u', category: 'metall', row: 3, col: 13, playable: true, electrons: [2, 8, 3], desc: 'Das dritthäufigste Element der Erdkruste. Es ist leicht, rostfrei und wird für Flugzeuge, Alufolie, Getränkedosen und Autoteile verwendet.' },
{ number: 14, symbol: 'Si', name: 'Silicium', mass: '28.085 u', category: 'metalloid', row: 3, col: 14, playable: true, electrons: [2, 8, 4], desc: 'Das Element, das unsere Computertechnologie antreibt! Silicium is ein Halbleiter und die absolute Basis aller Mikrochips und Solarzellen.' },
{ number: 15, symbol: 'P', name: 'Phosphor', mass: '30.974 u', category: 'nichtmetall', row: 3, col: 15, playable: true, electrons: [2, 8, 5], desc: 'Ein lebenswichtiges Element, das im menschlichen Erbgut (DNA) und in Knochen vorkommt. Roter Phosphor wird auf Streichholz-Reibflächen verwendet.' },
{ number: 16, symbol: 'S', name: 'Schwefel', mass: '32.06 u', category: 'nichtmetall', row: 3, col: 16, playable: true, electrons: [2, 8, 6], desc: 'Ein zitronengelber, geruchloser Feststoff. Seine organischen Verbindungen riechen oft extrem faulig (z.B. faule Eier). Schwefel ist wichtig für Haare und Proteine.' },
{ number: 17, symbol: 'Cl', name: 'Chlor', mass: '35.45 u', category: 'halogen', row: 3, col: 17, playable: true, electrons: [2, 8, 7], desc: 'Ein giftiges, stechend riechendes gelbgrünes Gas. Chlor ist extrem reaktiv und wird weltweit zur Desinfektion von Trinkwasser und Pools genutzt.' },
{ number: 18, symbol: 'Ar', name: 'Argon', mass: '39.948 u', category: 'edelgas', row: 3, col: 18, playable: false, electrons: [2, 8, 8], desc: 'Das dritthäufigste Gas in unserer Atmosphäre. Argon wird als ungiftiges Schutzgas beim Schweißen und in Doppelglasscheiben zur Wärmeisolierung eingesetzt.' },
{ number: 19, symbol: 'K', name: 'Kalium', mass: '39.098 u', category: 'alkalimetall', row: 4, col: 1, playable: false, electrons: [2, 8, 8, 1], desc: 'Ein weiches, hochreaktives Alkalimetall. Es reagiert noch heftiger mit Wasser als Natrium und ist essenziell für die Weiterleitung von Nervensignalen.' },
{ number: 20, symbol: 'Ca', name: 'Calcium', mass: '40.078 u', category: 'erdalkali', row: 4, col: 2, playable: false, electrons: [2, 8, 8, 2], desc: 'Der elementare Baustein für Skelette und Zähne! Calcium bildet Knochen, Eierschalen, Muscheln und Kreide und ist wichtig für die Muskelarbeit.' },
{ number: 26, symbol: 'Fe', name: 'Eisen', mass: '55.845 u', category: 'uebergang', row: 4, col: 8, playable: true, electrons: [2, 8, 14, 2], desc: 'Das am häufigsten genutzte Metall der Menschheit. Eisen bildet das Zentrum unseres Erdkerns (Magnetfeld) und transportiert Sauerstoff in unserem Blut (Hämoglobin).' }
{ number: 18, symbol: 'Ar', name: 'Argon', mass: '39.948 u', category: 'edelgas', row: 3, col: 18, playable: true, electrons: [2, 8, 8], desc: 'Das dritthäufigste Gas in unserer Atmosphäre. Argon wird als ungiftiges Schutzgas beim Schweißen und in Doppelglasscheiben zur Wärmeisolierung eingesetzt.' },
{ number: 19, symbol: 'K', name: 'Kalium', mass: '39.098 u', category: 'alkalimetall', row: 4, col: 1, playable: true, electrons: [2, 8, 8, 1], desc: 'Ein weiches, hochreaktives Alkalimetall. Es reagiert noch heftiger mit Wasser als Natrium und ist essenziell für die Weiterleitung von Nervensignalen.' },
{ number: 20, symbol: 'Ca', name: 'Calcium', mass: '40.078 u', category: 'erdalkali', row: 4, col: 2, playable: true, electrons: [2, 8, 8, 2], desc: 'Der elementare Baustein für Skelette und Zähne! Calcium bildet Knochen, Eierschalen, Muscheln und Kreide und ist wichtig für die Muskelarbeit.' },
{ number: 26, symbol: 'Fe', name: 'Eisen', mass: '55.845 u', category: 'uebergang', row: 4, col: 8, playable: true, electrons: [2, 8, 14, 2], desc: 'Das am häufigsten genutzte Metall der Menschheit. Eisen bildet das Zentrum unseres Erdkerns (Magnetfeld) und transportiert Sauerstoff in unserem Blut (Hämoglobin).' },
{ number: 31, symbol: 'Ga', name: 'Gallium', mass: '69.723 u', category: 'metall', row: 4, col: 13, playable: true, electrons: [2, 8, 18, 3], desc: 'Ein faszinierendes Metall mit einem sehr niedrigen Schmelzpunkt von 29.76 °C. Es schmilzt sprichwörtlich in der warmen Hand!' },
{ number: 32, symbol: 'Ge', name: 'Germanium', mass: '72.63 u', category: 'metalloid', row: 4, col: 14, playable: true, electrons: [2, 8, 18, 4], desc: 'Ein glänzendes, hartes Halbmetall. Es ist ein wichtiger Halbleiter und wird oft in Infrarot-Optiken und Glasfaserkabeln eingesetzt.' },
{ number: 33, symbol: 'As', name: 'Arsen', mass: '74.922 u', category: 'metalloid', row: 4, col: 15, playable: true, electrons: [2, 8, 18, 5], desc: 'Ein berüchtigtes, hochgiftiges Halbmetall. Historisch als König der Gifte bekannt, wird es heute in Halbleitern und Speziallegierungen verwendet.' },
{ number: 34, symbol: 'Se', name: 'Selen', mass: '78.97 u', category: 'nichtmetall', row: 4, col: 16, playable: true, electrons: [2, 8, 18, 6], desc: 'Ein wichtiges Spurenelement, das für Lebewesen essenziell ist. Selen ist lichtempfindlich und leitet Strom besser bei Belichtung (Kopiergeräte).' },
{ number: 35, symbol: 'Br', name: 'Brom', mass: '79.904 u', category: 'halogen', row: 4, col: 17, playable: true, electrons: [2, 8, 18, 7], desc: 'Das einzige flüssige Nichtmetall bei Raumtemperatur! Es ist eine rotbraune, ätzende Flüssigkeit mit einem extrem stechenden, unangenehmen Geruch.' },
{ number: 36, symbol: 'Kr', name: 'Krypton', mass: '83.798 u', category: 'edelgas', row: 4, col: 18, playable: true, electrons: [2, 8, 18, 8], desc: 'Ein seltenes Edelgas. Unter Hochspannung leuchtet es weiß-violett und wird in hocheffizienten Glühlampen sowie Blitzlichtern für Kameras genutzt.' },
{ number: 37, symbol: 'Rb', name: 'Rubidium', mass: '85.468 u', category: 'alkalimetall', row: 5, col: 1, playable: true, electrons: [2, 8, 18, 8, 1], desc: 'Ein extrem reaktives Alkalimetall. Es entzündet sich bei Kontakt mit Luft sofort selbst und reagiert explosionsartig mit Wasser.' },
{ number: 38, symbol: 'Sr', name: 'Strontium', mass: '87.62 u', category: 'erdalkali', row: 5, col: 2, playable: true, electrons: [2, 8, 18, 8, 2], desc: 'Ein reaktives Erdalkalimetall. Seine Salze brennen mit einer intensiv roten Flamme und sind daher in roten Feuerwerkskörpern unentbehrlich.' },
{ number: 49, symbol: 'In', name: 'Indium', mass: '114.818 u', category: 'metall', row: 5, col: 13, playable: true, electrons: [2, 8, 18, 18, 3], desc: 'Ein sehr weiches, silbriges Metall. Es wird als Indiumzinnoxid (ITO) zur Herstellung von transparenten Elektroden für Touchscreens verwendet.' },
{ number: 50, symbol: 'Sn', name: 'Zinn', mass: '118.71 u', category: 'metall', row: 5, col: 14, playable: true, electrons: [2, 8, 18, 18, 4], desc: 'Ein silberweißes Metall. Beim Biegen einer Zinnstange hört man ein charakteristisches Knistern, das sogenannte "Zinn-Schreien".' },
{ number: 51, symbol: 'Sb', name: 'Antimon', mass: '121.76 u', category: 'metalloid', row: 5, col: 15, playable: true, electrons: [2, 8, 18, 18, 5], desc: 'Ein sprödes, glänzendes Halbmetall. Es dehnt sich beim Erstarren aus und wird für Legierungen sowie feuerhemmende Materialien eingesetzt.' },
{ number: 52, symbol: 'Te', name: 'Tellur', mass: '127.6 u', category: 'metalloid', row: 5, col: 16, playable: true, electrons: [2, 8, 18, 18, 6], desc: 'Ein sehr seltenes, silbrig-glänzendes Halbmetall. Es wird hauptsächlich zur Legierung von Metallen verwendet, um deren Festigkeit zu steigern.' },
{ number: 53, symbol: 'I', name: 'Iod', mass: '126.904 u', category: 'halogen', row: 5, col: 17, playable: true, electrons: [2, 8, 18, 18, 7], desc: 'Ein violett-schwarzer Feststoff. Iod sublimiert beim Erwärmen zu prächtigen violetten Dämpfen. Es ist lebenswichtig für unsere Schilddrüse.' },
{ number: 54, symbol: 'Xe', name: 'Xenon', mass: '131.293 u', category: 'edelgas', row: 5, col: 18, playable: true, electrons: [2, 8, 18, 18, 8], desc: 'Das schwerste stabile Edelgas. Es leuchtet intensiv blau-violett und wird in Hochleistungsscheinwerfern (Xenonlicht) und in der Medizin als Narkosemittel genutzt.' },
{ number: 55, symbol: 'Cs', name: 'Caesium', mass: '132.905 u', category: 'alkalimetall', row: 6, col: 1, playable: true, electrons: [2, 8, 18, 18, 8, 1], desc: 'Das reaktivste aller stabilen Metalle! Es schmilzt bereits bei 28.4 °C und reagiert mit Wasser so extrem heftig, dass es meist das Gefäß zersprengt.' },
{ number: 56, symbol: 'Ba', name: 'Barium', mass: '137.327 u', category: 'erdalkali', row: 6, col: 2, playable: true, electrons: [2, 8, 18, 18, 8, 2], desc: 'Ein weiches, hochreaktives Erdalkalimetall. Bariumsulfat wird wegen seiner Unlöslichkeit in der Medizin als Kontrastmittel für Röntgenbilder eingesetzt.' },
{ number: 81, symbol: 'Tl', name: 'Thallium', mass: '204.38 u', category: 'metall', row: 6, col: 13, playable: true, electrons: [2, 8, 18, 32, 18, 3], desc: 'Ein extrem giftiges Schwermetall. Es wurde früher oft als Rattengift verwendet. Der Kontakt mit Thallium führt beim Menschen zu Haarausfall und Nervenschäden.' },
{ number: 82, symbol: 'Pb', name: 'Blei', mass: '207.2 u', category: 'metall', row: 6, col: 14, playable: true, electrons: [2, 8, 18, 32, 18, 4], desc: 'Ein schweres, weiches und giftiges Metall. Es lässt sich leicht verformen und schützt in Bleischürzen hocheffektiv vor radioaktiver Strahlung.' },
{ number: 83, symbol: 'Bi', name: 'Bismut', mass: '208.980 u', category: 'metall', row: 6, col: 15, playable: true, electrons: [2, 8, 18, 32, 18, 5], desc: 'Ein rötlich-weißes, ungiftiges Schwermetall. Seine Kristalle laufen an Luft in schillernden Regenbogenfarben an und bilden wunderschöne Treppenstrukturen.' },
{ number: 84, symbol: 'Po', name: 'Polonium', mass: '209 u', category: 'metalloid', row: 6, col: 16, playable: true, electrons: [2, 8, 18, 32, 18, 6], desc: 'Ein extrem seltenes, hochradioaktives und tödlich giftiges Halbmetall. Es wurde von Marie Curie entdeckt und nach ihrem Heimatland Polen benannt.' },
{ number: 85, symbol: 'At', name: 'Astat', mass: '210 u', category: 'halogen', row: 6, col: 17, playable: true, electrons: [2, 8, 18, 32, 18, 7], desc: 'Das seltenste natürlich vorkommende Element der Erdkruste. Ein sichtbares Stück Astat würde aufgrund der extremen Radioaktivität sofort verdampfen.' },
{ number: 86, symbol: 'Rn', name: 'Radon', mass: '222 u', category: 'edelgas', row: 6, col: 18, playable: true, electrons: [2, 8, 18, 32, 18, 8], desc: 'Ein unsichtbares, geruchloses und hochradioaktives Edelgas. Es kann aus dem Boden austreten und sich gefährlich in schlecht belüfteten Kellern anreichern.' },
{ number: 87, symbol: 'Fr', name: 'Francium', mass: '223 u', category: 'alkalimetall', row: 7, col: 1, playable: true, electrons: [2, 8, 18, 32, 18, 8, 1], desc: 'Das zweitseltenste Element in der Erdkruste nach Astat. Es ist extrem radioaktiv und so instabil, dass man bisher nie eine sichtbare Menge herstellen konnte.' },
{ number: 88, symbol: 'Ra', name: 'Radium', mass: '226 u', category: 'erdalkali', row: 7, col: 2, playable: true, electrons: [2, 8, 18, 32, 18, 8, 2], desc: 'Ein stark radioaktives Erdalkalimetall, das im Dunkeln bläulich leuchtet. Marie Curie entdeckte es; früher wurde es fälschlicherweise in Leuchtfarben genutzt.' },
{ number: 113, symbol: 'Nh', name: 'Nihonium', mass: '286 u', category: 'metall', row: 7, col: 13, playable: true, electrons: [2, 8, 18, 32, 32, 18, 3], desc: 'Ein künstlich erzeugtes superschweres Element. Es wurde am RIKEN-Institut in Japan entdeckt und ist nach dem japanischen Wort "Nihon" (Japan) benannt.' },
{ number: 114, symbol: 'Fl', name: 'Flerovium', mass: '289 u', category: 'metall', row: 7, col: 14, playable: true, electrons: [2, 8, 18, 32, 32, 18, 4], desc: 'Ein künstlich hergestelltes, extrem radioaktives künstliches Element. Es wurde nach dem Flerow-Labor für Kernreaktionen in Russland benannt.' },
{ number: 115, symbol: 'Mc', name: 'Moscovium', mass: '290 u', category: 'metall', row: 7, col: 15, playable: true, electrons: [2, 8, 18, 32, 32, 18, 5], desc: 'Ein künstliches, extrem instabiles superschweres Element, benannt nach der russischen Region Moskau, in der sich das Forschungszentrum Dubna befindet.' },
{ number: 116, symbol: 'Lv', name: 'Livermorium', mass: '293 u', category: 'metall', row: 7, col: 16, playable: true, electrons: [2, 8, 18, 32, 32, 18, 6], desc: 'Ein künstliches, hochgradig radioaktives Element. Es wurde gemeinschaftlich in Dubna (Russland) und in Livermore (USA) hergestellt.' },
{ number: 117, symbol: 'Ts', name: 'Tenness', mass: '294 u', category: 'halogen', row: 7, col: 17, playable: true, electrons: [2, 8, 18, 32, 32, 18, 7], desc: 'Ein superschweres, künstliches Halogen. Es wurde 2010 synthetisiert und ist nach dem US-Bundesstaat Tennessee benannt.' },
{ number: 118, symbol: 'Og', name: 'Oganesson', mass: '294 u', category: 'edelgas', row: 7, col: 18, playable: true, electrons: [2, 8, 18, 32, 32, 18, 8], desc: 'Das schwerste bekannte Element im Periodensystem mit der Ordnungszahl 118. Es ist extrem kurzlebig und nach dem Physiker Juri Oganesjan benannt.' }
];
// Rezepturenbuch (die Formeln müssen genau den Kombinationen der Symbole entsprechen)
@ -387,11 +417,19 @@ spawnBtns.forEach(btn => {
// Tisch leeren Button
clearDeskBtn.addEventListener('click', () => {
workspace.innerHTML = '';
const elementsToRemove = workspace.querySelectorAll('.atom, .molecule');
elementsToRemove.forEach(el => el.remove());
elementsOnDesk = [];
reactorAtoms = [];
reactorMolecules = [];
updateStats();
updateReactorUI();
});
// Reaktor-Box Buttons
document.getElementById('reactor-synth-btn').addEventListener('click', synthesizeReactor);
document.getElementById('reactor-decompose-btn').addEventListener('click', decomposeReactor);
// =========================================
// MODALS LOGIC
// =========================================
@ -419,10 +457,31 @@ function closePSE() {
pseModal.classList.add('hidden');
}
function getElementColor(symbol) {
if (elementDetails[symbol]) {
return elementDetails[symbol].color;
}
const el = pseElements.find(e => e.symbol === symbol);
if (el) {
const categoryColors = {
'alkalimetall': '#ff7675',
'erdalkali': '#e17055',
'uebergang': '#b2bec3',
'metalloid': '#fdcb6e',
'nichtmetall': '#74b9ff',
'halogen': '#55efc4',
'edelgas': '#e84393',
'metall': '#ffeaa7'
};
return categoryColors[el.category] || '#b2bec3';
}
return '#b2bec3';
}
// PSE Atom Spawnen Event
pseSpawnBtn.addEventListener('click', () => {
if (selectedPSEElement) {
spawnAtom(selectedPSEElement.symbol, elementDetails[selectedPSEElement.symbol].color);
spawnAtom(selectedPSEElement.symbol, getElementColor(selectedPSEElement.symbol));
closePSE();
}
});
@ -500,144 +559,204 @@ document.addEventListener('mouseup', () => {
if (draggingElement) {
draggingElement.style.zIndex = '';
draggingElement.style.boxShadow = '';
checkForReactions();
handleElementDrop();
draggingElement = null;
}
});
function checkForReactions() {
if (!draggingElement) return;
let reactorAtoms = [];
let reactorMolecules = [];
// 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();
function isElementOverReactor(el) {
const reactorBox = document.getElementById('reactor-box');
if (!reactorBox) return false;
const r1 = el.getBoundingClientRect();
const r2 = reactorBox.getBoundingClientRect();
return !(r1.right < r2.left ||
r1.left > r2.right ||
r1.bottom < r2.top ||
r1.top > r2.bottom);
}
function handleElementDrop() {
if (!draggingElement) return;
// Check if element is dropped over the reactor box
if (isElementOverReactor(draggingElement)) {
// Add to reactor state
if (draggingElement.classList.contains('atom')) {
const symbol = draggingElement.dataset.symbol;
reactorAtoms.push(symbol);
} else if (draggingElement.classList.contains('molecule')) {
const recipeId = draggingElement.dataset.recipeId;
const recipe = recipes.find(r => r.id === recipeId);
if (recipe) {
reactorMolecules.push(recipe);
}
}
// Remove from desk
workspace.removeChild(draggingElement);
elementsOnDesk = elementsOnDesk.filter(el => el !== draggingElement);
updateStats();
updateReactorUI();
// Remove visual feedback highlight
const reactorBox = document.getElementById('reactor-box');
if (reactorBox) reactorBox.classList.remove('drag-over');
}
}
function updateReactorUI() {
const summary = document.getElementById('reactor-contents-summary');
if (!summary) return;
summary.innerHTML = '';
if (reactorAtoms.length === 0 && reactorMolecules.length === 0) {
summary.innerHTML = '<span class="empty-text">Atome/Moleküle hierher ziehen!</span>';
return;
}
// Group atoms by symbol for compact display
const atomCounts = {};
reactorAtoms.forEach(sym => {
atomCounts[sym] = (atomCounts[sym] || 0) + 1;
});
if (touches) {
cluster.push(el);
added = true;
}
}
// Render atom badges
Object.keys(atomCounts).forEach(sym => {
const count = atomCounts[sym];
const badge = document.createElement('div');
badge.classList.add('reactor-badge', 'atom-badge');
badge.style.backgroundColor = getElementColor(sym);
badge.title = `Klicke zum Auswerfen`;
badge.innerHTML = `<span class="badge-count">${count}x</span> ${sym}`;
// Dark/light text color contrast
if (sym === 'C' || sym === 'Fe') {
badge.style.color = '#fff';
} else {
badge.style.color = '#333';
}
if (cluster.length > 1) {
// Reaktions-Keys extrahieren (Atome => Großbuchstaben-Symbol, Moleküle => Kleinbuchstaben-Rezept-ID)
const reactantKeys = [];
cluster.forEach(el => {
if (el.classList.contains('atom')) {
reactantKeys.push(el.dataset.symbol);
} else if (el.classList.contains('molecule')) {
reactantKeys.push(el.dataset.recipeId);
}
badge.addEventListener('click', () => {
ejectAtomFromReactor(sym);
});
reactantKeys.sort();
// ZUERST: Fortgeschrittene Molekül-Reaktionen prüfen
let advancedReactionFound = false;
for (const advRecipe of advancedRecipes) {
const advIngredients = [...advRecipe.ingredients].sort();
if (JSON.stringify(reactantKeys) === JSON.stringify(advIngredients)) {
// FORTGESCHRITTENE REAKTION ERFOLGREICH!
advancedReactionFound = true;
const midX = parseFloat(draggingElement.style.left) + draggingElement.offsetWidth / 2;
const midY = parseFloat(draggingElement.style.top) + draggingElement.offsetHeight / 2;
// Lösche alle reactant-Elemente im Cluster vom Tisch
cluster.forEach(el => {
if (workspace.contains(el)) {
workspace.removeChild(el);
}
elementsOnDesk = elementsOnDesk.filter(e => e !== el);
summary.appendChild(badge);
});
// Dicke, bunte Explosion erzeugen
triggerExplosion(midX, midY, '#ff9f43');
// Render molecule badges
reactorMolecules.forEach((recipe, idx) => {
const badge = document.createElement('div');
badge.classList.add('reactor-badge', 'molecule-badge');
badge.style.backgroundColor = recipe.color;
badge.title = `Klicke zum Auswerfen`;
// Erzeuge alle Produkt-Moleküle des fortgeschrittenen Rezepts
advRecipe.results.forEach((prodId, index) => {
const prodRecipe = recipes.find(r => r.id === prodId);
if (prodRecipe) {
// Platziere Produkte nebeneinander im Fusionszentrum
const offsetMultiplier = index - (advRecipe.results.length - 1) / 2;
const molX = midX - 60 + (offsetMultiplier * 80);
const molY = midY - 20;
createMolecule(prodRecipe, molX, molY);
// Show chemical formula (e.g. H2O)
const formula = recipe.id.toUpperCase().replace(/\d/g, m => '<sub>' + m + '</sub>');
badge.innerHTML = `${formula}`;
badge.style.color = '#fff';
// Entdeckung registrieren
const isNew = !discoveredMolecules.has(prodRecipe.id);
if (isNew) {
discoveredMolecules.add(prodRecipe.id);
localStorage.setItem('chem_lab_discoveries', JSON.stringify([...discoveredMolecules]));
badge.addEventListener('click', () => {
ejectMoleculeFromReactor(idx);
});
summary.appendChild(badge);
});
}
function ejectAtomFromReactor(symbol) {
const idx = reactorAtoms.indexOf(symbol);
if (idx > -1) {
reactorAtoms.splice(idx, 1);
// Position back on desk near reactor
const reactorBox = document.getElementById('reactor-box');
const rx = parseFloat(reactorBox.style.left || (workspace.clientWidth - 340)) - 60 - Math.random() * 40;
const ry = parseFloat(reactorBox.style.top || (workspace.clientHeight - 190)) + Math.random() * 40;
spawnAtom(symbol, getElementColor(symbol));
const lastEl = elementsOnDesk[elementsOnDesk.length - 1];
if (lastEl) {
lastEl.style.left = Math.max(10, rx) + 'px';
lastEl.style.top = Math.max(10, ry) + 'px';
}
updateReactorUI();
}
}
function ejectMoleculeFromReactor(idx) {
const recipe = reactorMolecules[idx];
if (recipe) {
reactorMolecules.splice(idx, 1);
// Position back on desk near reactor
const reactorBox = document.getElementById('reactor-box');
const rx = parseFloat(reactorBox.style.left || (workspace.clientWidth - 340)) - 100 - Math.random() * 40;
const ry = parseFloat(reactorBox.style.top || (workspace.clientHeight - 190)) + Math.random() * 40;
createMolecule(recipe, Math.max(10, rx), Math.max(10, ry));
updateReactorUI();
}
}
function synthesizeReactor() {
if (reactorAtoms.length === 0) {
alert("Der Reaktor enthält keine freien Atome für die Synthese!");
return;
}
// Sort recipes by ingredient length descending so we build larger molecules first
const sortedRecipes = [...recipes].sort((a, b) => b.ingredients.length - a.ingredients.length);
let synthesizedAny = false;
let keepMatching = true;
while (keepMatching) {
keepMatching = false;
const availableCounts = {};
reactorAtoms.forEach(sym => {
availableCounts[sym] = (availableCounts[sym] || 0) + 1;
});
renderDiscoveryBook();
for (const recipe of sortedRecipes) {
const recipeCounts = {};
recipe.ingredients.forEach(sym => {
recipeCounts[sym] = (recipeCounts[sym] || 0) + 1;
});
// Story-Modus Ziel prüfen (für fortgeschrittene Reaktionen)
if (gameMode === 'story') {
const currentLevel = levels[currentLevelIndex];
if (advRecipe.id === currentLevel.goalFormula) {
handleLevelSuccess(currentLevel, advRecipe);
let match = true;
for (const sym of Object.keys(recipeCounts)) {
if (!availableCounts[sym] || availableCounts[sym] < recipeCounts[sym]) {
match = false;
break;
}
}
// Info-Modal für die gesamte Reaktion anzeigen!
showAdvancedReactionModal(advRecipe);
break;
if (match) {
// Match found! Consume atoms
recipe.ingredients.forEach(sym => {
const idx = reactorAtoms.indexOf(sym);
if (idx > -1) {
reactorAtoms.splice(idx, 1);
}
}
if (advancedReactionFound) return;
// DANACH: Normale Atom-Fusion (Cluster darf KEINE Moleküle enthalten!)
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);
// Spawn molecule near the reactor
const reactorBox = document.getElementById('reactor-box');
const rx = parseFloat(reactorBox.style.left || (workspace.clientWidth - 340)) - 100 - Math.random() * 40;
const ry = parseFloat(reactorBox.style.top || (workspace.clientHeight - 190)) + Math.random() * 40;
createMolecule(recipe, Math.max(10, rx), Math.max(10, ry));
// Neues Molekül erstellen
const molX = midX - 60; // Zentrieren
const molY = midY - 20;
createMolecule(recipe, molX, molY);
// Explosion at the reactor center
const rect = reactorBox.getBoundingClientRect();
const workspaceRect = workspace.getBoundingClientRect();
const rx_exp = rect.left - workspaceRect.left + rect.width / 2;
const ry_exp = rect.top - workspaceRect.top + rect.height / 2;
triggerExplosion(rx_exp, ry_exp, recipe.color);
// Entdeckung registrieren
// Discovery check
const isNew = !discoveredMolecules.has(recipe.id);
if (isNew) {
discoveredMolecules.add(recipe.id);
@ -645,22 +764,66 @@ function checkForReactions() {
renderDiscoveryBook();
}
// Story-Modus Ziel prüfen (für atomare Fusionen)
// Story check
if (gameMode === 'story') {
const currentLevel = levels[currentLevelIndex];
if (recipe.id === currentLevel.goalFormula) {
handleLevelSuccess(currentLevel, recipe);
break;
}
}
// Info-Modal anzeigen (bei neuer Entdeckung)
showModal(recipe, isNew);
synthesizedAny = true;
keepMatching = true;
break;
}
}
}
if (synthesizedAny) {
updateReactorUI();
} else {
alert("Aus den vorhandenen Atomen konnte kein bekanntes Molekül synthetisiert werden!");
}
}
function decomposeReactor() {
if (reactorMolecules.length === 0) {
alert("Es befinden sich keine Moleküle in der Reaktor-Box, die zerlegt werden können!");
return;
}
let decomposedAny = false;
const reactorBox = document.getElementById('reactor-box');
while (reactorMolecules.length > 0) {
const recipe = reactorMolecules.pop();
recipe.ingredients.forEach(sym => {
reactorAtoms.push(sym);
});
// Trigger grey decomposition particle explosion
const rect = reactorBox.getBoundingClientRect();
const workspaceRect = workspace.getBoundingClientRect();
const rx_exp = rect.left - workspaceRect.left + rect.width / 2;
const ry_exp = rect.top - workspaceRect.top + rect.height / 2;
triggerExplosion(rx_exp, ry_exp, '#b2bec3');
decomposedAny = true;
}
if (decomposedAny) {
updateReactorUI();
const summary = document.getElementById('reactor-contents-summary');
if (summary) {
summary.animate([
{ transform: 'scale(1)' },
{ transform: 'scale(1.05)' },
{ transform: 'scale(1)' }
], { duration: 200, easing: 'ease-out' });
}
}
}
function createMolecule(recipe, x, y) {
@ -963,8 +1126,12 @@ tabStoryBtn.addEventListener('click', () => {
function switchMode(mode) {
gameMode = mode;
workspace.innerHTML = '';
const elementsToRemove = workspace.querySelectorAll('.atom, .molecule');
elementsToRemove.forEach(el => el.remove());
elementsOnDesk = [];
reactorAtoms = [];
reactorMolecules = [];
updateReactorUI();
updateStats();
closeModal();
closeStorySuccessModal();
@ -1044,8 +1211,12 @@ function renderLevelDots() {
if (isActive) dot.classList.add('active');
dot.addEventListener('click', () => {
workspace.innerHTML = '';
const elementsToRemove = workspace.querySelectorAll('.atom, .molecule');
elementsToRemove.forEach(el => el.remove());
elementsOnDesk = [];
reactorAtoms = [];
reactorMolecules = [];
updateReactorUI();
updateStats();
loadStoryLevel(idx);
});
@ -1129,8 +1300,12 @@ function closeStorySuccessModal() {
// Story Next Level Button Event
storyNextLevelBtn.addEventListener('click', () => {
closeStorySuccessModal();
workspace.innerHTML = '';
const elementsToRemove = workspace.querySelectorAll('.atom, .molecule');
elementsToRemove.forEach(el => el.remove());
elementsOnDesk = [];
reactorAtoms = [];
reactorMolecules = [];
updateReactorUI();
updateStats();
if (currentLevelIndex < levels.length - 1) {

View File

@ -102,7 +102,23 @@
<button id="clear-desk-btn" class="control-btn danger">🧹 Tisch leeren</button>
</div>
</div>
<div id="workspace"></div>
<div id="workspace">
<!-- REAKTOR-BOX -->
<div id="reactor-box">
<div class="reactor-header">
<h3>☢️ Reaktor-Box</h3>
</div>
<div class="reactor-body">
<div id="reactor-contents-summary">
<span class="empty-text">Atome/Moleküle hierher ziehen!</span>
</div>
<div class="reactor-buttons">
<button id="reactor-synth-btn" class="reactor-btn">✨ Synthetisieren</button>
<button id="reactor-decompose-btn" class="reactor-btn secondary">💔 Zerlegen</button>
</div>
</div>
</div>
</div>
</div>
<!-- Info-Modal für Entdeckungen -->
@ -163,6 +179,7 @@
<span class="legend-item"><span class="legend-color alkalimetall"></span>Alkalimetalle</span>
<span class="legend-item"><span class="legend-color erdalkali"></span>Erdalkali</span>
<span class="legend-item"><span class="legend-color uebergang"></span>Übergangsmetalle</span>
<span class="legend-item"><span class="legend-color metall"></span>Andere Metalle</span>
<span class="legend-item"><span class="legend-color metalloid"></span>Halbmetalle</span>
<span class="legend-item"><span class="legend-color nichtmetall"></span>Nichtmetalle</span>
<span class="legend-item"><span class="legend-color halogen"></span>Halogene</span>

136
style.css
View File

@ -17,6 +17,7 @@
--color-nichtmetall: #74b9ff;
--color-halogen: #55efc4;
--color-edelgas: #e84393;
--color-metall: #ffeaa7;
}
* {
@ -757,7 +758,7 @@ body {
#pse-grid {
display: grid;
grid-template-columns: repeat(18, 1fr);
grid-template-rows: repeat(4, 1fr);
grid-template-rows: repeat(7, 1fr);
gap: 6px;
padding: 10px;
background-color: rgba(0, 0, 0, 0.15);
@ -839,6 +840,7 @@ body {
.nichtmetall { background-color: var(--color-nichtmetall); color: #333; border-color: rgba(0,0,0,0.15); }
.halogen { background-color: var(--color-halogen); color: #333; border-color: rgba(0,0,0,0.15); }
.edelgas { background-color: var(--color-edelgas); color: #333; border-color: rgba(0,0,0,0.15); }
.metall { background-color: var(--color-metall); color: #333; border-color: rgba(0,0,0,0.15); }
.pse-el.active-el[data-symbol="C"] {
color: #fff;
@ -1043,3 +1045,135 @@ body {
.hidden {
display: none !important;
}
/* REAKTOR-BOX STYLES */
#reactor-box {
position: absolute;
bottom: 20px;
right: 20px;
width: 320px;
background: rgba(30, 39, 46, 0.95);
border: 2px dashed #3498db;
border-radius: 12px;
padding: 15px;
box-shadow: var(--shadow);
z-index: 50;
display: flex;
flex-direction: column;
gap: 10px;
transition: border-color 0.2s, background-color 0.2s, transform 0.2s;
backdrop-filter: blur(8px);
}
#reactor-box.drag-over {
border-color: #2ecc71;
background: rgba(46, 204, 113, 0.2);
transform: scale(1.02);
}
.reactor-header h3 {
font-size: 1.05rem;
color: #fff;
margin: 0;
text-align: center;
letter-spacing: 0.5px;
}
.reactor-body {
display: flex;
flex-direction: column;
gap: 12px;
}
#reactor-contents-summary {
background: rgba(0, 0, 0, 0.4);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 10px;
min-height: 80px;
font-size: 0.85rem;
color: var(--text-muted);
display: flex;
flex-wrap: wrap;
gap: 8px;
align-content: flex-start;
}
.reactor-buttons {
display: flex;
gap: 10px;
}
.reactor-btn {
flex: 1;
background: #3498db;
color: white;
border: none;
border-radius: 6px;
padding: 10px 14px;
font-weight: bold;
cursor: pointer;
transition: background 0.15s, transform 0.1s;
font-size: 0.85rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.15);
}
.reactor-btn:hover {
background: #2980b9;
}
.reactor-btn:active {
transform: scale(0.95);
}
.reactor-btn.secondary {
background: #7f8c8d;
}
.reactor-btn.secondary:hover {
background: #95a5a6;
}
.reactor-badge {
display: inline-flex;
align-items: center;
padding: 6px 10px;
border-radius: 6px;
font-size: 0.8rem;
font-weight: bold;
cursor: pointer;
user-select: none;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
border: 1px solid rgba(0,0,0,0.15);
transition: transform 0.1s, box-shadow 0.1s;
background-image: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.15) 0%, rgba(0, 0, 0, 0.1) 100%);
}
.reactor-badge:hover {
transform: scale(1.05);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.atom-badge {
border-radius: 6px;
}
.molecule-badge {
border-radius: 6px;
}
.badge-count {
margin-right: 6px;
opacity: 0.75;
background: rgba(0, 0, 0, 0.1);
padding: 1px 4px;
border-radius: 4px;
}
.empty-text {
width: 100%;
text-align: center;
line-height: 60px;
font-style: italic;
color: #7f8c8d;
}