@jjlmoya/utils-science 1.30.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +5 -1
  4. package/src/index.ts +2 -0
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/mandelbrot-fractal/bibliography.astro +14 -0
  8. package/src/tool/mandelbrot-fractal/bibliography.ts +16 -0
  9. package/src/tool/mandelbrot-fractal/component.astro +242 -0
  10. package/src/tool/mandelbrot-fractal/entry.ts +26 -0
  11. package/src/tool/mandelbrot-fractal/i18n/de.ts +159 -0
  12. package/src/tool/mandelbrot-fractal/i18n/en.ts +160 -0
  13. package/src/tool/mandelbrot-fractal/i18n/es.ts +159 -0
  14. package/src/tool/mandelbrot-fractal/i18n/fr.ts +159 -0
  15. package/src/tool/mandelbrot-fractal/i18n/id.ts +159 -0
  16. package/src/tool/mandelbrot-fractal/i18n/it.ts +159 -0
  17. package/src/tool/mandelbrot-fractal/i18n/ja.ts +159 -0
  18. package/src/tool/mandelbrot-fractal/i18n/ko.ts +159 -0
  19. package/src/tool/mandelbrot-fractal/i18n/nl.ts +159 -0
  20. package/src/tool/mandelbrot-fractal/i18n/pl.ts +159 -0
  21. package/src/tool/mandelbrot-fractal/i18n/pt.ts +159 -0
  22. package/src/tool/mandelbrot-fractal/i18n/ru.ts +159 -0
  23. package/src/tool/mandelbrot-fractal/i18n/sv.ts +159 -0
  24. package/src/tool/mandelbrot-fractal/i18n/tr.ts +159 -0
  25. package/src/tool/mandelbrot-fractal/i18n/zh.ts +159 -0
  26. package/src/tool/mandelbrot-fractal/index.ts +11 -0
  27. package/src/tool/mandelbrot-fractal/logic/MandelbrotEngine.ts +67 -0
  28. package/src/tool/mandelbrot-fractal/mandelbrot-fractal-calculator.css +357 -0
  29. package/src/tool/mandelbrot-fractal/seo.astro +15 -0
  30. package/src/tool/twin-paradox-visualizer/bibliography.astro +14 -0
  31. package/src/tool/twin-paradox-visualizer/bibliography.ts +12 -0
  32. package/src/tool/twin-paradox-visualizer/component.astro +205 -0
  33. package/src/tool/twin-paradox-visualizer/entry.ts +26 -0
  34. package/src/tool/twin-paradox-visualizer/i18n/de.ts +168 -0
  35. package/src/tool/twin-paradox-visualizer/i18n/en.ts +168 -0
  36. package/src/tool/twin-paradox-visualizer/i18n/es.ts +168 -0
  37. package/src/tool/twin-paradox-visualizer/i18n/fr.ts +168 -0
  38. package/src/tool/twin-paradox-visualizer/i18n/id.ts +168 -0
  39. package/src/tool/twin-paradox-visualizer/i18n/it.ts +168 -0
  40. package/src/tool/twin-paradox-visualizer/i18n/ja.ts +168 -0
  41. package/src/tool/twin-paradox-visualizer/i18n/ko.ts +168 -0
  42. package/src/tool/twin-paradox-visualizer/i18n/nl.ts +168 -0
  43. package/src/tool/twin-paradox-visualizer/i18n/pl.ts +168 -0
  44. package/src/tool/twin-paradox-visualizer/i18n/pt.ts +168 -0
  45. package/src/tool/twin-paradox-visualizer/i18n/ru.ts +168 -0
  46. package/src/tool/twin-paradox-visualizer/i18n/sv.ts +168 -0
  47. package/src/tool/twin-paradox-visualizer/i18n/tr.ts +168 -0
  48. package/src/tool/twin-paradox-visualizer/i18n/zh.ts +168 -0
  49. package/src/tool/twin-paradox-visualizer/index.ts +11 -0
  50. package/src/tool/twin-paradox-visualizer/logic.ts +33 -0
  51. package/src/tool/twin-paradox-visualizer/seo.astro +15 -0
  52. package/src/tool/twin-paradox-visualizer/twin-paradox-visualizer.css +395 -0
  53. package/src/tools.ts +4 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-science",
3
- "version": "1.30.0",
3
+ "version": "1.32.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -12,10 +12,12 @@ import { radioactiveDecay } from '../tool/radioactive-decay/index';
12
12
  import { naturalSelectionDrift } from '../tool/natural-selection-drift/index';
13
13
  import { entropySecondLaw } from '../tool/entropy-second-law/index';
14
14
  import { phaseDiagramCriticalPoints } from '../tool/phase-diagram-critical-points/index';
15
+ import { twinParadoxVisualizer } from '../tool/twin-paradox-visualizer/index';
16
+ import { mandelbrotFractal } from '../tool/mandelbrot-fractal/index';
15
17
 
16
18
  export const scienceCategory: ScienceCategoryEntry = {
17
19
  icon: 'mdi:flask',
18
- tools: [colonyCounter, asteroidImpact, microwaveDetector, simulationProbability, cellularRenewal, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, phaseDiagramCriticalPoints],
20
+ tools: [colonyCounter, asteroidImpact, microwaveDetector, simulationProbability, cellularRenewal, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal],
19
21
  i18n: {
20
22
  es: () => import('./i18n/es').then((m) => m.content),
21
23
  en: () => import('./i18n/en').then((m) => m.content),
package/src/entries.ts CHANGED
@@ -12,6 +12,8 @@ export { radioactiveDecay } from './tool/radioactive-decay/entry';
12
12
  export { naturalSelectionDrift } from './tool/natural-selection-drift/entry';
13
13
  export { entropySecondLaw } from './tool/entropy-second-law/entry';
14
14
  export { phaseDiagramCriticalPoints } from './tool/phase-diagram-critical-points/entry';
15
+ export { twinParadoxVisualizer } from './tool/twin-paradox-visualizer/entry';
16
+ export { mandelbrotFractal } from './tool/mandelbrot-fractal/entry';
15
17
  export { scienceCategory } from './category';
16
18
  import { asteroidImpact } from './tool/asteroid-impact/entry';
17
19
  import { cellularRenewal } from './tool/cellular-renewal/entry';
@@ -26,4 +28,6 @@ import { radioactiveDecay } from './tool/radioactive-decay/entry';
26
28
  import { naturalSelectionDrift } from './tool/natural-selection-drift/entry';
27
29
  import { entropySecondLaw } from './tool/entropy-second-law/entry';
28
30
  import { phaseDiagramCriticalPoints } from './tool/phase-diagram-critical-points/entry';
29
- export const ALL_ENTRIES = [asteroidImpact, cellularRenewal, colonyCounter, microwaveDetector, simulationProbability, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, phaseDiagramCriticalPoints];
31
+ import { twinParadoxVisualizer } from './tool/twin-paradox-visualizer/entry';
32
+ import { mandelbrotFractal } from './tool/mandelbrot-fractal/entry';
33
+ export const ALL_ENTRIES = [asteroidImpact, cellularRenewal, colonyCounter, microwaveDetector, simulationProbability, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal];
package/src/index.ts CHANGED
@@ -13,6 +13,8 @@ export { RADIOACTIVE_DECAY_TOOL } from './tool/radioactive-decay/index';
13
13
  export { NATURAL_SELECTION_DRIFT_TOOL } from './tool/natural-selection-drift/index';
14
14
  export { ENTROPY_SECOND_LAW_TOOL } from './tool/entropy-second-law/index';
15
15
  export { PHASE_DIAGRAM_CRITICAL_POINTS_TOOL } from './tool/phase-diagram-critical-points/index';
16
+ export { TWIN_PARADOX_VISUALIZER_TOOL } from './tool/twin-paradox-visualizer/index';
17
+ export { MANDELBROT_FRACTAL_TOOL } from './tool/mandelbrot-fractal/index';
16
18
 
17
19
  export type {
18
20
  KnownLocale,
@@ -18,7 +18,7 @@ describe('Locale Completeness Validation', () => {
18
18
  });
19
19
  });
20
20
 
21
- it('all 13 tools registered', () => {
22
- expect(ALL_TOOLS.length).toBe(13);
21
+ it('all 15 tools registered', () => {
22
+ expect(ALL_TOOLS.length).toBe(15);
23
23
  });
24
24
  });
@@ -4,8 +4,8 @@ import { scienceCategory } from '../data';
4
4
 
5
5
  describe('Tool Validation Suite', () => {
6
6
  describe('Library Registration', () => {
7
- it('should have 13 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(13);
7
+ it('should have 15 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(15);
9
9
  });
10
10
 
11
11
  it('scienceCategory should be defined', () => {
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { mandelbrotFractal } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const content = await mandelbrotFractal.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SharedBibliography links={content.bibliography} />}
@@ -0,0 +1,16 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'The Fractal Geometry of Nature',
6
+ url: 'https://en.wikipedia.org/wiki/The_Fractal_Geometry_of_Nature',
7
+ },
8
+ {
9
+ name: 'Complex Dynamics and Renormalization',
10
+ url: 'https://abel.math.harvard.edu/~ctm/papers/home/text/papers/real/book.pdf',
11
+ },
12
+ {
13
+ name: 'The Science of Fractal Images',
14
+ url: 'https://www.scribd.com/document/679858135/Antologie-The-Science-of-Fractal-Images',
15
+ },
16
+ ];
@@ -0,0 +1,242 @@
1
+ ---
2
+ import './mandelbrot-fractal-calculator.css';
3
+
4
+ interface Props {
5
+ ui: Record<string, string>;
6
+ }
7
+
8
+ const { ui } = Astro.props;
9
+ ---
10
+
11
+ <div class="mandelbrot-root" id="mandelbrot-root">
12
+ <section class="mandelbrot-stage" aria-label={ui.canvasLabel}>
13
+ <canvas id="mandelbrot-canvas" class="mandelbrot-canvas"></canvas>
14
+ <div class="mandelbrot-reticle" aria-hidden="true"></div>
15
+ <div class="mandelbrot-coordinate-strip">
16
+ <span>{ui.centerPoint}</span>
17
+ <strong id="mandelbrot-center">-0.500000 + 0.000000i</strong>
18
+ </div>
19
+ </section>
20
+
21
+ <section class="mandelbrot-panel">
22
+ <div class="mandelbrot-presets" aria-label={ui.presetsLabel}>
23
+ <button class="mandelbrot-preset active" data-x="-0.5" data-y="0" data-scale="1">{ui.presetFull}</button>
24
+ <button class="mandelbrot-preset" data-x="-0.743643887" data-y="0.131825904" data-scale="550">{ui.presetSeahorse}</button>
25
+ <button class="mandelbrot-preset" data-x="-0.101096" data-y="0.956286" data-scale="190">{ui.presetSpiral}</button>
26
+ </div>
27
+
28
+ <button id="mandelbrot-reset" class="mandelbrot-reset-button">{ui.reset}</button>
29
+
30
+ <div class="mandelbrot-readouts">
31
+ <div class="mandelbrot-readout mandelbrot-readout-hero">
32
+ <span>{ui.magnification}</span>
33
+ <strong id="mandelbrot-zoom">1x</strong>
34
+ </div>
35
+ <div class="mandelbrot-readout">
36
+ <span>{ui.visibleWindow}</span>
37
+ <strong id="mandelbrot-window">3.500 x 2.000</strong>
38
+ </div>
39
+ <div class="mandelbrot-readout">
40
+ <span>{ui.renderBudget}</span>
41
+ <strong id="mandelbrot-budget">180</strong>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="mandelbrot-controls">
46
+ <label class="mandelbrot-control">
47
+ <span>{ui.iterationsLabel}</span>
48
+ <input id="mandelbrot-iterations" type="range" min="60" max="900" value="180" step="20" />
49
+ </label>
50
+ <label class="mandelbrot-control">
51
+ <span>{ui.contrastLabel}</span>
52
+ <input id="mandelbrot-contrast" type="range" min="0.55" max="2.4" value="1.15" step="0.05" />
53
+ </label>
54
+ <label class="mandelbrot-control">
55
+ <span>{ui.colorLabel}</span>
56
+ <select id="mandelbrot-palette">
57
+ <option value="ember">{ui.paletteEmber}</option>
58
+ <option value="lagoon">{ui.paletteLagoon}</option>
59
+ <option value="ink">{ui.paletteInk}</option>
60
+ </select>
61
+ </label>
62
+ </div>
63
+ </section>
64
+ </div>
65
+
66
+ <script>
67
+ import { MandelbrotEngine } from './logic/MandelbrotEngine';
68
+
69
+ const root = document.getElementById('mandelbrot-root');
70
+
71
+ if (root) {
72
+ const canvas = document.getElementById('mandelbrot-canvas') as HTMLCanvasElement;
73
+ const iterationsInput = document.getElementById('mandelbrot-iterations') as HTMLInputElement;
74
+ const contrastInput = document.getElementById('mandelbrot-contrast') as HTMLInputElement;
75
+ const paletteInput = document.getElementById('mandelbrot-palette') as HTMLSelectElement;
76
+ const centerOutput = document.getElementById('mandelbrot-center');
77
+ const zoomOutput = document.getElementById('mandelbrot-zoom');
78
+ const windowOutput = document.getElementById('mandelbrot-window');
79
+ const budgetOutput = document.getElementById('mandelbrot-budget');
80
+ const presets = document.querySelectorAll<HTMLButtonElement>('.mandelbrot-preset');
81
+ const resetButton = document.getElementById('mandelbrot-reset');
82
+ const engine = new MandelbrotEngine();
83
+ const storageKey = 'mandelbrot-fractal-calculator-state';
84
+
85
+ const state = {
86
+ centerX: -0.5,
87
+ centerY: 0,
88
+ scale: 1,
89
+ width: 0,
90
+ height: 0,
91
+ };
92
+
93
+ function restoreNumber(value: unknown, fallback: number, min = -Infinity): number {
94
+ return Number.isFinite(value) && Number(value) >= min ? Number(value) : fallback;
95
+ }
96
+
97
+ function restoreInput(input: HTMLInputElement | HTMLSelectElement, value: unknown) {
98
+ if (typeof value === 'string') input.value = value;
99
+ }
100
+
101
+ function loadState() {
102
+ try {
103
+ const saved = window.localStorage.getItem(storageKey);
104
+ if (!saved) return;
105
+
106
+ const parsed = JSON.parse(saved);
107
+ state.centerX = restoreNumber(parsed.centerX, state.centerX);
108
+ state.centerY = restoreNumber(parsed.centerY, state.centerY);
109
+ state.scale = restoreNumber(parsed.scale, state.scale, 1);
110
+ restoreInput(iterationsInput, parsed.iterations);
111
+ restoreInput(contrastInput, parsed.contrast);
112
+ restoreInput(paletteInput, parsed.palette);
113
+ presets.forEach((preset) => preset.classList.remove('active'));
114
+ } catch {
115
+ window.localStorage.removeItem(storageKey);
116
+ }
117
+ }
118
+
119
+ function saveState() {
120
+ const payload = {
121
+ centerX: state.centerX,
122
+ centerY: state.centerY,
123
+ scale: state.scale,
124
+ iterations: iterationsInput.value,
125
+ contrast: contrastInput.value,
126
+ palette: paletteInput.value,
127
+ };
128
+ window.localStorage.setItem(storageKey, JSON.stringify(payload));
129
+ }
130
+
131
+ function channel(t: number, phase: number, palette: string): number {
132
+ const wave = Math.sin((t + phase) * Math.PI * 2) * 0.5 + 0.5;
133
+ if (palette === 'lagoon') return Math.round(32 + wave * 196);
134
+ if (palette === 'ink') return Math.round(18 + Math.pow(wave, 2.2) * 230);
135
+ return Math.round(42 + wave * 210);
136
+ }
137
+
138
+ function colorFor(sample: ReturnType<MandelbrotEngine['sample']>, max: number, contrast: number, palette: string): [number, number, number] {
139
+ if (!sample.escaped) return palette === 'ink' ? [4, 8, 18] : [8, 10, 14];
140
+ const t = Math.pow(sample.smooth / max, contrast);
141
+ if (palette === 'lagoon') return [channel(t, 0.52, palette), channel(t, 0.1, palette), channel(t, 0.82, palette)];
142
+ if (palette === 'ink') return [channel(t, 0.78, palette), channel(t, 0.55, palette), channel(t, 0.18, palette)];
143
+ return [channel(t, 0.02, palette), channel(t, 0.72, palette), channel(t, 0.42, palette)];
144
+ }
145
+
146
+ function resizeCanvas() {
147
+ const rect = canvas.getBoundingClientRect();
148
+ const dpr = Math.min(window.devicePixelRatio || 1, 2);
149
+ state.width = Math.max(320, Math.floor(rect.width));
150
+ state.height = Math.max(260, Math.floor(rect.height));
151
+ canvas.width = Math.floor(state.width * dpr);
152
+ canvas.height = Math.floor(state.height * dpr);
153
+ }
154
+
155
+ function render() {
156
+ resizeCanvas();
157
+ const ctx = canvas.getContext('2d');
158
+ if (!ctx) return;
159
+
160
+ const maxIterations = parseInt(iterationsInput.value, 10);
161
+ const contrast = parseFloat(contrastInput.value);
162
+ const palette = paletteInput.value;
163
+ const image = ctx.createImageData(canvas.width, canvas.height);
164
+ const dpr = canvas.width / state.width;
165
+
166
+ for (let py = 0; py < canvas.height; py += 1) {
167
+ for (let px = 0; px < canvas.width; px += 1) {
168
+ const complex = engine.pixelToComplex(px / dpr, py / dpr, state);
169
+ const sample = engine.sample(complex.real, complex.imaginary, maxIterations);
170
+ const color = colorFor(sample, maxIterations, contrast, palette);
171
+ const index = (py * canvas.width + px) * 4;
172
+ image.data[index] = color[0];
173
+ image.data[index + 1] = color[1];
174
+ image.data[index + 2] = color[2];
175
+ image.data[index + 3] = 255;
176
+ }
177
+ }
178
+
179
+ ctx.putImageData(image, 0, 0);
180
+ updateStats(maxIterations);
181
+ saveState();
182
+ }
183
+
184
+ function updateStats(maxIterations: number) {
185
+ const stats = engine.getStats(state);
186
+ if (centerOutput) centerOutput.textContent = stats.centerLabel;
187
+ if (zoomOutput) zoomOutput.textContent = `${stats.magnification.toLocaleString(undefined, { maximumFractionDigits: 1 })}x`;
188
+ if (windowOutput) windowOutput.textContent = `${formatSpan(stats.visibleWidth)} x ${formatSpan(stats.visibleHeight)}`;
189
+ if (budgetOutput) budgetOutput.textContent = maxIterations.toString();
190
+ }
191
+
192
+ function formatSpan(value: number): string {
193
+ if (value < 0.001) return value.toExponential(3);
194
+ if (value < 0.1) return value.toFixed(6);
195
+ return value.toFixed(4);
196
+ }
197
+
198
+ function setViewport(centerX: number, centerY: number, scale: number) {
199
+ state.centerX = centerX;
200
+ state.centerY = centerY;
201
+ state.scale = scale;
202
+ render();
203
+ }
204
+
205
+ function resetState() {
206
+ window.localStorage.removeItem(storageKey);
207
+ iterationsInput.value = '180';
208
+ contrastInput.value = '1.15';
209
+ paletteInput.value = 'ember';
210
+ presets.forEach((preset) => preset.classList.remove('active'));
211
+ presets[0]?.classList.add('active');
212
+ setViewport(-0.5, 0, 1);
213
+ }
214
+
215
+ presets.forEach((button) => {
216
+ button.addEventListener('click', () => {
217
+ presets.forEach((preset) => preset.classList.remove('active'));
218
+ button.classList.add('active');
219
+ setViewport(
220
+ parseFloat(button.dataset.x || '-0.5'),
221
+ parseFloat(button.dataset.y || '0'),
222
+ parseFloat(button.dataset.scale || '1'),
223
+ );
224
+ });
225
+ });
226
+
227
+ canvas.addEventListener('click', (event) => {
228
+ const rect = canvas.getBoundingClientRect();
229
+ const complex = engine.pixelToComplex(event.clientX - rect.left, event.clientY - rect.top, state);
230
+ presets.forEach((preset) => preset.classList.remove('active'));
231
+ setViewport(complex.real, complex.imaginary, state.scale * 2.25);
232
+ });
233
+
234
+ iterationsInput.addEventListener('input', render);
235
+ contrastInput.addEventListener('input', render);
236
+ paletteInput.addEventListener('change', render);
237
+ resetButton?.addEventListener('click', resetState);
238
+ window.addEventListener('resize', render);
239
+ loadState();
240
+ render();
241
+ }
242
+ </script>
@@ -0,0 +1,26 @@
1
+ import type { ScienceToolEntry } from '../../types';
2
+
3
+ export const mandelbrotFractal: ScienceToolEntry = {
4
+ id: 'mandelbrot-fractal-calculator',
5
+ icons: {
6
+ bg: 'mdi:blur-radial',
7
+ fg: 'mdi:chart-scatter-plot',
8
+ },
9
+ i18n: {
10
+ de: () => import('./i18n/de').then((m) => m.content),
11
+ en: () => import('./i18n/en').then((m) => m.content),
12
+ es: () => import('./i18n/es').then((m) => m.content),
13
+ fr: () => import('./i18n/fr').then((m) => m.content),
14
+ id: () => import('./i18n/id').then((m) => m.content),
15
+ it: () => import('./i18n/it').then((m) => m.content),
16
+ ja: () => import('./i18n/ja').then((m) => m.content),
17
+ ko: () => import('./i18n/ko').then((m) => m.content),
18
+ nl: () => import('./i18n/nl').then((m) => m.content),
19
+ pl: () => import('./i18n/pl').then((m) => m.content),
20
+ pt: () => import('./i18n/pt').then((m) => m.content),
21
+ ru: () => import('./i18n/ru').then((m) => m.content),
22
+ sv: () => import('./i18n/sv').then((m) => m.content),
23
+ tr: () => import('./i18n/tr').then((m) => m.content),
24
+ zh: () => import('./i18n/zh').then((m) => m.content),
25
+ },
26
+ };
@@ -0,0 +1,159 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+
4
+ const slug = 'mandelbrot-fraktal-rechner';
5
+ const title = 'Mandelbrot Fraktal Rechner und Selbstahnlichkeits Explorer';
6
+ const description = 'Erkunden Sie die Mandelbrot Menge, zoomen Sie in selbstahnliche Fraktalgrenzen hinein und vergleichen Sie Iterationstiefe, Farbkontrast und Koordinaten der komplexen Ebene.';
7
+
8
+ const howTo = [
9
+ {
10
+ name: 'Wahlen Sie eine Region der Mandelbrot Menge',
11
+ text: 'Beginnen Sie mit der gesamten Menge oder springen Sie direkt zu einer detailreichen Region wie dem Seepferdchental oder einem spiralfoermigen Minibrot.',
12
+ },
13
+ {
14
+ name: 'Zoomen Sie durch Klicken auf das Bild',
15
+ text: 'Klicken Sie auf einen beliebigen Punkt auf der Leinwand, um die komplexe Ebene neu zu zentrieren und den Fraktal um diesen Punkt zu vergroessern.',
16
+ },
17
+ {
18
+ name: 'Passen Sie Iterationstiefe und Farbkontrast an',
19
+ text: 'Erhoehen Sie das Iterationsbudget, um feinere Grenzstrukturen sichtbar zu machen, und passen Sie dann Kontrast und Farbpalette an, um die Fluchtzeitbaender besser lesbar zu machen.',
20
+ },
21
+ ];
22
+
23
+ const faq = [
24
+ {
25
+ question: 'Was zeigt der Mandelbrot Mengen Rechner?',
26
+ answer: 'Er zeigt, welche komplexen Zahlen c die Rekursion z(n+1) = z(n)^2 + c beschraenkt halten, wenn man bei z = 0 beginnt. Punkte, die innerhalb des gewaehlten Iterationsbudgets nie entkommen, werden als Elemente der Menge eingefaerbt, waehrend aeussere Punkte danach gefaerbt werden, wie schnell ihre Umlaufbahn entkommt.',
27
+ },
28
+ {
29
+ question: 'Warum enthaelt der Mandelbrot Rand so viele Details?',
30
+ answer: 'Der Rand trennt stabile und entkommende Umlaufbahnen. Schon winzige Koordinatenaenderungen in der Naehe dieses Randes koennen das Langzeitverhalten vollstaendig veraendern. Diese Empfindlichkeit erzeugt ineinander verschachtelte Knoten, Spiralen, Filamente und miniaturisierte Kopien, die auf vielen Vergroesserungsstufen erscheinen.',
31
+ },
32
+ {
33
+ question: 'Ist die Mandelbrot Menge wirklich selbstahnlich?',
34
+ answer: 'Sie ist nicht perfekt selbstahnlich im gleichen strengen Sinne wie ein Sierpinski Dreieck, aber sie ist reichhaltig quasi selbstahnlich. Kleine Kopien der gesamten Menge erscheinen ueberall in der Ebene, oft verzerrt und durch aufwaendige verzweigte Strukturen verbunden.',
35
+ },
36
+ {
37
+ question: 'Was steuert die Iterationsanzahl?',
38
+ answer: 'Die Iterationsanzahl bestimmt, wie lange der Rechner jeden Punkt testet, bevor er entscheidet, dass er wahrscheinlich zur Menge gehoert. Hoehere Werte legen tiefere Filamente und sauberere Minibrots frei, erfordern aber mehr Berechnung pro Pixel.',
39
+ },
40
+ {
41
+ question: 'Warum aendern sich die Farben ausserhalb des schwarzen Bereichs?',
42
+ answer: 'Die Farben aussen basieren auf der Fluchtzeit: Punkte, die schnell entkommen, erhalten andere Farben als Punkte, die viele Iterationen in der Naehe der Menge bleiben. Glaettende Farbgebung reduziert harte Baender und erleichtert die Untersuchung der Geometrie benachbarter Umlaufbahnen.',
43
+ },
44
+ ];
45
+
46
+ export const content: ToolLocaleContent = {
47
+ slug,
48
+ title,
49
+ description,
50
+ ui: {
51
+ title: 'Mandelbrot Fraktal Rechner',
52
+ canvasLabel: 'Interaktive Mandelbrot Mengen Leinwand',
53
+ presetsLabel: 'Mandelbrot Region Voreinstellungen',
54
+ presetFull: 'Gesamte Menge',
55
+ presetSeahorse: 'Seepferdchental',
56
+ presetSpiral: 'Spiral Minibrot',
57
+ centerPoint: 'Zentrum',
58
+ magnification: 'Vergroesserung',
59
+ visibleWindow: 'Sichtbarer Ausschnitt',
60
+ renderBudget: 'Iterationen',
61
+ iterationsLabel: 'Iterationstiefe',
62
+ contrastLabel: 'Fluchtkontrast',
63
+ colorLabel: 'Farbfeld',
64
+ paletteEmber: 'Glutbaender',
65
+ paletteLagoon: 'Lagunen Plasma',
66
+ paletteInk: 'Tinten Spektrum',
67
+ },
68
+ seo: [
69
+ {
70
+ type: 'title',
71
+ text: 'Mandelbrot Mengen Rechner fur Fraktale, Fluchtzeit und Selbstahnlichkeit',
72
+ level: 2,
73
+ },
74
+ {
75
+ type: 'paragraph',
76
+ html: 'Dieser Mandelbrot Fraktal Rechner rendert die klassische Menge der komplexen Ebene, definiert durch die Iteration <strong>z(n+1) = z(n)^2 + c</strong>. Er ist fur die Erkundung konzipiert, nicht fur die passive Betrachtung. Jeder Klick zentriert die Ebene neu, jeder Zoom legt eine kleinere mathematische Nachbarschaft frei, und der Iterationsschieberegler lasst Sie entscheiden, wie tief der Rechner die Grenze testen soll, bevor er einen Punkt als stabil oder entweichend farbt.',
77
+ },
78
+ {
79
+ type: 'title',
80
+ text: 'Wie man das Mandelbrot Bild liest',
81
+ level: 3,
82
+ },
83
+ {
84
+ type: 'paragraph',
85
+ html: 'Die dunkle zentrale Form markiert Punkte, deren Umlaufbahnen innerhalb des aktuellen Iterationsbudgets beschrankt bleiben. Die farbige Aussenseite ist eine Fluchtzeitkarte. Ein Punkt, der nahe der Menge gefarbt ist, kann hunderte von Iterationen uberstehen, bevor sein Betrag den Fluchtradius uberschreitet, wahrend ein weit entfernter Punkt fast sofort entkommt. Die wissenschaftlich interessanteste Geometrie befindet sich normalerweise nicht innerhalb der gefullten Form, sondern entlang der Grenze, wo beschranktes und unbeschranktes Verhalten ineinandergreifen.',
86
+ },
87
+ {
88
+ type: 'table',
89
+ headers: ['Steuerung', 'Was sie andert', 'Wann erhohen'],
90
+ rows: [
91
+ ['<strong>Iterationstiefe</strong>', 'Wie viele Rekursionsschritte fur jeden Pixel getestet werden.', 'Hoehere Werte nach dem Zoomen in dunne Filamente oder miniaturisierte Kopien verwenden.'],
92
+ ['<strong>Fluchtkontrast</strong>', 'Wie stark glatte Fluchtwerte in sichtbare Baender getrennt werden.', 'Erhohen, wenn das Bild flach aussieht; senken, wenn die Farben zu hart sind.'],
93
+ ['<strong>Palette</strong>', 'Die Farbzuordnung, die auf aeussere Punkte angewendet wird.', 'Paletten wechseln, um Strukturen sichtbar zu machen, die von einem Farbfeld verdeckt werden koennten.'],
94
+ ],
95
+ },
96
+ {
97
+ type: 'title',
98
+ text: 'Selbstahnlichkeit und Minibrots',
99
+ level: 3,
100
+ },
101
+ {
102
+ type: 'paragraph',
103
+ html: 'Ein Grund, warum die Mandelbrot Menge so beruhmt ist, ist ihre Quasi Selbstahnlichkeit. Wenn Sie in Antennen, Spiralen und Taeler zoomen, stossen Sie immer wieder auf kleine mandelbrotahnliche Inseln, die oft als Minibrots bezeichnet werden. Diese Kopien sind nicht nur dekorativ. Ihre Anordnung spiegelt die Dynamik quadratischer Abbildungen wider, einschliesslich periodischer Knoten, Bifurkationsmuster und Regionen, in denen Umlaufbahnen ueber lange Zeitraeume gefangen bleiben, bevor sie entkommen.',
104
+ },
105
+ {
106
+ type: 'title',
107
+ text: 'Warum hoehere Iterationen bei tiefem Zoom wichtig sind',
108
+ level: 3,
109
+ },
110
+ {
111
+ type: 'paragraph',
112
+ html: 'Bei der Ansicht der gesamten Menge liefert eine moderate Iterationsgrenze ein erkennbares Bild. Bei staerkerer Vergroesserung brauchen viele Grenzpunkte jedoch viel laenger, um zu zeigen, ob sie entkommen. Wenn die Iterationsgrenze zu niedrig ist, koennen feine Strukturen faelschlich solide oder matschig aussehen. Die Erhoehung der Iterationsanzahl verbessert die Grenzklassifikation und ermoeglicht es dem Rechner, schmale Ranken, Spiralarme und Satellitenknoten mit mehr Sicherheit aufzuloesen.',
113
+ },
114
+ {
115
+ type: 'title',
116
+ text: 'Mathematische Bedeutung der komplexen Koordinaten',
117
+ level: 3,
118
+ },
119
+ {
120
+ type: 'paragraph',
121
+ html: 'Die Koordinatenanzeige zeigt das aktuelle Zentrum des Ansichtsfensters als komplexe Zahl c = a + bi. Die horizontale Achse ist der Realteil und die vertikale Achse der Imaginaerteil. Ein Klick auf die Leinwand waehlt eine neue komplexe Koordinate und vergroessert dann das sichtbare Fenster darum herum. Dies macht das Werkzeug nuetzlich, um zu lernen, wie visuelle Regionen des Fraktals mit genauen Positionen in der komplexen Ebene korrespondieren.',
122
+ },
123
+ ],
124
+ faq,
125
+ bibliography,
126
+ howTo,
127
+ schemas: [
128
+ {
129
+ '@context': 'https://schema.org',
130
+ '@type': 'SoftwareApplication',
131
+ name: title,
132
+ description,
133
+ applicationCategory: 'ScientificApplication',
134
+ operatingSystem: 'Any',
135
+ },
136
+ {
137
+ '@context': 'https://schema.org',
138
+ '@type': 'FAQPage',
139
+ mainEntity: faq.map((item) => ({
140
+ '@type': 'Question',
141
+ name: item.question,
142
+ acceptedAnswer: {
143
+ '@type': 'Answer',
144
+ text: item.answer,
145
+ },
146
+ })),
147
+ },
148
+ {
149
+ '@context': 'https://schema.org',
150
+ '@type': 'HowTo',
151
+ name: title,
152
+ step: howTo.map((step) => ({
153
+ '@type': 'HowToStep',
154
+ name: step.name,
155
+ text: step.text,
156
+ })),
157
+ },
158
+ ],
159
+ };