@jjlmoya/utils-science 1.27.0 → 1.29.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/entropy-second-law/bibliography.astro +14 -0
  8. package/src/tool/entropy-second-law/bibliography.ts +12 -0
  9. package/src/tool/entropy-second-law/component.astro +366 -0
  10. package/src/tool/entropy-second-law/entropy-second-law-simulator.css +445 -0
  11. package/src/tool/entropy-second-law/entry.ts +26 -0
  12. package/src/tool/entropy-second-law/i18n/de.ts +210 -0
  13. package/src/tool/entropy-second-law/i18n/en.ts +210 -0
  14. package/src/tool/entropy-second-law/i18n/es.ts +210 -0
  15. package/src/tool/entropy-second-law/i18n/fr.ts +210 -0
  16. package/src/tool/entropy-second-law/i18n/id.ts +210 -0
  17. package/src/tool/entropy-second-law/i18n/it.ts +210 -0
  18. package/src/tool/entropy-second-law/i18n/ja.ts +210 -0
  19. package/src/tool/entropy-second-law/i18n/ko.ts +210 -0
  20. package/src/tool/entropy-second-law/i18n/nl.ts +210 -0
  21. package/src/tool/entropy-second-law/i18n/pl.ts +210 -0
  22. package/src/tool/entropy-second-law/i18n/pt.ts +210 -0
  23. package/src/tool/entropy-second-law/i18n/ru.ts +210 -0
  24. package/src/tool/entropy-second-law/i18n/sv.ts +210 -0
  25. package/src/tool/entropy-second-law/i18n/tr.ts +210 -0
  26. package/src/tool/entropy-second-law/i18n/zh.ts +210 -0
  27. package/src/tool/entropy-second-law/index.ts +11 -0
  28. package/src/tool/entropy-second-law/logic.ts +208 -0
  29. package/src/tool/entropy-second-law/seo.astro +15 -0
  30. package/src/tool/phase-diagram-critical-points/bibliography.astro +14 -0
  31. package/src/tool/phase-diagram-critical-points/bibliography.ts +16 -0
  32. package/src/tool/phase-diagram-critical-points/component.astro +397 -0
  33. package/src/tool/phase-diagram-critical-points/entry.ts +26 -0
  34. package/src/tool/phase-diagram-critical-points/i18n/de.ts +179 -0
  35. package/src/tool/phase-diagram-critical-points/i18n/en.ts +181 -0
  36. package/src/tool/phase-diagram-critical-points/i18n/es.ts +179 -0
  37. package/src/tool/phase-diagram-critical-points/i18n/fr.ts +179 -0
  38. package/src/tool/phase-diagram-critical-points/i18n/id.ts +179 -0
  39. package/src/tool/phase-diagram-critical-points/i18n/it.ts +179 -0
  40. package/src/tool/phase-diagram-critical-points/i18n/ja.ts +179 -0
  41. package/src/tool/phase-diagram-critical-points/i18n/ko.ts +179 -0
  42. package/src/tool/phase-diagram-critical-points/i18n/nl.ts +179 -0
  43. package/src/tool/phase-diagram-critical-points/i18n/pl.ts +179 -0
  44. package/src/tool/phase-diagram-critical-points/i18n/pt.ts +179 -0
  45. package/src/tool/phase-diagram-critical-points/i18n/ru.ts +179 -0
  46. package/src/tool/phase-diagram-critical-points/i18n/sv.ts +179 -0
  47. package/src/tool/phase-diagram-critical-points/i18n/tr.ts +179 -0
  48. package/src/tool/phase-diagram-critical-points/i18n/zh.ts +179 -0
  49. package/src/tool/phase-diagram-critical-points/index.ts +11 -0
  50. package/src/tool/phase-diagram-critical-points/logic.ts +179 -0
  51. package/src/tool/phase-diagram-critical-points/phase-diagram-critical-points-visualizer.css +542 -0
  52. package/src/tool/phase-diagram-critical-points/seo.astro +15 -0
  53. package/src/tools.ts +4 -0
@@ -0,0 +1,542 @@
1
+ .phase-lab {
2
+ --phase-ink: #182028;
3
+ --phase-muted: rgba(24, 32, 40, 0.62);
4
+ --phase-panel: rgba(255, 255, 255, 0.72);
5
+ --phase-line: rgba(24, 32, 40, 0.12);
6
+ --phase-hairline: rgba(24, 32, 40, 0.09);
7
+ --phase-label: #5f6b70;
8
+ --phase-track: rgba(24, 32, 40, 0.25);
9
+ --phase-solid: #8ea3b0;
10
+ --phase-liquid: #2e8bc0;
11
+ --phase-gas: #e3b341;
12
+ --phase-super: #36b18f;
13
+ --phase-critical: #e65355;
14
+
15
+ display: grid;
16
+ gap: 1rem;
17
+ width: min(100%, 1180px);
18
+ padding: clamp(1rem, 3vw, 1.7rem);
19
+ color: var(--phase-ink);
20
+ background:
21
+ linear-gradient(135deg, rgba(227, 179, 65, 0.18), transparent 32%),
22
+ linear-gradient(225deg, rgba(54, 177, 143, 0.18), transparent 34%),
23
+ #eef3f1;
24
+ border: 1px solid rgba(24, 32, 40, 0.08);
25
+ border-radius: 8px;
26
+ box-shadow: 0 28px 70px rgba(32, 58, 64, 0.16);
27
+ }
28
+
29
+ .theme-dark .phase-lab {
30
+ --phase-ink: #f7fbf7;
31
+ --phase-muted: rgba(247, 251, 247, 0.66);
32
+ --phase-panel: rgba(8, 16, 20, 0.74);
33
+ --phase-line: rgba(247, 251, 247, 0.13);
34
+ --phase-hairline: rgba(247, 251, 247, 0.11);
35
+ --phase-label: rgba(247, 251, 247, 0.58);
36
+ --phase-track: rgba(247, 251, 247, 0.24);
37
+
38
+ background:
39
+ linear-gradient(135deg, rgba(227, 179, 65, 0.18), transparent 32%),
40
+ linear-gradient(225deg, rgba(54, 177, 143, 0.22), transparent 34%),
41
+ #081014;
42
+ border-color: rgba(255, 255, 255, 0.08);
43
+ box-shadow: 0 28px 70px rgba(0, 0, 0, 0.38);
44
+ }
45
+
46
+ .phase-panel,
47
+ .phase-map-shell {
48
+ min-width: 0;
49
+ }
50
+
51
+ .phase-panel {
52
+ display: grid;
53
+ gap: 1.15rem;
54
+ align-content: start;
55
+ padding: 0.25rem 0.1rem;
56
+ background: transparent;
57
+ border: 0;
58
+ border-radius: 0;
59
+ }
60
+
61
+ .phase-field {
62
+ display: grid;
63
+ gap: 0.62rem;
64
+ padding-bottom: 1.05rem;
65
+ border-bottom: 1px solid var(--phase-hairline);
66
+ }
67
+
68
+ .phase-field span,
69
+ .phase-readout > span,
70
+ .phase-meter span,
71
+ .phase-coexistence-head span {
72
+ color: var(--phase-muted);
73
+ font-size: 0.72rem;
74
+ font-weight: 700;
75
+ letter-spacing: 0.08em;
76
+ text-transform: uppercase;
77
+ }
78
+
79
+ .phase-field output,
80
+ .phase-readout strong {
81
+ font-weight: 760;
82
+ line-height: 0.92;
83
+ }
84
+
85
+ .phase-field output {
86
+ font-size: clamp(1.65rem, 7vw, 3rem);
87
+ }
88
+
89
+ .phase-field select {
90
+ width: 100%;
91
+ min-height: 42px;
92
+ padding: 0 2.2rem 0 0.45rem;
93
+ color: var(--phase-ink);
94
+ appearance: none;
95
+ background:
96
+ linear-gradient(45deg, transparent 50%, currentcolor 50%) right 0.92rem center / 6px 6px no-repeat,
97
+ linear-gradient(135deg, currentcolor 50%, transparent 50%) right 0.58rem center / 6px 6px no-repeat;
98
+ border: 0;
99
+ border-bottom: 1px solid var(--phase-line);
100
+ border-radius: 0;
101
+ font-weight: 700;
102
+ }
103
+
104
+ .theme-dark .phase-field select {
105
+ color: var(--phase-ink);
106
+ background:
107
+ linear-gradient(45deg, transparent 50%, currentcolor 50%) right 0.92rem center / 6px 6px no-repeat,
108
+ linear-gradient(135deg, currentcolor 50%, transparent 50%) right 0.58rem center / 6px 6px no-repeat,
109
+ #081014;
110
+ }
111
+
112
+ .phase-field select option {
113
+ color: #182028;
114
+ background: #eef3f1;
115
+ }
116
+
117
+ .theme-dark .phase-field select option {
118
+ color: #f7fbf7;
119
+ background: #081014;
120
+ }
121
+
122
+ .phase-field input[type='range'] {
123
+ --fill: 50%;
124
+
125
+ width: 100%;
126
+ height: 24px;
127
+ margin: 0;
128
+ appearance: none;
129
+ background: transparent;
130
+ }
131
+
132
+ .phase-field input[type='range']::-webkit-slider-runnable-track {
133
+ height: 2px;
134
+ border-radius: 0;
135
+ background:
136
+ linear-gradient(90deg, var(--phase-ink) 0, var(--phase-ink) var(--fill), var(--phase-track) var(--fill), var(--phase-track) 100%);
137
+ }
138
+
139
+ .phase-field input[type='range']::-webkit-slider-thumb {
140
+ width: 13px;
141
+ height: 13px;
142
+ margin-top: -5.5px;
143
+ border: 2px solid var(--phase-ink);
144
+ border-radius: 50%;
145
+ appearance: none;
146
+ background: var(--phase-panel);
147
+ box-shadow: none;
148
+ cursor: grab;
149
+ }
150
+
151
+ .phase-field input[type='range']::-moz-range-track {
152
+ height: 2px;
153
+ border-radius: 0;
154
+ background: var(--phase-track);
155
+ }
156
+
157
+ .phase-field input[type='range']::-moz-range-progress {
158
+ height: 2px;
159
+ border-radius: 0;
160
+ background: var(--phase-ink);
161
+ }
162
+
163
+ .phase-field input[type='range']::-moz-range-thumb {
164
+ width: 13px;
165
+ height: 13px;
166
+ border: 2px solid var(--phase-ink);
167
+ border-radius: 50%;
168
+ background: var(--phase-panel);
169
+ box-shadow: none;
170
+ cursor: grab;
171
+ }
172
+
173
+ #phase-reset {
174
+ justify-self: start;
175
+ min-height: 32px;
176
+ padding: 0;
177
+ color: var(--phase-muted);
178
+ background: transparent;
179
+ border: 0;
180
+ border-radius: 0;
181
+ font-size: 0.8rem;
182
+ font-weight: 800;
183
+ letter-spacing: 0.08em;
184
+ text-transform: uppercase;
185
+ cursor: pointer;
186
+ opacity: 0.62;
187
+ transition: opacity 160ms ease;
188
+ }
189
+
190
+ #phase-reset:hover {
191
+ opacity: 1;
192
+ }
193
+
194
+ .theme-dark #phase-reset {
195
+ color: var(--phase-muted);
196
+ background: transparent;
197
+ }
198
+
199
+ .phase-map-shell {
200
+ padding: 0;
201
+ overflow: visible;
202
+ background: transparent;
203
+ border: 0;
204
+ border-radius: 0;
205
+ }
206
+
207
+ .phase-map-frame {
208
+ position: relative;
209
+ padding: 0 0 1.05rem 1.1rem;
210
+ }
211
+
212
+ .theme-dark .phase-map-shell {
213
+ background: transparent;
214
+ }
215
+
216
+ .phase-map {
217
+ display: block;
218
+ width: 100%;
219
+ height: auto;
220
+ min-height: clamp(390px, 52vw, 560px);
221
+ }
222
+
223
+ .phase-axis-label {
224
+ position: absolute;
225
+ color: var(--phase-muted);
226
+ font-size: 0.58rem;
227
+ font-weight: 800;
228
+ letter-spacing: 0.12em;
229
+ opacity: 0.58;
230
+ pointer-events: none;
231
+ text-transform: uppercase;
232
+ }
233
+
234
+ .phase-axis-label-y {
235
+ top: 50%;
236
+ left: 0;
237
+ transform: translate(-48%, -50%) rotate(-90deg);
238
+ transform-origin: center;
239
+ }
240
+
241
+ .phase-axis-label-x {
242
+ bottom: 0;
243
+ left: calc(1.1rem + 50%);
244
+ transform: translateX(-50%);
245
+ }
246
+
247
+ .phase-region {
248
+ stroke: none;
249
+ }
250
+
251
+ .phase-region-gas {
252
+ fill: rgba(227, 179, 65, 0.06);
253
+ }
254
+
255
+ .phase-region-solid {
256
+ fill: rgba(142, 163, 176, 0.08);
257
+ }
258
+
259
+ .phase-region-liquid {
260
+ fill: rgba(46, 139, 192, 0.07);
261
+ }
262
+
263
+ .phase-region-supercritical {
264
+ fill: rgba(54, 177, 143, 0.07);
265
+ }
266
+
267
+ .phase-grid {
268
+ fill: none;
269
+ stroke: var(--phase-hairline);
270
+ stroke-width: 1;
271
+ }
272
+
273
+ .phase-boundary {
274
+ fill: none;
275
+ stroke-linecap: round;
276
+ stroke-linejoin: round;
277
+ }
278
+
279
+ .phase-vapor {
280
+ stroke: var(--phase-critical);
281
+ stroke-width: 1.5;
282
+ }
283
+
284
+ .phase-melt {
285
+ stroke: var(--phase-ink);
286
+ stroke-width: 1.5;
287
+ stroke-dasharray: 8 10;
288
+ opacity: 0.62;
289
+ }
290
+
291
+ .phase-point circle {
292
+ fill: var(--phase-ink);
293
+ stroke: #fff;
294
+ stroke-width: 2;
295
+ }
296
+
297
+ .phase-critical circle {
298
+ fill: var(--phase-critical);
299
+ }
300
+
301
+ .phase-point text,
302
+ .phase-region-label {
303
+ fill: var(--phase-ink);
304
+ font-weight: 800;
305
+ }
306
+
307
+ .phase-point text {
308
+ font-size: 10px;
309
+ letter-spacing: 0.08em;
310
+ opacity: 0.5;
311
+ paint-order: stroke;
312
+ stroke: #eef3f1;
313
+ stroke-width: 4px;
314
+ stroke-linejoin: round;
315
+ text-transform: uppercase;
316
+ }
317
+
318
+ .theme-dark .phase-point text {
319
+ stroke: #081014;
320
+ }
321
+
322
+ .phase-region-label {
323
+ fill: var(--phase-label);
324
+ font-size: 10px;
325
+ letter-spacing: 0.14em;
326
+ opacity: 0.5;
327
+ paint-order: stroke;
328
+ stroke: rgba(238, 243, 241, 0.7);
329
+ stroke-width: 4px;
330
+ stroke-linejoin: round;
331
+ text-transform: uppercase;
332
+ }
333
+
334
+ .theme-dark .phase-region-label {
335
+ stroke: rgba(8, 16, 20, 0.74);
336
+ }
337
+
338
+ .phase-sample-marker {
339
+ transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
340
+ }
341
+
342
+ .phase-sample-trail {
343
+ fill: none;
344
+ stroke: var(--phase-critical);
345
+ transform-origin: center;
346
+ }
347
+
348
+ .phase-sample-trail-outer {
349
+ stroke-width: 1;
350
+ opacity: 0.26;
351
+ animation: phase-pulse 1800ms ease-in-out infinite;
352
+ }
353
+
354
+ .phase-sample-trail-inner {
355
+ stroke-width: 4;
356
+ stroke-dasharray: 7 10;
357
+ opacity: 0.36;
358
+ animation: phase-spin 5200ms linear infinite;
359
+ }
360
+
361
+ .phase-sample-dot {
362
+ fill: var(--phase-critical);
363
+ stroke: #fff;
364
+ stroke-width: 3;
365
+ }
366
+
367
+ .phase-sample-marker[data-phase='solid'] .phase-sample-dot {
368
+ fill: var(--phase-solid);
369
+ }
370
+
371
+ .phase-sample-marker[data-phase='liquid'] .phase-sample-dot {
372
+ fill: var(--phase-liquid);
373
+ }
374
+
375
+ .phase-sample-marker[data-phase='gas'] .phase-sample-dot {
376
+ fill: var(--phase-gas);
377
+ }
378
+
379
+ .phase-sample-marker[data-phase='supercritical'] .phase-sample-dot {
380
+ fill: var(--phase-super);
381
+ }
382
+
383
+ .phase-readout {
384
+ align-content: start;
385
+ padding-top: 1rem;
386
+ border-top: 1px solid var(--phase-hairline);
387
+ }
388
+
389
+ .phase-readout strong {
390
+ font-size: clamp(2.2rem, 10vw, 4.2rem);
391
+ }
392
+
393
+ .phase-readout p {
394
+ margin: 0;
395
+ color: var(--phase-muted);
396
+ line-height: 1.55;
397
+ }
398
+
399
+ .phase-meter {
400
+ display: grid;
401
+ gap: 0.55rem;
402
+ padding-top: 0.75rem;
403
+ border-top: 1px solid var(--phase-hairline);
404
+ }
405
+
406
+ .phase-meter div {
407
+ display: flex;
408
+ align-items: center;
409
+ justify-content: space-between;
410
+ gap: 1rem;
411
+ }
412
+
413
+ .phase-meter output {
414
+ font-weight: 800;
415
+ }
416
+
417
+ .phase-meter i {
418
+ --value: 0;
419
+
420
+ display: block;
421
+ height: 4px;
422
+ overflow: hidden;
423
+ background: rgba(24, 32, 40, 0.12);
424
+ border-radius: 0;
425
+ }
426
+
427
+ .phase-meter i::before {
428
+ display: block;
429
+ width: calc(var(--value) * 100%);
430
+ height: 100%;
431
+ background: linear-gradient(90deg, var(--phase-gas), var(--phase-critical), var(--phase-super));
432
+ content: "";
433
+ }
434
+
435
+ .phase-coexistence {
436
+ display: grid;
437
+ gap: 0.65rem;
438
+ padding-top: 0.8rem;
439
+ border-top: 1px solid var(--phase-hairline);
440
+ }
441
+
442
+ .phase-coexistence-head {
443
+ display: grid;
444
+ grid-template-columns: 1fr auto 1fr;
445
+ gap: 0.65rem;
446
+ align-items: center;
447
+ }
448
+
449
+ .phase-coexistence-head span,
450
+ .phase-coexistence-head output {
451
+ color: var(--phase-muted);
452
+ font-size: 0.62rem;
453
+ font-weight: 800;
454
+ letter-spacing: 0.08em;
455
+ text-transform: uppercase;
456
+ }
457
+
458
+ .phase-coexistence-head span:last-child {
459
+ text-align: right;
460
+ }
461
+
462
+ .phase-coexistence-head output {
463
+ color: var(--phase-ink);
464
+ }
465
+
466
+ .phase-coexistence-axis {
467
+ position: relative;
468
+ height: 24px;
469
+ }
470
+
471
+ .phase-coexistence-axis::before {
472
+ position: absolute;
473
+ top: 50%;
474
+ left: 0;
475
+ width: 100%;
476
+ height: 1px;
477
+ background: var(--phase-track);
478
+ content: "";
479
+ }
480
+
481
+ .phase-coexistence-axis::after {
482
+ position: absolute;
483
+ top: 50%;
484
+ right: 0;
485
+ width: calc(var(--coexistence, 0) * 100%);
486
+ height: 1px;
487
+ background: var(--phase-critical);
488
+ box-shadow: 0 0 14px rgba(230, 83, 85, 0.26);
489
+ content: "";
490
+ }
491
+
492
+ .phase-coexistence-axis i {
493
+ --value: 0;
494
+
495
+ position: absolute;
496
+ top: 50%;
497
+ left: calc(var(--value) * 100%);
498
+ width: 9px;
499
+ height: 9px;
500
+ background: var(--phase-critical);
501
+ border-radius: 50%;
502
+ transform: translate(-50%, -50%);
503
+ transition: left 260ms cubic-bezier(0.16, 1, 0.3, 1);
504
+ }
505
+
506
+ @keyframes phase-pulse {
507
+ 0%,
508
+ 100% {
509
+ opacity: 0.16;
510
+ transform: scale(0.9);
511
+ }
512
+
513
+ 50% {
514
+ opacity: 0.34;
515
+ transform: scale(1.12);
516
+ }
517
+ }
518
+
519
+ @keyframes phase-spin {
520
+ to {
521
+ transform: rotate(360deg);
522
+ }
523
+ }
524
+
525
+ @media (min-width: 900px) {
526
+ .phase-lab {
527
+ grid-template-columns: minmax(190px, 0.44fr) minmax(0, 1.9fr) minmax(230px, 0.54fr);
528
+ align-items: stretch;
529
+ }
530
+
531
+ .phase-controls {
532
+ padding-right: clamp(0rem, 2vw, 1rem);
533
+ border-right: 1px solid var(--phase-hairline);
534
+ }
535
+
536
+ .phase-readout {
537
+ padding-top: 0.25rem;
538
+ padding-left: clamp(0rem, 2vw, 1rem);
539
+ border-top: 0;
540
+ border-left: 1px solid var(--phase-hairline);
541
+ }
542
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { phaseDiagramCriticalPoints } 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 phaseDiagramCriticalPoints.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
@@ -11,6 +11,8 @@ import { LORENZ_ATTRACTOR_TOOL } from './tool/lorenz-attractor/index';
11
11
  import { STELLAR_HABITABILITY_ZONE_TOOL } from './tool/stellar-habitability-zone/index';
12
12
  import { RADIOACTIVE_DECAY_TOOL } from './tool/radioactive-decay/index';
13
13
  import { NATURAL_SELECTION_DRIFT_TOOL } from './tool/natural-selection-drift/index';
14
+ import { ENTROPY_SECOND_LAW_TOOL } from './tool/entropy-second-law/index';
15
+ import { PHASE_DIAGRAM_CRITICAL_POINTS_TOOL } from './tool/phase-diagram-critical-points/index';
14
16
 
15
17
  export const ALL_TOOLS: ToolDefinition[] = [
16
18
  COLONY_COUNTER_TOOL,
@@ -24,4 +26,6 @@ export const ALL_TOOLS: ToolDefinition[] = [
24
26
  STELLAR_HABITABILITY_ZONE_TOOL,
25
27
  RADIOACTIVE_DECAY_TOOL,
26
28
  NATURAL_SELECTION_DRIFT_TOOL,
29
+ ENTROPY_SECOND_LAW_TOOL,
30
+ PHASE_DIAGRAM_CRITICAL_POINTS_TOOL,
27
31
  ];