@jjlmoya/utils-science 1.43.0 → 1.44.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 (30) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/entries.ts +3 -1
  4. package/src/index.ts +1 -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/black-hole-event-horizon-simulator/bibliography.astro +14 -0
  8. package/src/tool/black-hole-event-horizon-simulator/bibliography.ts +16 -0
  9. package/src/tool/black-hole-event-horizon-simulator/black-hole-event-horizon-simulator.css +366 -0
  10. package/src/tool/black-hole-event-horizon-simulator/component.astro +302 -0
  11. package/src/tool/black-hole-event-horizon-simulator/entry.ts +29 -0
  12. package/src/tool/black-hole-event-horizon-simulator/i18n/de.ts +179 -0
  13. package/src/tool/black-hole-event-horizon-simulator/i18n/en.ts +259 -0
  14. package/src/tool/black-hole-event-horizon-simulator/i18n/es.ts +259 -0
  15. package/src/tool/black-hole-event-horizon-simulator/i18n/fr.ts +179 -0
  16. package/src/tool/black-hole-event-horizon-simulator/i18n/id.ts +259 -0
  17. package/src/tool/black-hole-event-horizon-simulator/i18n/it.ts +179 -0
  18. package/src/tool/black-hole-event-horizon-simulator/i18n/ja.ts +179 -0
  19. package/src/tool/black-hole-event-horizon-simulator/i18n/ko.ts +259 -0
  20. package/src/tool/black-hole-event-horizon-simulator/i18n/nl.ts +179 -0
  21. package/src/tool/black-hole-event-horizon-simulator/i18n/pl.ts +259 -0
  22. package/src/tool/black-hole-event-horizon-simulator/i18n/pt.ts +179 -0
  23. package/src/tool/black-hole-event-horizon-simulator/i18n/ru.ts +259 -0
  24. package/src/tool/black-hole-event-horizon-simulator/i18n/sv.ts +179 -0
  25. package/src/tool/black-hole-event-horizon-simulator/i18n/tr.ts +179 -0
  26. package/src/tool/black-hole-event-horizon-simulator/i18n/zh.ts +179 -0
  27. package/src/tool/black-hole-event-horizon-simulator/index.ts +11 -0
  28. package/src/tool/black-hole-event-horizon-simulator/logic.ts +68 -0
  29. package/src/tool/black-hole-event-horizon-simulator/seo.astro +15 -0
  30. package/src/tools.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-science",
3
- "version": "1.43.0",
3
+ "version": "1.44.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -24,10 +24,11 @@ import { conwayLifeRuleLab } from '../tool/conway-life-rule-lab/index';
24
24
  import { crystalLatticeStructureFinder } from '../tool/crystal-lattice-structure-finder/index';
25
25
  import { fermiParadoxFilterLab } from '../tool/fermi-paradox-filter-lab/index';
26
26
  import { epidemicSirSimulator } from '../tool/epidemic-sir-simulator/index';
27
+ import { blackHoleEventHorizonSimulator } from '../tool/black-hole-event-horizon-simulator/index';
27
28
 
28
29
  export const scienceCategory: ScienceCategoryEntry = {
29
30
  icon: 'mdi:flask',
30
- tools: [colonyCounter, asteroidImpact, microwaveDetector, simulationProbability, cellularRenewal, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, doubleSlitDecoherence, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal, planetAtmosphereSurvival, threeBodyProblem, rocheLimitSatelliteDisruption, dysonSphereEnergyCapture, globalAlbedoSnowballSimulator, conwayLifeRuleLab, crystalLatticeStructureFinder, fermiParadoxFilterLab, epidemicSirSimulator],
31
+ tools: [colonyCounter, asteroidImpact, microwaveDetector, simulationProbability, cellularRenewal, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, doubleSlitDecoherence, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal, planetAtmosphereSurvival, threeBodyProblem, rocheLimitSatelliteDisruption, dysonSphereEnergyCapture, globalAlbedoSnowballSimulator, conwayLifeRuleLab, crystalLatticeStructureFinder, fermiParadoxFilterLab, epidemicSirSimulator, blackHoleEventHorizonSimulator],
31
32
  i18n: {
32
33
  es: () => import('./i18n/es').then((m) => m.content),
33
34
  en: () => import('./i18n/en').then((m) => m.content),
package/src/entries.ts CHANGED
@@ -24,6 +24,7 @@ export { conwayLifeRuleLab } from './tool/conway-life-rule-lab/entry';
24
24
  export { crystalLatticeStructureFinder } from './tool/crystal-lattice-structure-finder/entry';
25
25
  export { fermiParadoxFilterLab } from './tool/fermi-paradox-filter-lab/entry';
26
26
  export { epidemicSirSimulator } from './tool/epidemic-sir-simulator/entry';
27
+ export { blackHoleEventHorizonSimulator } from './tool/black-hole-event-horizon-simulator/entry';
27
28
  export { scienceCategory } from './category';
28
29
  import { asteroidImpact } from './tool/asteroid-impact/entry';
29
30
  import { cellularRenewal } from './tool/cellular-renewal/entry';
@@ -50,4 +51,5 @@ import { conwayLifeRuleLab } from './tool/conway-life-rule-lab/entry';
50
51
  import { crystalLatticeStructureFinder } from './tool/crystal-lattice-structure-finder/entry';
51
52
  import { fermiParadoxFilterLab } from './tool/fermi-paradox-filter-lab/entry';
52
53
  import { epidemicSirSimulator } from './tool/epidemic-sir-simulator/entry';
53
- export const ALL_ENTRIES = [asteroidImpact, cellularRenewal, colonyCounter, microwaveDetector, simulationProbability, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, doubleSlitDecoherence, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal, planetAtmosphereSurvival, threeBodyProblem, rocheLimitSatelliteDisruption, dysonSphereEnergyCapture, globalAlbedoSnowballSimulator, conwayLifeRuleLab, crystalLatticeStructureFinder, fermiParadoxFilterLab, epidemicSirSimulator];
54
+ import { blackHoleEventHorizonSimulator } from './tool/black-hole-event-horizon-simulator/entry';
55
+ export const ALL_ENTRIES = [asteroidImpact, cellularRenewal, colonyCounter, microwaveDetector, simulationProbability, cosmicInflation, temperatureTimeline, lorenzAttractor, stellarHabitabilityZone, radioactiveDecay, naturalSelectionDrift, entropySecondLaw, doubleSlitDecoherence, phaseDiagramCriticalPoints, twinParadoxVisualizer, mandelbrotFractal, planetAtmosphereSurvival, threeBodyProblem, rocheLimitSatelliteDisruption, dysonSphereEnergyCapture, globalAlbedoSnowballSimulator, conwayLifeRuleLab, crystalLatticeStructureFinder, fermiParadoxFilterLab, epidemicSirSimulator, blackHoleEventHorizonSimulator];
package/src/index.ts CHANGED
@@ -25,6 +25,7 @@ export { CONWAY_LIFE_RULE_LAB_TOOL } from './tool/conway-life-rule-lab/index';
25
25
  export { CRYSTAL_LATTICE_STRUCTURE_FINDER_TOOL } from './tool/crystal-lattice-structure-finder/index';
26
26
  export { FERMI_PARADOX_FILTER_LAB_TOOL } from './tool/fermi-paradox-filter-lab/index';
27
27
  export { EPIDEMIC_SIR_SIMULATOR_TOOL } from './tool/epidemic-sir-simulator/index';
28
+ export { BLACK_HOLE_EVENT_HORIZON_SIMULATOR_TOOL } from './tool/black-hole-event-horizon-simulator/index';
28
29
 
29
30
  export type {
30
31
  KnownLocale,
@@ -18,7 +18,7 @@ describe('Locale Completeness Validation', () => {
18
18
  });
19
19
  });
20
20
 
21
- it('all 25 tools registered', () => {
22
- expect(ALL_TOOLS.length).toBe(25);
21
+ it('all 26 tools registered', () => {
22
+ expect(ALL_TOOLS.length).toBe(26);
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 25 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(25);
7
+ it('should have 26 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(26);
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 { blackHoleEventHorizonSimulator } 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 blackHoleEventHorizonSimulator.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: 'Event Horizon Telescope Collaboration, First M87 Event Horizon Telescope Results',
6
+ url: 'https://ui.adsabs.harvard.edu/abs/2019ApJ...875L...1E',
7
+ },
8
+ {
9
+ name: 'NASA, Black Holes',
10
+ url: 'https://science.nasa.gov/universe/black-holes/',
11
+ },
12
+ {
13
+ name: 'The Foundation of the General Theory of Relativity',
14
+ url: 'https://ia801808.us.archive.org/3/items/the-foundation-of-the-general-theory-of-relativity/The%20Foundation%20of%20the%20General%20Theory%20of%20Relativity.pdf',
15
+ }
16
+ ];
@@ -0,0 +1,366 @@
1
+ .bh-lab {
2
+ --bh-ink: #f6f2e8;
3
+ --bh-muted: #a8b2c3;
4
+ --bh-panel: rgba(12, 15, 24, 0.72);
5
+ --bh-line: rgba(255, 255, 255, 0.16);
6
+ --bh-blue: #4dd7ff;
7
+ --bh-gold: #ffe27a;
8
+ --bh-red: #ff4d6d;
9
+ --bh-warp: 0.58;
10
+
11
+ gap: 18px;
12
+ width: min(100%, 1180px);
13
+ margin-inline: auto;
14
+ color: var(--bh-ink);
15
+ }
16
+
17
+ .bh-card {
18
+ display: grid;
19
+ gap: 0;
20
+ overflow: hidden;
21
+ border-radius: 8px;
22
+ background:
23
+ radial-gradient(circle at 50% 42%, rgba(255, 226, 122, calc(0.05 + var(--bh-warp) * 0.11)), transparent 19rem),
24
+ linear-gradient(145deg, #080a11 0%, #121a27 52%, #080910 100%);
25
+ box-shadow: 0 30px 90px rgba(0, 0, 0, 0.34);
26
+ }
27
+
28
+ .bh-stage {
29
+ position: relative;
30
+ min-width: 0;
31
+ }
32
+
33
+ .bh-visual {
34
+ position: relative;
35
+ min-height: 390px;
36
+ }
37
+
38
+ .bh-svg {
39
+ display: block;
40
+ width: 100%;
41
+ height: auto;
42
+ min-height: 390px;
43
+ }
44
+
45
+ .bh-space {
46
+ fill: transparent;
47
+ }
48
+
49
+ .bh-stars circle {
50
+ fill: rgba(255, 255, 255, 0.8);
51
+ opacity: calc(0.16 + var(--bh-warp) * 0.58);
52
+ transform-origin: 380px 310px;
53
+ }
54
+
55
+ .bh-disk {
56
+ fill: none;
57
+ stroke: url("#bh-disk");
58
+ stroke-linecap: round;
59
+ transform-origin: 380px 314px;
60
+ }
61
+
62
+ .bh-disk-back {
63
+ opacity: 0.5;
64
+ stroke-width: 17;
65
+ filter: url("#bh-blur");
66
+ }
67
+
68
+ .bh-disk-front {
69
+ opacity: 0.88;
70
+ stroke-width: 8;
71
+ stroke-dasharray: 520 160;
72
+ animation: bh-flow 6s linear infinite;
73
+ }
74
+
75
+ .bh-horizon {
76
+ fill: url("#bh-core-glow");
77
+ stroke: rgba(255, 255, 255, 0.08);
78
+ stroke-width: 2;
79
+ }
80
+
81
+ .bh-horizon-glow {
82
+ fill: rgba(0, 0, 0, 0.2);
83
+ stroke: rgba(255, 210, 102, 0.24);
84
+ stroke-width: 16;
85
+ filter: url("#bh-blur");
86
+ }
87
+
88
+ .bh-photon,
89
+ .bh-isco {
90
+ fill: none;
91
+ stroke-width: 2;
92
+ transform-origin: 380px 310px;
93
+ }
94
+
95
+ .bh-photon {
96
+ stroke: rgba(77, 215, 255, 0.52);
97
+ stroke-dasharray: 5 9;
98
+ animation: bh-spin 12s linear infinite;
99
+ }
100
+
101
+ .bh-isco {
102
+ stroke: rgba(255, 255, 255, 0.22);
103
+ stroke-dasharray: 2 14;
104
+ animation: bh-spin 20s linear infinite reverse;
105
+ }
106
+
107
+ .bh-probe circle {
108
+ fill: #fff;
109
+ filter: drop-shadow(0 0 14px rgba(77, 215, 255, 0.9));
110
+ }
111
+
112
+ .bh-probe path {
113
+ fill: var(--bh-blue);
114
+ }
115
+
116
+ .bh-label {
117
+ color: #dbe7ff;
118
+ font-size: 0.78rem;
119
+ font-weight: 800;
120
+ letter-spacing: 0.04em;
121
+ text-transform: uppercase;
122
+ }
123
+
124
+ .bh-label line {
125
+ stroke: rgba(255, 255, 255, 0.28);
126
+ stroke-width: 1;
127
+ }
128
+
129
+ .bh-label text {
130
+ fill: currentcolor;
131
+ }
132
+
133
+ .bh-readout {
134
+ display: grid;
135
+ gap: 7px;
136
+ padding: 0 18px 20px;
137
+ }
138
+
139
+ .bh-readout span {
140
+ color: var(--bh-blue);
141
+ font-size: 0.74rem;
142
+ font-weight: 900;
143
+ letter-spacing: 0.1em;
144
+ text-transform: uppercase;
145
+ }
146
+
147
+ .bh-readout strong {
148
+ font-size: clamp(2.3rem, 10vw, 4.8rem);
149
+ font-weight: 700;
150
+ line-height: 0.95;
151
+ }
152
+
153
+ .bh-readout p {
154
+ max-width: 62ch;
155
+ margin: 0;
156
+ color: var(--bh-muted);
157
+ font-size: 1rem;
158
+ line-height: 1.55;
159
+ }
160
+
161
+ .bh-controls {
162
+ display: grid;
163
+ gap: 20px;
164
+ min-width: 0;
165
+ padding: 0 18px 18px;
166
+ }
167
+
168
+ .bh-kpis,
169
+ .bh-orbit-panel {
170
+ display: grid;
171
+ grid-template-columns: repeat(2, minmax(0, 1fr));
172
+ gap: 10px;
173
+ }
174
+
175
+ .bh-kpis div,
176
+ .bh-orbit-panel div {
177
+ min-height: 96px;
178
+ border: 1px solid var(--bh-line);
179
+ border-radius: 8px;
180
+ padding: 13px;
181
+ background: var(--bh-panel);
182
+ }
183
+
184
+ .bh-kpis span,
185
+ .bh-orbit-panel span,
186
+ .bh-slider span {
187
+ display: block;
188
+ color: var(--bh-muted);
189
+ font-size: 0.82rem;
190
+ font-weight: 800;
191
+ line-height: 1.24;
192
+ }
193
+
194
+ .bh-kpis strong,
195
+ .bh-orbit-panel strong {
196
+ display: block;
197
+ margin-top: 10px;
198
+ color: #fff;
199
+ font-size: clamp(1.42rem, 7vw, 2.45rem);
200
+ font-weight: 700;
201
+ font-variant-numeric: lining-nums tabular-nums;
202
+ line-height: 1;
203
+ overflow-wrap: anywhere;
204
+ }
205
+
206
+ .bh-sliders {
207
+ display: grid;
208
+ gap: 22px;
209
+ padding: 8px 0 2px;
210
+ }
211
+
212
+ .bh-slider {
213
+ position: relative;
214
+ display: grid;
215
+ gap: 11px;
216
+ padding-bottom: 20px;
217
+ }
218
+
219
+ .bh-slider output {
220
+ position: absolute;
221
+ left: var(--value-x, 50%);
222
+ bottom: 0;
223
+ color: var(--bh-gold);
224
+ font-size: 0.82rem;
225
+ font-weight: 900;
226
+ font-variant-numeric: tabular-nums;
227
+ opacity: 0;
228
+ transform: translateX(-50%) translateY(3px);
229
+ transition: opacity 150ms ease, transform 150ms ease;
230
+ white-space: nowrap;
231
+ }
232
+
233
+ .bh-slider:hover output,
234
+ .bh-slider:focus-within output {
235
+ opacity: 1;
236
+ transform: translateX(-50%) translateY(0);
237
+ }
238
+
239
+ .bh-slider input {
240
+ width: 100%;
241
+ height: 32px;
242
+ appearance: none;
243
+ background: transparent;
244
+ cursor: pointer;
245
+ }
246
+
247
+ .bh-slider input::-webkit-slider-runnable-track {
248
+ height: 3px;
249
+ border-radius: 999px;
250
+ background: linear-gradient(90deg, var(--bh-blue), var(--bh-gold), var(--bh-red));
251
+ }
252
+
253
+ .bh-slider input::-moz-range-track {
254
+ height: 3px;
255
+ border-radius: 999px;
256
+ background: linear-gradient(90deg, var(--bh-blue), var(--bh-gold), var(--bh-red));
257
+ }
258
+
259
+ .bh-slider input::-webkit-slider-thumb {
260
+ width: 16px;
261
+ height: 16px;
262
+ margin-top: -6.5px;
263
+ border: 2px solid #10131d;
264
+ border-radius: 999px;
265
+ appearance: none;
266
+ background: #fff;
267
+ box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.12), 0 0 18px rgba(255, 226, 122, 0.58);
268
+ transition: box-shadow 140ms ease, transform 140ms ease;
269
+ }
270
+
271
+ .bh-slider input::-moz-range-thumb {
272
+ width: 16px;
273
+ height: 16px;
274
+ border: 2px solid #10131d;
275
+ border-radius: 999px;
276
+ background: #fff;
277
+ box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.12), 0 0 18px rgba(255, 226, 122, 0.58);
278
+ transition: box-shadow 140ms ease, transform 140ms ease;
279
+ }
280
+
281
+ .bh-slider input:hover::-webkit-slider-thumb,
282
+ .bh-slider input:focus-visible::-webkit-slider-thumb {
283
+ box-shadow: 0 0 0 9px rgba(255, 226, 122, 0.16), 0 0 24px rgba(255, 226, 122, 0.78);
284
+ transform: scale(1.25);
285
+ }
286
+
287
+ .bh-slider input:hover::-moz-range-thumb,
288
+ .bh-slider input:focus-visible::-moz-range-thumb {
289
+ box-shadow: 0 0 0 9px rgba(255, 226, 122, 0.16), 0 0 24px rgba(255, 226, 122, 0.78);
290
+ transform: scale(1.25);
291
+ }
292
+
293
+ @keyframes bh-flow {
294
+ to {
295
+ stroke-dashoffset: -680;
296
+ }
297
+ }
298
+
299
+ @keyframes bh-spin {
300
+ to {
301
+ transform: rotate(360deg);
302
+ }
303
+ }
304
+
305
+ @media (min-width: 820px) {
306
+ .bh-card {
307
+ grid-template-columns: minmax(0, 1.18fr) minmax(340px, 0.82fr);
308
+ align-items: stretch;
309
+ }
310
+
311
+ .bh-stage,
312
+ .bh-controls {
313
+ min-height: 650px;
314
+ }
315
+
316
+ .bh-readout {
317
+ position: absolute;
318
+ inset: auto 30px 28px;
319
+ padding: 0;
320
+ }
321
+
322
+ .bh-controls {
323
+ align-content: center;
324
+ padding: 24px;
325
+ border-left: 1px solid rgba(255, 255, 255, 0.08);
326
+ }
327
+
328
+ .bh-kpis {
329
+ grid-template-columns: repeat(2, minmax(0, 1fr));
330
+ }
331
+ }
332
+
333
+ .theme-light .bh-lab {
334
+ --bh-ink: #131721;
335
+ --bh-muted: #596475;
336
+ --bh-panel: rgba(255, 255, 255, 0.78);
337
+ --bh-line: rgba(19, 23, 33, 0.13);
338
+ }
339
+
340
+ .theme-light .bh-card {
341
+ background:
342
+ radial-gradient(circle at 50% 42%, rgba(255, 167, 61, calc(0.08 + var(--bh-warp) * 0.12)), transparent 19rem),
343
+ linear-gradient(145deg, #f7fbff 0%, #edf3f7 52%, #fff 100%);
344
+ box-shadow: 0 26px 76px rgba(28, 40, 58, 0.14);
345
+ }
346
+
347
+ .theme-light .bh-controls {
348
+ border-left-color: rgba(19, 23, 33, 0.1);
349
+ }
350
+
351
+ .theme-light .bh-stars circle {
352
+ fill: rgba(20, 31, 48, 0.46);
353
+ }
354
+
355
+ .theme-light .bh-label {
356
+ color: #334055;
357
+ }
358
+
359
+ .theme-light .bh-label line {
360
+ stroke: rgba(19, 23, 33, 0.24);
361
+ }
362
+
363
+ .theme-light .bh-kpis strong,
364
+ .theme-light .bh-orbit-panel strong {
365
+ color: #111827;
366
+ }