@jjlmoya/utils-science 1.32.0 → 1.33.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/planet-atmosphere-survival/bibliography.astro +14 -0
  8. package/src/tool/planet-atmosphere-survival/bibliography.ts +16 -0
  9. package/src/tool/planet-atmosphere-survival/component.astro +404 -0
  10. package/src/tool/planet-atmosphere-survival/entry.ts +26 -0
  11. package/src/tool/planet-atmosphere-survival/i18n/de.ts +255 -0
  12. package/src/tool/planet-atmosphere-survival/i18n/en.ts +255 -0
  13. package/src/tool/planet-atmosphere-survival/i18n/es.ts +255 -0
  14. package/src/tool/planet-atmosphere-survival/i18n/fr.ts +255 -0
  15. package/src/tool/planet-atmosphere-survival/i18n/id.ts +255 -0
  16. package/src/tool/planet-atmosphere-survival/i18n/it.ts +255 -0
  17. package/src/tool/planet-atmosphere-survival/i18n/ja.ts +255 -0
  18. package/src/tool/planet-atmosphere-survival/i18n/ko.ts +255 -0
  19. package/src/tool/planet-atmosphere-survival/i18n/nl.ts +255 -0
  20. package/src/tool/planet-atmosphere-survival/i18n/pl.ts +255 -0
  21. package/src/tool/planet-atmosphere-survival/i18n/pt.ts +255 -0
  22. package/src/tool/planet-atmosphere-survival/i18n/ru.ts +255 -0
  23. package/src/tool/planet-atmosphere-survival/i18n/sv.ts +255 -0
  24. package/src/tool/planet-atmosphere-survival/i18n/tr.ts +255 -0
  25. package/src/tool/planet-atmosphere-survival/i18n/zh.ts +255 -0
  26. package/src/tool/planet-atmosphere-survival/index.ts +11 -0
  27. package/src/tool/planet-atmosphere-survival/logic.ts +201 -0
  28. package/src/tool/planet-atmosphere-survival/planet-atmosphere-survival-calculator.css +494 -0
  29. package/src/tool/planet-atmosphere-survival/seo.astro +15 -0
  30. package/src/tools.ts +2 -0
@@ -0,0 +1,494 @@
1
+ .survival-console {
2
+ --survival-ink: #162023;
3
+ --survival-muted: #667578;
4
+ --survival-soft: #0fa;
5
+ --survival-panel: rgba(255, 255, 255, 0.72);
6
+ --survival-panel-strong: rgba(255, 255, 255, 0.86);
7
+ --survival-line: rgba(20, 43, 46, 0.09);
8
+ --survival-grid: transparent;
9
+ --survival-cyan: #00a994;
10
+ --survival-yellow: #cfaa45;
11
+ --survival-red: #d64258;
12
+ --survival-violet: #7368ff;
13
+ --survival-shadow: rgba(0, 0, 0, 0.02);
14
+
15
+ position: relative;
16
+ display: grid;
17
+ gap: clamp(0.9rem, 3vw, 1.5rem);
18
+ width: min(100%, 1180px);
19
+ padding: clamp(0.9rem, 2.4vw, 1.35rem);
20
+ overflow: hidden;
21
+ color: var(--survival-ink);
22
+ background: #fafbfc;
23
+ border: 1px solid rgba(20, 43, 46, 0.06);
24
+ border-radius: 18px;
25
+ box-shadow: 0 30px 60px var(--survival-shadow);
26
+ }
27
+
28
+ .theme-dark .survival-console {
29
+ --survival-ink: #eef7f1;
30
+ --survival-muted: #889a98;
31
+ --survival-panel: rgba(18, 31, 34, 0.88);
32
+ --survival-panel-strong: rgba(10, 21, 24, 0.94);
33
+ --survival-line: rgba(151, 255, 235, 0.12);
34
+ --survival-grid: rgba(133, 231, 217, 0.04);
35
+ --survival-cyan: #85e7d9;
36
+ --survival-shadow: rgba(0, 0, 0, 0.34);
37
+
38
+ background:
39
+ linear-gradient(90deg, rgba(133, 231, 217, 0.045) 1px, transparent 1px),
40
+ linear-gradient(0deg, rgba(133, 231, 217, 0.04) 1px, transparent 1px),
41
+ linear-gradient(135deg, #0b1518 0%, #101d20 48%, #151c1f 100%);
42
+ background-size: 18px 18px, 18px 18px, auto;
43
+ }
44
+
45
+ .survival-visor,
46
+ .survival-panel,
47
+ .survival-summary-card {
48
+ min-width: 0;
49
+ }
50
+
51
+ .survival-summary-card {
52
+ display: grid;
53
+ gap: 1.1rem;
54
+ padding: clamp(1rem, 2.5vw, 1.35rem);
55
+ border: 1px solid rgba(20, 43, 46, 0.055);
56
+ border-radius: 14px;
57
+ background: var(--survival-panel);
58
+ backdrop-filter: blur(20px);
59
+ box-shadow: 0 30px 60px rgba(0, 0, 0, 0.02);
60
+ }
61
+
62
+ .theme-dark .survival-summary-card {
63
+ border-color: rgba(133, 231, 217, 0.06);
64
+ }
65
+
66
+ .survival-summary-kicker,
67
+ .survival-summary-readouts span {
68
+ display: block;
69
+ color: var(--survival-muted);
70
+ font-size: 0.64rem;
71
+ font-weight: 850;
72
+ letter-spacing: 0;
73
+ text-transform: uppercase;
74
+ }
75
+
76
+ .survival-summary-card h2 {
77
+ margin: 0.18rem 0 0;
78
+ color: var(--survival-ink);
79
+ font-size: clamp(1.7rem, 4vw, 3.2rem);
80
+ font-weight: 860;
81
+ letter-spacing: 0;
82
+ line-height: 0.95;
83
+ }
84
+
85
+ .survival-summary-readouts {
86
+ display: grid;
87
+ grid-template-columns: repeat(3, minmax(0, 1fr));
88
+ gap: 0.75rem;
89
+ }
90
+
91
+ .survival-summary-readouts strong {
92
+ display: block;
93
+ margin-top: 0.22rem;
94
+ color: var(--survival-ink);
95
+ font-size: clamp(1rem, 2.2vw, 1.34rem);
96
+ line-height: 1;
97
+ overflow-wrap: anywhere;
98
+ }
99
+
100
+ .survival-visor {
101
+ display: grid;
102
+ gap: 1rem;
103
+ }
104
+
105
+ .survival-planet,
106
+ .survival-timeline,
107
+ .survival-panel {
108
+ border: 1px solid rgba(20, 43, 46, 0.055);
109
+ border-radius: 14px;
110
+ background:
111
+ linear-gradient(90deg, var(--survival-grid) 1px, transparent 1px),
112
+ linear-gradient(0deg, var(--survival-grid) 1px, transparent 1px),
113
+ var(--survival-panel);
114
+ background-size: 14px 14px, 14px 14px, auto;
115
+ backdrop-filter: blur(20px);
116
+ box-shadow: 0 30px 60px rgba(0, 0, 0, 0.02);
117
+ }
118
+
119
+ .theme-dark .survival-planet,
120
+ .theme-dark .survival-timeline,
121
+ .theme-dark .survival-panel {
122
+ border-color: rgba(133, 231, 217, 0.06);
123
+ }
124
+
125
+ .survival-planet {
126
+ position: relative;
127
+ display: grid;
128
+ min-height: 420px;
129
+ place-items: center;
130
+ box-shadow:
131
+ 0 30px 60px rgba(0, 0, 0, 0.02),
132
+ inset -80px -80px 140px rgba(217, 75, 96, 0.035);
133
+ }
134
+
135
+ .survival-particle-canvas {
136
+ position: absolute;
137
+ inset: 0;
138
+ width: 100%;
139
+ height: 100%;
140
+ opacity: 0.52;
141
+ }
142
+
143
+ .theme-dark .survival-particle-canvas {
144
+ opacity: 0.86;
145
+ }
146
+
147
+ .theme-dark .survival-planet {
148
+ box-shadow: inset -80px -80px 140px rgba(217, 75, 96, 0.08);
149
+ }
150
+
151
+ .survival-orbit {
152
+ position: relative;
153
+ z-index: 1;
154
+ width: min(100%, 580px);
155
+ height: auto;
156
+ overflow: visible;
157
+ }
158
+
159
+ .survival-shell {
160
+ fill: none;
161
+ stroke: var(--survival-line);
162
+ stroke-width: 1.2;
163
+ }
164
+
165
+ .survival-shell-outer {
166
+ stroke-dasharray: 4 12;
167
+ }
168
+
169
+ .survival-particles {
170
+ transform-origin: 230px 230px;
171
+ }
172
+
173
+ .survival-particle {
174
+ stroke: var(--survival-cyan);
175
+ stroke-linecap: round;
176
+ stroke-width: 1.5;
177
+ opacity: var(--particle-opacity);
178
+ transform-origin: 230px 230px;
179
+ animation: survival-particle-drift var(--particle-speed, 18s) linear infinite;
180
+ animation-delay: var(--particle-delay);
181
+ }
182
+
183
+ .survival-core {
184
+ fill: var(--survival-panel-strong);
185
+ stroke: rgba(20, 43, 46, 0.1);
186
+ }
187
+
188
+ .theme-dark .survival-core {
189
+ stroke: rgba(133, 231, 217, 0.12);
190
+ }
191
+
192
+ .survival-core-time,
193
+ .survival-core-label,
194
+ .survival-spoke-label,
195
+ .survival-timeline text {
196
+ fill: var(--survival-ink);
197
+ text-anchor: middle;
198
+ }
199
+
200
+ .survival-core-time {
201
+ font-size: 42px;
202
+ font-weight: 850;
203
+ }
204
+
205
+ .survival-core-label {
206
+ fill: var(--survival-muted);
207
+ font-size: 11px;
208
+ font-weight: 750;
209
+ text-transform: uppercase;
210
+ }
211
+
212
+ .survival-risk-ring {
213
+ display: none;
214
+ }
215
+
216
+ .survival-hazard-spoke {
217
+ stroke: var(--survival-red);
218
+ stroke-linecap: round;
219
+ stroke-width: 1.4;
220
+ opacity: 0.92;
221
+ filter: drop-shadow(0 0 5px rgba(217, 75, 96, 0.45));
222
+ }
223
+
224
+ .survival-hazard-node {
225
+ fill: var(--survival-red);
226
+ filter: drop-shadow(0 0 9px rgba(217, 75, 96, 0.58));
227
+ }
228
+
229
+ .survival-spoke-label {
230
+ fill: var(--survival-muted);
231
+ font-size: 10px;
232
+ font-weight: 820;
233
+ text-transform: uppercase;
234
+ }
235
+
236
+ .survival-timeline {
237
+ min-height: 142px;
238
+ padding: 0.3rem;
239
+ }
240
+
241
+ .survival-timeline svg {
242
+ width: 100%;
243
+ height: 150px;
244
+ }
245
+
246
+ .survival-timeline-grid {
247
+ fill: none;
248
+ stroke: var(--survival-line);
249
+ stroke-width: 1;
250
+ }
251
+
252
+ .survival-timeline-fill {
253
+ fill: rgba(217, 75, 96, 0.28);
254
+ }
255
+
256
+ .survival-timeline-cold {
257
+ fill: rgba(171, 218, 255, 0.42);
258
+ }
259
+
260
+ .survival-timeline-line {
261
+ fill: none;
262
+ stroke: var(--survival-red);
263
+ stroke-linecap: round;
264
+ stroke-linejoin: round;
265
+ stroke-width: 4;
266
+ }
267
+
268
+ .survival-timeline text {
269
+ fill: var(--survival-muted);
270
+ font-size: 10px;
271
+ text-anchor: middle;
272
+ }
273
+
274
+ .survival-axis-label {
275
+ font-weight: 760;
276
+ text-transform: uppercase;
277
+ }
278
+
279
+ .survival-axis-y {
280
+ text-anchor: start;
281
+ }
282
+
283
+ .survival-axis-x {
284
+ text-anchor: end;
285
+ }
286
+
287
+ .survival-panel {
288
+ position: relative;
289
+ display: grid;
290
+ align-content: start;
291
+ gap: 1.25rem;
292
+ padding: clamp(1rem, 3vw, 1.3rem);
293
+ }
294
+
295
+ .survival-panel-top {
296
+ display: grid;
297
+ gap: 0.8rem;
298
+ }
299
+
300
+ .survival-unit-toggle {
301
+ display: flex;
302
+ justify-self: end;
303
+ padding: 2px;
304
+ border: 1px solid rgba(20, 43, 46, 0.08);
305
+ border-radius: 20px;
306
+ background: rgba(255, 255, 255, 0.32);
307
+ }
308
+
309
+ .theme-dark .survival-unit-toggle {
310
+ border-color: rgba(255, 255, 255, 0.08);
311
+ background: rgba(255, 255, 255, 0.03);
312
+ }
313
+
314
+ .survival-unit-toggle button {
315
+ min-height: 28px;
316
+ padding: 4px 8px;
317
+ border: 0;
318
+ border-radius: 18px;
319
+ color: var(--survival-muted);
320
+ background: transparent;
321
+ font-size: 0.68rem;
322
+ font-weight: 850;
323
+ letter-spacing: 0;
324
+ text-transform: uppercase;
325
+ cursor: pointer;
326
+ transition: all 0.2s ease;
327
+ }
328
+
329
+ .survival-unit-toggle button:is(.is-active, .active) {
330
+ color: #000;
331
+ background: var(--survival-soft);
332
+ box-shadow: 0 0 18px rgba(133, 231, 217, 0.28);
333
+ }
334
+
335
+ .survival-field {
336
+ display: grid;
337
+ gap: 0.45rem;
338
+ }
339
+
340
+ .survival-field span,
341
+ .survival-metrics span {
342
+ color: var(--survival-muted);
343
+ font-size: 0.64rem;
344
+ font-weight: 850;
345
+ letter-spacing: 0;
346
+ text-transform: uppercase;
347
+ }
348
+
349
+ .survival-field output,
350
+ .survival-metrics strong {
351
+ display: block;
352
+ max-width: 100%;
353
+ overflow-wrap: anywhere;
354
+ color: var(--survival-ink);
355
+ font-size: 1.26rem;
356
+ font-weight: 750;
357
+ line-height: 1;
358
+ }
359
+
360
+ .survival-field select {
361
+ width: 100%;
362
+ min-height: 50px;
363
+ padding-right: 1.6rem;
364
+ border: 0;
365
+ appearance: none;
366
+ color: var(--survival-ink);
367
+ background-color: transparent;
368
+ background-image:
369
+ linear-gradient(45deg, transparent 50%, currentcolor 50%),
370
+ linear-gradient(135deg, currentcolor 50%, transparent 50%);
371
+ background-position:
372
+ calc(100% - 14px) 54%,
373
+ calc(100% - 8px) 54%;
374
+ background-repeat: no-repeat;
375
+ background-size: 6px 6px, 6px 6px;
376
+ font-size: 1.82rem;
377
+ font-weight: 850;
378
+ }
379
+
380
+ .survival-field select option {
381
+ color: #101d20;
382
+ }
383
+
384
+ .survival-note {
385
+ min-height: 4rem;
386
+ margin: 0;
387
+ color: #637174;
388
+ font-size: 0.9rem;
389
+ line-height: 1.45;
390
+ }
391
+
392
+ .theme-dark .survival-note {
393
+ color: #a6b7b4;
394
+ }
395
+
396
+ .survival-grid,
397
+ .survival-metrics {
398
+ display: grid;
399
+ gap: 1.05rem;
400
+ }
401
+
402
+ .survival-field input[type='range'] {
403
+ width: 100%;
404
+ height: 22px;
405
+ margin: 0;
406
+ appearance: none;
407
+ background: transparent;
408
+ }
409
+
410
+ .survival-field input[type='range']::-webkit-slider-runnable-track {
411
+ height: 3px;
412
+ background: linear-gradient(90deg, var(--survival-cyan), var(--survival-yellow), var(--survival-red));
413
+ }
414
+
415
+ .survival-field input[type='range']::-webkit-slider-thumb {
416
+ width: 15px;
417
+ height: 15px;
418
+ margin-top: -6px;
419
+ border: 2px solid #f8f9fa;
420
+ border-radius: 50%;
421
+ appearance: none;
422
+ background: var(--survival-violet);
423
+ box-shadow: 0 0 0 1px rgba(0, 169, 148, 0.32), 0 0 14px rgba(115, 104, 255, 0.28);
424
+ }
425
+
426
+ .theme-dark .survival-field input[type='range']::-webkit-slider-thumb {
427
+ border-color: #0d171a;
428
+ box-shadow: 0 0 0 1px rgba(133, 231, 217, 0.38), 0 0 16px rgba(115, 104, 255, 0.42);
429
+ }
430
+
431
+ .survival-field input[type='range']::-moz-range-track {
432
+ height: 3px;
433
+ background: linear-gradient(90deg, var(--survival-cyan), var(--survival-yellow), var(--survival-red));
434
+ }
435
+
436
+ .survival-field input[type='range']::-moz-range-thumb {
437
+ width: 15px;
438
+ height: 15px;
439
+ border: 2px solid #f8f9fa;
440
+ border-radius: 50%;
441
+ background: var(--survival-violet);
442
+ box-shadow: 0 0 0 1px rgba(0, 169, 148, 0.32), 0 0 14px rgba(115, 104, 255, 0.28);
443
+ }
444
+
445
+ .theme-dark .survival-field input[type='range']::-moz-range-thumb {
446
+ border-color: #0d171a;
447
+ box-shadow: 0 0 0 1px rgba(133, 231, 217, 0.38), 0 0 16px rgba(115, 104, 255, 0.42);
448
+ }
449
+
450
+ .survival-metrics {
451
+ grid-template-columns: repeat(2, minmax(0, 1fr));
452
+ padding-top: 0.45rem;
453
+ border-top: 1px solid var(--survival-line);
454
+ }
455
+
456
+ @media (min-width: 900px) {
457
+ .survival-console {
458
+ grid-template-columns: minmax(0, 1.38fr) minmax(315px, 0.78fr);
459
+ align-items: start;
460
+ }
461
+
462
+ .survival-summary-card {
463
+ grid-column: 1 / -1;
464
+ grid-template-columns: minmax(0, 1fr) minmax(360px, 0.62fr);
465
+ align-items: end;
466
+ }
467
+
468
+ .survival-planet {
469
+ min-height: 560px;
470
+ }
471
+
472
+ .survival-panel-top {
473
+ grid-template-columns: minmax(0, 1fr) auto;
474
+ align-items: start;
475
+ }
476
+
477
+ .survival-grid {
478
+ grid-template-columns: repeat(2, minmax(0, 1fr));
479
+ }
480
+ }
481
+
482
+ @keyframes survival-particle-drift {
483
+ 0% {
484
+ transform: rotate(0deg) translateX(0);
485
+ }
486
+
487
+ 50% {
488
+ transform: rotate(180deg) translateX(var(--particle-chaos, 0));
489
+ }
490
+
491
+ 100% {
492
+ transform: rotate(360deg) translateX(0);
493
+ }
494
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { planetAtmosphereSurvival } 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 planetAtmosphereSurvival.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
package/src/tools.ts CHANGED
@@ -15,6 +15,7 @@ import { ENTROPY_SECOND_LAW_TOOL } from './tool/entropy-second-law/index';
15
15
  import { PHASE_DIAGRAM_CRITICAL_POINTS_TOOL } from './tool/phase-diagram-critical-points/index';
16
16
  import { TWIN_PARADOX_VISUALIZER_TOOL } from './tool/twin-paradox-visualizer/index';
17
17
  import { MANDELBROT_FRACTAL_TOOL } from './tool/mandelbrot-fractal/index';
18
+ import { PLANET_ATMOSPHERE_SURVIVAL_TOOL } from './tool/planet-atmosphere-survival/index';
18
19
 
19
20
  export const ALL_TOOLS: ToolDefinition[] = [
20
21
  COLONY_COUNTER_TOOL,
@@ -32,4 +33,5 @@ export const ALL_TOOLS: ToolDefinition[] = [
32
33
  PHASE_DIAGRAM_CRITICAL_POINTS_TOOL,
33
34
  TWIN_PARADOX_VISUALIZER_TOOL,
34
35
  MANDELBROT_FRACTAL_TOOL,
36
+ PLANET_ATMOSPHERE_SURVIVAL_TOOL,
35
37
  ];