feat(algorithms): add how-it-works and source links

Add idea, complexity, data structures, GPU use to 10 algorithm pages.
Link logic files on Gitea; a spec fails on a missing path.
Fix wrong texts: cloth phases, pendulum dt, fractal lighting, typos.
This commit is contained in:
lobo committed 2026-10-21 11:51:15 +02:00
1 parent 0857ce482b
commit 4b19245c6c
20 files changed
+318 -27

No files matched your search

+87 -9
View File
@@ -499,6 +499,14 @@
},
"ALERT": {
"START_END_NODES": "Bitte wählen Sie einen Start- und Endknoten aus, bevor Sie den Algorithmus starten."
},
"HOW_IT_WORKS": {
"INTRO": "Das Gitter ist ein zweidimensionales Array aus Knoten. Jeder Knoten speichert seine Distanz vom Start, seinen Vorgänger und für A* die Heuristik h und die Summe f = g + h. Beide Algorithmen laufen vorab komplett durch und liefern die Liste der besuchten Knoten und den Pfad. Die Animation spielt diese Liste danach Knoten für Knoten mit setTimeout ab.",
"ITEM_1": "Dijkstra: alle Knoten liegen in einer Liste. Dijkstra sortiert in jedem Schritt die ganze Liste nach Distanz (O(n² log n)) und entnimmt den nächsten Knoten. Ein Heap wäre schneller; bei höchstens 22.500 Knoten reicht es hier. Hat der nächste Knoten die Distanz unendlich, ist das Ziel nicht erreichbar.",
"ITEM_2": "A*: gleiche Struktur, aber nur die offene Liste wird sortiert, nach f = g + h; bei gleichem f gewinnt das kleinere h. Heuristik ist die Manhattan-Distanz. Sie ist zulässig, weil jeder Schritt 1 kostet und es nur vier Richtungen gibt. Darum bleibt der Pfad optimal.",
"ITEM_3": "Der Pfad entsteht am Ende aus der Vorgänger-Kette, vom Ziel zurück zum Start.",
"ITEM_4": "Vergleich: Start, Ziel und Wände werden in ein zweites Gitter kopiert. A* läuft auf dem ersten, Dijkstra auf dem zweiten, beide Animationen laufen gleichzeitig. Die Zahl der besuchten Knoten zeigt den Unterschied.",
"ITEM_5": "Rechenzeit ist die Zeit der Suche ohne Animation. Speicher: ein Knotenobjekt pro Zelle, maximal 150 × 150 = 22.500 Knoten."
}
},
"SORTING": {
@@ -523,6 +531,14 @@
"DISCLAIMER_2": "Average Case: Der statistische Normalfall.",
"DISCLAIMER_3": "Worst Case: Die Daten sind maximal ungünstig angeordnet (hier bricht Quick Sort ohne Optimierung ein, während Heap Sort stabil bleibt).",
"DISCLAIMER_4": "Zusätzlich gibt es fast immer einen Time-Space Trade-off (Zeit-Speicher-Kompromiss): Algorithmen, die extrem schnell sind (wie Merge Sort), benötigen oft viel zusätzlichen Arbeitsspeicher. Algorithmen, die direkt im vorhandenen Speicher arbeiten (wie Heap Sort), sparen Platz, sind aber manchmal komplexer oder minimal langsamer. Es gibt also keine \"One-Size-Fits-All\"-Lösung."
},
"HOW_IT_WORKS": {
"INTRO": "Jeder Algorithmus läuft zuerst komplett durch und legt bei jedem Vergleich und jedem Tausch eine Kopie des Arrays (Snapshot) in eine Liste. Die Animation spielt die Snapshots danach mit 100 ms pro Schritt ab. Die Rechenzeit ist die Zeit für den Durchlauf samt Kopien, nicht die Animation.",
"ITEM_1": "Bubble Sort und Cocktail Sort: O(n²) Vergleiche, in-place. Cocktail Sort wechselt pro Durchlauf die Richtung und stoppt, sobald ein Durchlauf nichts mehr tauscht.",
"ITEM_2": "Quick Sort: Lomuto-Partition mit dem letzten Element als Pivot, rekursiv. Durchschnitt O(n log n), schlechtester Fall O(n²), zum Beispiel bei schon sortierten Daten.",
"ITEM_3": "Heap Sort: baut einen Max-Heap im Array auf (heapify von der Mitte nach vorn) und tauscht die Wurzel ans Ende. Immer O(n log n), kein Zusatzspeicher.",
"ITEM_4": "Tim Sort (vereinfacht): Insertion Sort auf festen Blöcken von 32 Elementen, dann Bottom-up-Merge mit Hilfsarrays. Ohne Run-Erkennung und Galloping wie im Original. Bei 200 Balken sind das 7 Blöcke und 3 Merge-Ebenen.",
"ITEM_5": "Speicher: die Snapshot-Liste ist der größte Posten, O(Schritte · n). Bubble Sort mit 200 Balken erzeugt bis zu etwa 40.000 Snapshots mit je 200 Einträgen."
}
},
"GOL": {
@@ -545,6 +561,13 @@
"DISCLAIMER_2": "Eine tote Zelle „wird geboren“ (lebt in der Folgegeneration), wenn sie genau drei lebende Nachbarn hat.",
"DISCLAIMER_3": "Eine lebende Zelle „stirbt“ (ist in der Folgegeneration tot), wenn sie weniger als zwei (Vereinsamung) oder mehr als drei (Übervölkerung) lebende Nachbarn hat.",
"DISCLAIMER_4": " Eine tote Zelle bleibt tot, wenn sie nicht genau drei lebende Nachbarn hat."
},
"HOW_IT_WORKS": {
"INTRO": "Das Spielfeld sind zwei Gitter aus Zellen mit einem alive-Flag: ein Lese- und ein Schreibgitter (Double Buffering). Jede Generation liest nur aus dem einen und schreibt nur in das andere, danach werden beide getauscht. So beeinflusst eine schon geänderte Zelle ihre Nachbarn nicht in derselben Generation.",
"ITEM_1": "Pro Zelle werden die acht Nachbarn gezählt (Moore-Nachbarschaft). Der Rand wird abgeschnitten, nicht umgebrochen: Randzellen haben weniger Nachbarn, das Feld ist kein Torus.",
"ITEM_2": "Laufzeit pro Generation O(Zeilen · Spalten · 8). Bei 200 × 200 sind das 40.000 Zellen und 320.000 Nachbar-Prüfungen.",
"ITEM_3": "Die Schleife ist eine async-Schleife: rechnen, zeichnen, dann warten, bis die eingestellte Zeit pro Generation voll ist. Ändert sich keine Zelle mehr, stoppt das Spiel von selbst.",
"ITEM_4": "Gezeichnet wird das ganze Gitter auf ein Canvas: eine Füll-Operation für den Hintergrund plus eine pro lebender Zelle."
}
},
"LABYRINTH": {
@@ -560,6 +583,13 @@
"DISCLAIMER_2": "Erreichbarkeit: Da es ein Spannbaum ist, wird garantiert jede Zelle des Gitters Teil des Labyrinths, es gibt keine isolierten Bereiche.",
"DISCLAIMER_3": "Zufälligkeit: Durch die Gewichtung der Kanten mit Zufallswerten entstehen bei jedem Durchlauf völlig neue, einzigartige Strukturen.",
"DISCLAIMER_4": "Anwendung: Solche Labyrinthe sind die perfekte Testumgebung für Pfadfindungsalgorithmen wie Dijkstra oder A*."
},
"HOW_IT_WORKS": {
"INTRO": "Das Gitter hat 101 × 101 Zellen. Zellen mit geraden Koordinaten sind Räume (51 × 51 = 2.601), die Zellen dazwischen sind Wände. Beide Algorithmen berechnen zuerst die Reihenfolge, in der Wände geöffnet werden; die Animation öffnet sie danach eine nach der anderen. Das Ergebnis ist ein Spannbaum: jeder Raum ist erreichbar, und zwischen zwei Räumen gibt es genau einen Weg.",
"ITEM_1": "Prim (randomisiert): startet in einem zufälligen Raum und hält eine Frontier-Liste mit Wänden zu noch nicht besuchten Nachbarräumen. Pro Schritt wird eine zufällige Wand gewählt (Tausch mit dem letzten Element, dann pop: O(1)) und geöffnet, wenn der Raum dahinter noch unbesucht ist. Statt Kantengewichten entscheidet der Zufall.",
"ITEM_2": "Kruskal (randomisiert): alle 5.100 Wände zwischen zwei Räumen werden gesammelt und mit Fisher-Yates gemischt. Jeder Raum trägt eine Mengen-ID. Eine Wand wird geöffnet, wenn die Räume verschiedene IDs haben; danach bekommen alle Räume der einen Menge die ID der anderen. Das ist ein Durchlauf über das Gitter pro Vereinigung, einfacher als Union-Find und bei 2.601 Räumen schnell genug.",
"ITEM_3": "Start und Ziel liegen in zwei zufälligen Ecken. Dijkstra und A* laufen danach auf demselben Gitter wie auf der Wegfindungs-Seite.",
"ITEM_4": "Speicher: ein Knotenobjekt pro Zelle (10.201) plus die Liste der zu öffnenden Zellen."
}
},
"FRACTAL": {
@@ -571,7 +601,7 @@
"EXPLANATION": {
"TITLE": "Mathematische Kunst",
"MANDELBROT_EXPLANATION": "basiert auf der iterativen Formel 'z_{n+1} = z_n^2 + c'. Sie prüft für jeden Punkt in der komplexen Ebene, ob die Zahlenfolge stabil bleibt oder ins Unendliche entkommt. Vorteil: Gilt als 'Apfelmännchen' und Mutter der Fraktale. Sie bietet eine unendliche Vielfalt an selbstähnlichen Strukturen, in die man ewig hineinzoomen kann.",
"JULIA_EXPLANATION": "nutzt dieselbe Formel wie Mandelbrot, fixiert jedoch den Parameter 'c' und variiert den Startwert. Je nach Wahl von 'c' entstehen filigrane, wolkenartige Gebilde oder zusammenhanglose 'Staubwolken'. Vorteil: Ermöglicht eine enorme ästiehetische Varianz, da jede Koordinate der Mandelbrot-Menge ein völlig eigenes, einzigartiges Julia-Fraktal erzeugt.",
"JULIA_EXPLANATION": "nutzt dieselbe Formel wie Mandelbrot, fixiert jedoch den Parameter 'c' und variiert den Startwert. Je nach Wahl von 'c' entstehen filigrane, wolkenartige Gebilde oder zusammenhanglose 'Staubwolken'. Vorteil: Ermöglicht eine enorme ästhetische Varianz, da jede Koordinate der Mandelbrot-Menge ein völlig eigenes, einzigartiges Julia-Fraktal erzeugt.",
"NEWTON_EXPLANATION": "entsteht durch die Visualisierung des Newton-Verfahrens zur Nullstellen-Suche einer komplexen Funktion. Jeder Pixel wird danach eingefärbt, zu welcher Nullstelle der Algorithmus konvergiert. Vorteil: Erzeugt faszinierende, sternförmige Symmetrien und komplexe Grenzen, an denen sich die Einzugsgebiete der Nullstellen auf chaotische Weise treffen.",
"BURNING_SHIP_EXPLANATION": "ist eine variation des Mandelbrots, bei der vor jedem Iterationsschritt der Absolutbetrag der Real- und Imaginärteile genommen wird: '(|Re(z)| + i|Im(z)|)^2 + c'. Vorteil: Erzeugt eine markante, asymmetrische Struktur, die einem brennenden Schiff mit Segeln ähnelt. Das Fraktal wirkt düsterer und 'mechanischer' als die klassischen Mengen.",
"DISCLAIMER": "Alle diese Fraktale basieren auf dem Prinzip der Iteration und dem Chaos-Effekt. Das bedeutet für deine Visualisierung:",
@@ -580,6 +610,14 @@
"DISCLAIMER_3": "Komplexe Zahlen: Die Berechnung findet nicht in einem normalen Koordinatensystem statt, sondern in der komplexen Ebene mit realen und imaginären Anteilen.",
"DISCLAIMER_4": "Rechenintensität: Da für jeden Pixel hunderte Berechnungen durchgeführt werden, sind Fraktale ein klassischer Benchmark für die Performance von Grafikprozessoren (GPUs).",
"DISCLAIMER_BOTTOM": "Grafikkarten rechnen standardmäßig mit 32-Bit Fließkommazahlen (float). Diese haben nur etwa 7 Stellen Genauigkeit. Bei sehr hohem Zoom (> 100.000) ist der Unterschied zwischen zwei Pixeln so winzig, dass die Grafikkarte ihn nicht mehr darstellen kann. Sie berechnet für 10 Pixel nebeneinander exakt denselben Wert -> Du siehst Blöcke oder Treppenstufen."
},
"HOW_IT_WORKS": {
"INTRO": "Das Bild ist ein Fragment-Shader (GLSL) auf einem bildschirmfüllenden Rechteck in Babylon.js. Jeder Pixel rechnet unabhängig seine Folge: für Mandelbrot, Julia und Burning Ship z → z² + c, bis |z|² > 4 oder die maximale Iterationszahl erreicht ist (Fluchtzeit-Algorithmus). Newton iteriert z → z − (z³ − 1) / (3z²) und färbt nach der Nullstelle, gegen die der Pixel konvergiert.",
"ITEM_1": "Die CPU schickt pro Frame nur Uniforms: Mittelpunkt, Zoom, maximale Iterationen, Algorithmus, Farbschema und die Julia-Konstante. Die GPU rechnet alle Pixel parallel; Aufwand O(Pixel · Iterationen).",
"ITEM_2": "Die maximale Iterationszahl wächst mit dem Zoom: 100 + 200 · log10(Zoom), also bis etwa 1.060 beim maximalen Zoom 64.000.",
"ITEM_3": "Zoom per Mausrad hält den Punkt unter dem Cursor fest: sein Weltpunkt wird vor und nach dem Zoom gleich gesetzt und der Mittelpunkt entsprechend verschoben.",
"ITEM_4": "Die Farbe kommt aus dem Verhältnis Iterationen / Maximum; Punkte, die nie entkommen, bekommen die Farbe für t ≈ 1 (im Schema Blue-Gold dunkelrot).",
"ITEM_5": "Unter WebGPU übersetzt Babylon.js denselben GLSL-Shader nach WGSL; es gibt keinen eigenen Compute-Pfad."
}
},
"FRACTAL3D": {
@@ -597,7 +635,15 @@
"DISCLAIMER_1": "Keine Polygone: Es gibt keine Dreiecke oder Gitter. Die Form wird rein mathematisch für jeden Pixel in Echtzeit berechnet.",
"DISCLAIMER_2": "Distance Estimation: Der Algorithmus 'tastet' sich mit Lichtstrahlen voran, indem er berechnet, wie weit das nächste Objekt entfernt ist, ohne es sofort zu berühren.",
"DISCLAIMER_3": "Unendliche Details: Da die Oberfläche mathematisch definiert ist, verpixelt sie nicht beim Zoom – es erscheinen immer neue Strukturen.",
"DISCLAIMER_4": "Licht & Schatten: Um die Tiefe sichtbar zu machen, werden Lichtreflexionen und Schatten (Ambient Occlusion) basierend auf der Krümmung der Formel simuliert."
"DISCLAIMER_4": "Licht: Die Tiefe entsteht aus der Oberflächennormale: Flächen, die zur Kamera zeigen, sind heller, plus ein fester Anteil Umgebungslicht. Schatten und Ambient Occlusion werden nicht berechnet."
},
"HOW_IT_WORKS": {
"INTRO": "Es gibt keine Geometrie. Ein Fragment-Shader schickt pro Pixel einen Strahl von der Kamera in die Szene und tastet ihn mit Sphere Tracing (Raymarching) ab: ein Distance Estimator sagt, wie weit die Oberfläche mindestens entfernt ist, und der Strahl springt um diesen Betrag (mal 0,8 als Sicherheitsfaktor) weiter, maximal 128 Schritte. Vorher begrenzt ein Kugeltest (Radius 6) den Strahl auf den relevanten Bereich.",
"ITEM_1": "Mandelbulb: 8 Iterationen in Kugelkoordinaten mit Potenz 8 (z → z⁸ + c). Die Distanz ist 0,5 · ln(r) · r / dr, wobei dr die mitgeführte Ableitung ist.",
"ITEM_2": "Mandelbox: 15 Iterationen aus Box-Fold (Spiegeln an ±1), Sphere-Fold (Skalieren nach Radius) und Skalierung 2,8.",
"ITEM_3": "Julia-Bulb: wie Mandelbulb, aber mit fester Konstante c, die sich mit der Zeit leicht bewegt. Darum bewegt sich die Form.",
"ITEM_4": "Normalen kommen aus vier zusätzlichen Distanzabfragen. Beleuchtung: Licht aus Kamerarichtung plus 40 % Umgebungslicht, keine Schatten, kein Ambient Occlusion. Farbe: Orbit Trap (kleinster Radius während der Iteration) auf eine Cosinus-Palette.",
"ITEM_5": "Aufwand pro Frame: Pixel × Strahlschritte × Iterationen. Bei Full HD und Mandelbox im schlimmsten Fall rund 4 Milliarden Iterationsschritte. Das läuft als Fragment-Shader nur auf der GPU; einen CPU-Pfad gibt es nicht."
}
},
"PENDULUM": {
@@ -615,12 +661,19 @@
"EXPLANATION": {
"TITLE": "Chaostheorie: Das Doppelpendel",
"EXPLANATION": "Das Doppelpendel ist eines der bekanntesten und faszinierendsten Beispiele der Physik für ein dynamisches System, das 'deterministisches Chaos' erzeugt. Es besteht schlicht aus einem einfachen Pendel, an dessen unterem Ende ein zweites Pendel befestigt ist. Obwohl die zugrundeliegenden Bewegungsgesetze der klassischen Mechanik streng mathematisch definiert sind, ist das Verhalten des Doppelpendels auf lange Sicht absolut unvorhersehbar. Es gilt in der Physik als das klassische Vorzeigeobjekt für den sogenannten Schmetterlingseffekt.",
"DISCLAIMER": "Diese WebGPU-Simulation berechnet die Bewegungs- und Beschleunigungsgleichungen des Pendels 60-mal pro Sekunde in Echtzeit. Dabei gelten folgende Besonderheiten:",
"DISCLAIMER": "Die Simulation rechnet die Bewegungsgleichungen des Pendels einmal pro gerendertem Frame mit festem Zeitschritt dt = 0,015, auf der GPU (WebGPU) oder als Fallback auf der CPU. Dabei gelten folgende Besonderheiten:",
"DISCLAIMER_1": "Extreme Sensitivität: Winzigste Änderungen in den Startbedingungen (z.B. ein Tausendstel Grad Abweichung im Startwinkel oder bei der Masse) führen schon nach kurzer Zeit zu einer völlig anderen, chaotischen Flugbahn.",
"DISCLAIMER_2": "Deterministisches Chaos: Die Bewegung wirkt zwar völlig wild und zufällig, ist es aber nicht. Startest du die Simulation mit exakt denselben Werten neu, wird das Pendel zu 100 % denselben Weg fliegen.",
"DISCLAIMER_3": "Numerische Integration: Da Computer Zeit nicht stufenlos, sondern in winzigen Schritten (dt) berechnen, entstehen bei jedem Frame winzige mathematische Rundungsfehler. Diese summieren sich auf und beeinflussen das Chaos zusätzlich.",
"DISCLAIMER_4": "Energieerhaltung & Reibung: In einem perfekten physikalischen System ohne Widerstand würde das Pendel ewig weiterschwingen. Für eine natürliche Optik nutzt der Algorithmus einen künstlichen Dämpfungsfaktor, der Luftreibung simuliert und das System irgendwann beruhigt.",
"DISCLAIMER_BOTTOM": "HINWEIS: Wenn zuviele Impulse in das System gegeben werden, wird die Simulation instabil. Dann hängt das Pendel nur noch runter und es muss neu gestartet werden."
},
"HOW_IT_WORKS": {
"INTRO": "Die Bewegung folgt den Bewegungsgleichungen des Doppelpendels (Lagrange-Formulierung, Formeln wie im Wikipedia-Artikel). Pro gerendertem Frame wird ein Schritt mit festem Zeitschritt dt = 0,015 gerechnet: erst die Winkelbeschleunigungen a1 und a2, dann die Winkelgeschwindigkeiten (mal Dämpfung, plus Impuls), dann die Winkel (semi-implizites Euler-Verfahren).",
"ITEM_1": "WebGPU: ein Compute-Shader mit einem einzigen Thread rechnet den Physikschritt; der Zustand (θ1, θ2, v1, v2) bleibt in einem Storage Buffer auf der GPU. Ein zweiter Compute-Shader (64 Threads pro Workgroup, einer pro Pixel) zeichnet Stangen, Massen und Spur direkt in einen Pixel-Buffer; die Spur verblasst pro Frame um den Faktor Spurlänge. Ein Fragment-Shader zeigt den Buffer an.",
"ITEM_2": "Ohne WebGPU: dieselbe Physik in TypeScript auf der CPU. Die Spur entsteht per Ping-Pong zwischen zwei Render-Target-Texturen: ein GLSL-Shader liest das alte Bild, dämpft es und zeichnet die beiden Massen neu; ein zweiter Shader zeigt Spur und Stangen an.",
"ITEM_3": "Pixel-Buffer-Kodierung: Intensität 0 bis 1 für Spur 1, +2 für Spur 2, +10 und +20 für die Stangen. So reicht ein Float pro Pixel.",
"ITEM_4": "Der Zeitschritt ist fest und nicht an die Bildrate gekoppelt: bei 120 Hz läuft das Pendel doppelt so schnell wie bei 60 Hz. Das Euler-Verfahren erhält die Energie nicht exakt; große Impulse können die Simulation instabil machen (siehe Hinweis)."
}
},
"CLOTH": {
@@ -640,13 +693,21 @@
"DATA_STRUCTURES_EXPLANATION_TITLE": "Datenstrukturen",
"CLOTH_SIMULATION_EXPLANATION": "Stoffsimulationen modellieren Textilien meist als ein Gitter aus Massepunkten (Vertices), die durch unsichtbare Verbindungen zusammengehalten werden. Ziel ist es, physikalische Einflüsse wie Schwerkraft, Wind und Kollisionen in Echtzeit darzustellen, ohne dass das Material zerreißt oder sich unnatürlich wie Gummi dehnt.",
"XPBD_EXPLANATION": "XPBD (Extended Position-Based Dynamics) ist ein moderner Algorithmus, der statt Beschleunigungen direkt die Positionen der Punkte manipuliert, um Abstandsbedingungen (Constraints) zu erfüllen. Das 'Extended' bedeutet, dass echte physikalische Steifigkeit unabhängig von der Framerate simuliert wird. Vorteil: Absolut stabil, explodiert nicht und topologische Änderungen (wie das Zerschneiden von Stoff) sind trivial. Nachteil: Es ist ein iteratives Näherungsverfahren und physikalisch minimal weniger akkurat als komplexe Matrix-Löser.",
"GPU_PARALLELIZATION_EXPLANATION": "Um zehntausende Punkte parallel auf der Grafikkarte zu berechnen, muss man 'Race Conditions' verhindern – also dass zwei Rechenkerne gleichzeitig denselben Knotenpunkt verschieben. Die Lösung nennt sich 'Independent Sets' (oder Graph Coloring): Die Verbindungen werden in isolierte Gruppen (z. B. 4 Phasen bei einem Gitter) unterteilt, in denen sich kein einziger Punkt überschneidet. So kann die GPU jede Gruppe blind und mit maximaler Geschwindigkeit abarbeiten.",
"GPU_PARALLELIZATION_EXPLANATION": "Um zehntausende Punkte parallel auf der Grafikkarte zu berechnen, muss man 'Race Conditions' verhindern – also dass zwei Rechenkerne gleichzeitig denselben Knotenpunkt verschieben. Die Lösung nennt sich 'Independent Sets' (oder Graph Coloring): Die Verbindungen werden in isolierte Gruppen (hier 8 Phasen: 2 horizontal, 2 vertikal, 4 diagonal) unterteilt, in denen sich kein einziger Punkt überschneidet. So kann die GPU jede Gruppe blind und mit maximaler Geschwindigkeit abarbeiten.",
"DATA_STRUCTURES_EXPLANATION": "Für maximale GPU-Performance müssen Daten speicherfreundlich ausgerichtet werden (16-Byte-Alignment). Anstatt viele einzelne Variablen zu nutzen, packt man Informationen clever in 4er-Blöcke (vec4). Ein Vertex speichert so z. B. [X, Y, Z, Inverse_Masse]. Hat ein Punkt die inverse Masse 0.0, wird er vom Algorithmus ignoriert und schwebt unbeweglich in der Luft – ein eleganter Trick für Aufhängungen ohne extra Wenn-Dann-Abfragen.",
"DISCLAIMER": "XPBD vs. Masse-Feder-Systeme: In der physikalischen Simulation gibt es grundlegende Architektur-Unterschiede beim Lösen der Gleichungen:",
"DISCLAIMER_1": "Klassische Masse-Feder-Systeme: Hier werden Kräfte (Hookesches Gesetz) berechnet, die zu Beschleunigungen und schließlich zu neuen Positionen führen. Es gibt zwei Wege, diese mathematisch in die Zukunft zu rechnen (Integration):",
"DISCLAIMER_2": "Explizite Löser (z.B. Forward Euler): Sie berechnen den nächsten Schritt stur aus dem aktuellen Zustand. Sie sind leicht zu programmieren, aber bei steifen Stoffen extrem instabil. Die Kräfte schaukeln sich auf und die simulation 'explodiert', sofern man keine winzigen, sehr leistungsfressenden Zeitschritte wählt.",
"DISCLAIMER_3": "Implizite Löser (z.B. Backward Euler): Sie berechnen den nächsten Schritt basierend auf dem zukünftigen Zustand. Das ist mathematisch enorm stabil, erfordert aber das Lösen riesiger globaler Matrix-Gleichungssysteme in jedem Frame. Dies ist auf der GPU schwerer zu parallelisieren und bricht zusammen, wenn sich die Struktur ändert (z. B. durch Zerschneiden des Stoffs).",
"DISCLAIMER_4": "Der XPBD-Kompromiss: XPBD umgeht dieses komplexe Matrix-Problem völlig, indem es als lokaler Löser arbeitet. Es kombiniert die unbedingte Stabilität eines impliziten Lösers mit der enormen Geschwindigkeit, Parallelisierbarkeit und dynamischen Anpassungsfähigkeit eines expliziten Systems."
},
"HOW_IT_WORKS": {
"INTRO": "Der Stoff ist ein Gitter aus 100 × 100 = 10.000 Partikeln. Jedes Partikel ist ein vec4 [x, y, z, 1/Masse]; die obere Reihe hat inverse Masse 0 und hängt fest. 39.402 Abstandsbedingungen (Constraints) halten die Partikel zusammen: horizontal, vertikal und zwei Diagonalen gegen Scherung. Pro Frame: Integration (Schwerkraft, Wind, Positionsvorhersage), dann 15 Substeps, in denen jede Bedingung einmal gelöst wird (XPBD), zuletzt die Geschwindigkeit aus der Positionsänderung.",
"ITEM_1": "XPBD: pro Bedingung wird die Abweichung C = |pA − pB| − Ruhelänge berechnet und beide Partikel um λ = −C / (wA + wB + α) entlang der Verbindung verschoben, gewichtet mit der inversen Masse. α = Compliance / dt² macht die Steifigkeit unabhängig vom Zeitschritt. Der Regler Dehnung skaliert die Ruhelänge.",
"ITEM_2": "GPU (WebGPU): drei Compute-Shader (Integrate, Solve, Velocity) mit 64 Threads pro Workgroup. Alle Daten bleiben in Storage Buffers auf der GPU; der Vertex-Shader liest die Positionen direkt aus dem Buffer. Nichts geht zurück zur CPU.",
"ITEM_3": "Graph Coloring: zwei Threads dürfen nie dasselbe Partikel schreiben. Darum sind die Bedingungen in 8 Phasen sortiert (gerade und ungerade Spalten, gerade und ungerade Zeilen, je zwei pro Diagonale). In einer Phase hat kein Partikel zwei Bedingungen, also läuft jede Phase ohne Locks. Pro Frame sind das 15 · 8 = 120 Solver-Dispatches (dazu je einer für Integrate und Velocity).",
"ITEM_4": "Ohne WebGPU: dieselben drei Schritte in TypeScript auf der CPU mit identischem Speicherlayout (Float32Array). Die Positionen werden pro Frame in den Vertex-Buffer des Meshes kopiert. 39.402 · 15 = 591.030 Bedingungs-Lösungen pro Frame sind für eine CPU viel, die Bildrate fällt deutlich.",
"ITEM_5": "Wind: feste Richtung (5, 0, 15) plus ein Sinus-Flattern aus Position und Zeit. Der Flatter-Anteil gibt zusätzlich leichten Auftrieb (y: Flattern · 2)."
}
},
"GPU": {
@@ -657,7 +718,7 @@
"TITLE": "Algorithmen",
"PATHFINDING": {
"TITLE": "Wegfindung",
"DESCRIPTION": "Vergleich von Dijkstra vs. A*."
"DESCRIPTION": "Dijkstra und A* auf einem Gitter, einzeln oder im direkten Vergleich."
},
"SORTING": {
"TITLE": "Sortierung",
@@ -669,7 +730,7 @@
},
"LABYRINTH": {
"TITLE": "Labyrinth-Erzeugung",
"DESCRIPTION": "Visualisierung verschiedener Laybrinth-Erzeugungs-Algorithmen."
"DESCRIPTION": "Labyrinth-Erzeugung mit Prim und Kruskal, danach Wegfindung darin."
},
"FOUR_COLOR": {
"TITLE": "Vier-Farben-Satz",
@@ -689,15 +750,17 @@
},
"PENDULUM": {
"TITLE": "Doppel-Pendel",
"DESCRIPTION": "Visualisierung einer chaotischen Doppel-Pendel-Simulation mit WebGPU."
"DESCRIPTION": "Chaotisches Doppelpendel, Physik im WebGPU-Compute-Shader (Fallback WebGL + CPU)."
},
"CLOTH": {
"TITLE": "Stoffsimulation",
"DESCRIPTION": "Simulation on Stoff mit WebGPU."
"DESCRIPTION": "Stoffsimulation mit XPBD auf der GPU (WebGPU, Fallback WebGL + CPU)."
},
"NOTE": "HINWEIS",
"GRID_HEIGHT": "Höhe",
"GRID_WIDTH": "Beite"
"GRID_WIDTH": "Breite",
"HOW_IT_WORKS": "So funktioniert es",
"SOURCE": "Quellcode"
},
"FOUR_COLOR": {
"TITLE": "Vier-Farben-Satz",
@@ -728,6 +791,13 @@
},
"ALERT": {
"NO_SOLUTION": "Keine Lösung gefunden (das sollte bei einer planaren Karte nicht passieren!)."
},
"HOW_IT_WORKS": {
"INTRO": "Die Karte entsteht auf einem Gitter: pro 30 Zellen wird ein Keim an eine zufällige freie Position gesetzt. Alle Keime wachsen gleichzeitig per Breitensuche (eine gemeinsame Warteschlange), bis jede Zelle zu einer Region gehört. Zwei Regionen sind Nachbarn, wenn zwei ihrer Zellen eine Kante teilen.",
"ITEM_1": "Datenstruktur: eine Liste von Regionen, jede mit einem Set ihrer Nachbar-IDs (Adjazenzliste). Das Gitter speichert pro Zelle nur Regions-ID und Farbe.",
"ITEM_2": "Lösen: Backtracking in der Reihenfolge der Regions-IDs. Für jede Region werden die Farben 1 bis 4 probiert; passt keine, geht der Löser eine Region zurück. Keine Heuristik wie 'meiste Nachbarn zuerst', darum liegen die Farbversuche bei großen Karten manchmal deutlich über der Zahl der Regionen.",
"ITEM_3": "Die Standardkarte (25 × 25, 20 Regionen) löst er in unter 1 ms. Große Karten können sehr lange dauern, weil das Backtracking keine Heuristik hat und der Worst Case exponentiell ist.",
"ITEM_4": "Prüfen: alle Regionen durchgehen und jede Farbe mit den Nachbarn vergleichen, O(Regionen + Grenzen)."
}
},
"FOURIER": {
@@ -749,6 +819,14 @@
"DISCLAIMER_2": "Jeder Punkt ist eine komplexe Zahl x + iy. Eine direkte diskrete Fourier-Transformation liefert einen Kreis pro Frequenz.",
"DISCLAIMER_3": "Die Kreise werden nach Radius sortiert. Der Regler behält nur die größten N Kreise.",
"DISCLAIMER_BOTTOM": "Weniger Kreise geben eine glattere Näherung. Mit allen Kreisen läuft die Kurve exakt durch alle 256 Punkte."
},
"HOW_IT_WORKS": {
"INTRO": "Die gezeichnete Form wird als geschlossenes Polygon behandelt und auf 256 Punkte mit gleichem Bogenabstand neu abgetastet. Jeder Punkt ist eine komplexe Zahl x + i·y. Eine direkte diskrete Fourier-Transformation (zwei verschachtelte Schleifen, O(N²) = 65.536 Schritte) liefert pro Frequenz einen Kreis mit Radius, Startwinkel und Drehzahl. Die Kreise werden nach Radius sortiert.",
"ITEM_1": "Frequenzen laufen von 0 bis N−1; alles über N/2 zählt als negative Frequenz, damit Kreise auch rückwärts drehen.",
"ITEM_2": "Pro Frame werden die Kreismittelpunkte addiert (O(Kreise)), die Spitze des letzten Kreises kommt an die Spur. Nach einer vollen Periode wird die Spur gelöscht.",
"ITEM_3": "Gezeichnet wird auf Canvas 2D mit requestAnimationFrame außerhalb der Angular-Zone. dt ist die Zeit zwischen zwei Frames, darum ist die Geschwindigkeit unabhängig von der Bildrate.",
"ITEM_4": "Vorlagen: Herz und Stern sind Formeln, das Quadrat vier Eckpunkte, der Hund ist eine Punktliste, die mit drei Chaikin-Durchläufen (Corner Cutting) geglättet wird.",
"ITEM_5": "Weniger Kreise wirken wie ein Tiefpass: nur die größten Radien bleiben, die Form wird weicher."
}
},
"STOPWATCH": {