@jjlmoya/utils-science 1.19.0 → 1.21.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.
- package/package.json +2 -1
- package/src/category/i18n/de.ts +1 -1
- package/src/category/i18n/fr.ts +6 -6
- package/src/category/i18n/ru.ts +1 -1
- package/src/category/index.ts +3 -1
- package/src/category/seo.astro +2 -2
- package/src/entries.ts +5 -1
- package/src/index.ts +2 -0
- package/src/pages/[locale]/[slug].astro +32 -15
- package/src/tests/locale_completeness.test.ts +5 -22
- package/src/tests/no_en_dash.test.ts +70 -0
- package/src/tests/seo_length.test.ts +5 -3
- package/src/tests/shared-test-helpers.ts +56 -0
- package/src/tests/title_quality.test.ts +1 -1
- package/src/tests/tool_exports.test.ts +34 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/asteroid-impact/bibliography.astro +2 -2
- package/src/tool/asteroid-impact/bibliography.ts +24 -0
- package/src/tool/asteroid-impact/component.astro +16 -9
- package/src/tool/asteroid-impact/i18n/de.ts +4 -24
- package/src/tool/asteroid-impact/i18n/en.ts +4 -24
- package/src/tool/asteroid-impact/i18n/es.ts +4 -24
- package/src/tool/asteroid-impact/i18n/fr.ts +10 -30
- package/src/tool/asteroid-impact/i18n/id.ts +4 -24
- package/src/tool/asteroid-impact/i18n/it.ts +4 -24
- package/src/tool/asteroid-impact/i18n/ja.ts +4 -24
- package/src/tool/asteroid-impact/i18n/ko.ts +4 -24
- package/src/tool/asteroid-impact/i18n/nl.ts +4 -24
- package/src/tool/asteroid-impact/i18n/pl.ts +4 -24
- package/src/tool/asteroid-impact/i18n/pt.ts +4 -24
- package/src/tool/asteroid-impact/i18n/ru.ts +8 -28
- package/src/tool/asteroid-impact/i18n/sv.ts +4 -24
- package/src/tool/asteroid-impact/i18n/tr.ts +4 -24
- package/src/tool/asteroid-impact/i18n/zh.ts +4 -24
- package/src/tool/asteroid-impact/index.ts +1 -0
- package/src/tool/asteroid-impact/script.ts +13 -7
- package/src/tool/asteroid-impact/seo.astro +1 -1
- package/src/tool/cellular-renewal/bibliography.astro +2 -2
- package/src/tool/cellular-renewal/bibliography.ts +24 -0
- package/src/tool/cellular-renewal/i18n/de.ts +3 -24
- package/src/tool/cellular-renewal/i18n/en.ts +3 -24
- package/src/tool/cellular-renewal/i18n/es.ts +3 -24
- package/src/tool/cellular-renewal/i18n/fr.ts +16 -37
- package/src/tool/cellular-renewal/i18n/id.ts +3 -24
- package/src/tool/cellular-renewal/i18n/it.ts +3 -24
- package/src/tool/cellular-renewal/i18n/ja.ts +3 -24
- package/src/tool/cellular-renewal/i18n/ko.ts +3 -24
- package/src/tool/cellular-renewal/i18n/nl.ts +3 -24
- package/src/tool/cellular-renewal/i18n/pl.ts +3 -24
- package/src/tool/cellular-renewal/i18n/pt.ts +3 -24
- package/src/tool/cellular-renewal/i18n/ru.ts +20 -41
- package/src/tool/cellular-renewal/i18n/sv.ts +3 -24
- package/src/tool/cellular-renewal/i18n/tr.ts +3 -24
- package/src/tool/cellular-renewal/i18n/zh.ts +12 -33
- package/src/tool/cellular-renewal/index.ts +1 -0
- package/src/tool/cellular-renewal/seo.astro +2 -1
- package/src/tool/colony-counter/bibliography.astro +2 -2
- package/src/tool/colony-counter/bibliography.ts +12 -0
- package/src/tool/colony-counter/i18n/de.ts +3 -12
- package/src/tool/colony-counter/i18n/en.ts +3 -12
- package/src/tool/colony-counter/i18n/es.ts +3 -12
- package/src/tool/colony-counter/i18n/fr.ts +3 -12
- package/src/tool/colony-counter/i18n/id.ts +3 -12
- package/src/tool/colony-counter/i18n/it.ts +3 -12
- package/src/tool/colony-counter/i18n/ja.ts +3 -12
- package/src/tool/colony-counter/i18n/ko.ts +3 -12
- package/src/tool/colony-counter/i18n/nl.ts +3 -12
- package/src/tool/colony-counter/i18n/pl.ts +3 -12
- package/src/tool/colony-counter/i18n/pt.ts +3 -12
- package/src/tool/colony-counter/i18n/ru.ts +8 -17
- package/src/tool/colony-counter/i18n/sv.ts +3 -12
- package/src/tool/colony-counter/i18n/tr.ts +3 -12
- package/src/tool/colony-counter/i18n/zh.ts +5 -14
- package/src/tool/colony-counter/index.ts +1 -0
- package/src/tool/colony-counter/seo.astro +1 -1
- package/src/tool/cosmic-inflation/bibliography.astro +14 -0
- package/src/tool/cosmic-inflation/bibliography.ts +12 -0
- package/src/tool/cosmic-inflation/component.astro +270 -0
- package/src/tool/cosmic-inflation/cosmic-inflation-calculator.css +277 -0
- package/src/tool/cosmic-inflation/entry.ts +26 -0
- package/src/tool/cosmic-inflation/i18n/de.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/en.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/es.ts +168 -0
- package/src/tool/cosmic-inflation/i18n/fr.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/id.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/it.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ja.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ko.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/nl.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/pl.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/pt.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/ru.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/sv.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/tr.ts +188 -0
- package/src/tool/cosmic-inflation/i18n/zh.ts +188 -0
- package/src/tool/cosmic-inflation/index.ts +11 -0
- package/src/tool/cosmic-inflation/logic/CosmicInflationEngine.ts +21 -0
- package/src/tool/cosmic-inflation/seo.astro +15 -0
- package/src/tool/microwave-detector/bibliography.astro +2 -2
- package/src/tool/microwave-detector/bibliography.ts +16 -0
- package/src/tool/microwave-detector/component.astro +9 -7
- package/src/tool/microwave-detector/i18n/de.ts +3 -16
- package/src/tool/microwave-detector/i18n/en.ts +3 -16
- package/src/tool/microwave-detector/i18n/es.ts +3 -16
- package/src/tool/microwave-detector/i18n/fr.ts +7 -20
- package/src/tool/microwave-detector/i18n/id.ts +3 -16
- package/src/tool/microwave-detector/i18n/it.ts +3 -16
- package/src/tool/microwave-detector/i18n/ja.ts +3 -16
- package/src/tool/microwave-detector/i18n/ko.ts +3 -16
- package/src/tool/microwave-detector/i18n/nl.ts +3 -16
- package/src/tool/microwave-detector/i18n/pl.ts +3 -16
- package/src/tool/microwave-detector/i18n/pt.ts +3 -16
- package/src/tool/microwave-detector/i18n/ru.ts +21 -34
- package/src/tool/microwave-detector/i18n/sv.ts +3 -16
- package/src/tool/microwave-detector/i18n/tr.ts +3 -16
- package/src/tool/microwave-detector/i18n/zh.ts +13 -26
- package/src/tool/microwave-detector/index.ts +1 -0
- package/src/tool/microwave-detector/logic/MicrowaveEngine.ts +5 -1
- package/src/tool/microwave-detector/microwave-leak-detector.css +22 -25
- package/src/tool/microwave-detector/seo.astro +2 -1
- package/src/tool/simulation-probability/bibliography.astro +2 -2
- package/src/tool/simulation-probability/bibliography.ts +24 -0
- package/src/tool/simulation-probability/i18n/de.ts +3 -24
- package/src/tool/simulation-probability/i18n/en.ts +3 -24
- package/src/tool/simulation-probability/i18n/es.ts +3 -24
- package/src/tool/simulation-probability/i18n/fr.ts +8 -29
- package/src/tool/simulation-probability/i18n/id.ts +3 -24
- package/src/tool/simulation-probability/i18n/it.ts +3 -24
- package/src/tool/simulation-probability/i18n/ja.ts +3 -24
- package/src/tool/simulation-probability/i18n/ko.ts +3 -24
- package/src/tool/simulation-probability/i18n/nl.ts +3 -24
- package/src/tool/simulation-probability/i18n/pl.ts +3 -24
- package/src/tool/simulation-probability/i18n/pt.ts +3 -24
- package/src/tool/simulation-probability/i18n/ru.ts +10 -31
- package/src/tool/simulation-probability/i18n/sv.ts +3 -24
- package/src/tool/simulation-probability/i18n/tr.ts +3 -24
- package/src/tool/simulation-probability/i18n/zh.ts +7 -28
- package/src/tool/simulation-probability/index.ts +1 -0
- package/src/tool/simulation-probability/seo.astro +2 -1
- package/src/tool/temperature-timeline/bibliography.astro +14 -0
- package/src/tool/temperature-timeline/bibliography.ts +12 -0
- package/src/tool/temperature-timeline/component.astro +289 -0
- package/src/tool/temperature-timeline/entry.ts +26 -0
- package/src/tool/temperature-timeline/i18n/de.ts +213 -0
- package/src/tool/temperature-timeline/i18n/en.ts +213 -0
- package/src/tool/temperature-timeline/i18n/es.ts +178 -0
- package/src/tool/temperature-timeline/i18n/fr.ts +213 -0
- package/src/tool/temperature-timeline/i18n/id.ts +213 -0
- package/src/tool/temperature-timeline/i18n/it.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ja.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ko.ts +213 -0
- package/src/tool/temperature-timeline/i18n/nl.ts +213 -0
- package/src/tool/temperature-timeline/i18n/pl.ts +213 -0
- package/src/tool/temperature-timeline/i18n/pt.ts +213 -0
- package/src/tool/temperature-timeline/i18n/ru.ts +213 -0
- package/src/tool/temperature-timeline/i18n/sv.ts +213 -0
- package/src/tool/temperature-timeline/i18n/tr.ts +213 -0
- package/src/tool/temperature-timeline/i18n/zh.ts +213 -0
- package/src/tool/temperature-timeline/index.ts +11 -0
- package/src/tool/temperature-timeline/logic/TemperatureTimelineEngine.ts +58 -0
- package/src/tool/temperature-timeline/planet-temperature-timeline.css +158 -0
- package/src/tool/temperature-timeline/seo.astro +15 -0
- package/src/tools.ts +4 -0
- package/src/types.ts +1 -3
|
@@ -41,14 +41,13 @@ const faq = [
|
|
|
41
41
|
answer: 'Bilgisayarın geleceği hakkındaki inançlarınıza bağlıdır. Düşük değerler (100-1000) kaynak kısıtlamalarını varsayar. Yüksek değerler (milyonlar) pratik olarak sınırsız hesaplama gücü varsayar. Çoğu bilimsel tartışma 1000 ile 1 trilyon arasındaki değerleri kullanır.',
|
|
42
42
|
},
|
|
43
43
|
];
|
|
44
|
+
import { bibliography } from '../bibliography';
|
|
44
45
|
import type { ToolLocaleContent } from '../../../types';
|
|
45
46
|
|
|
46
47
|
export const content: ToolLocaleContent = {
|
|
47
48
|
slug,
|
|
48
49
|
title,
|
|
49
50
|
description,
|
|
50
|
-
faqTitle: 'Sıkça Sorulan Sorular',
|
|
51
|
-
bibliographyTitle: 'Kaynakça',
|
|
52
51
|
ui: {
|
|
53
52
|
copied: 'Kopyalandı',
|
|
54
53
|
noHistory: 'Geçmiş yok',
|
|
@@ -167,28 +166,7 @@ export const content: ToolLocaleContent = {
|
|
|
167
166
|
},
|
|
168
167
|
],
|
|
169
168
|
faq,
|
|
170
|
-
bibliography
|
|
171
|
-
{
|
|
172
|
-
name: 'Bostrom, N. (2003). Are You Living in a Computer Simulation? The Philosophical Quarterly, 53(211), 243-255.',
|
|
173
|
-
url: 'https://www.nickbostrom.com/sim.html',
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
name: 'Chalmers, D. J. (2005). The Matrix as Metaphysics. Science Fiction and Philosophy, 132-142.',
|
|
177
|
-
url: 'https://consc.net/papers/matrix.html',
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
name: 'Gefter, A. (2014). The Man Who Tried to Redeem the World with Logic: The Life and Work of Kurt Gödel. Nautilus Magazine.',
|
|
181
|
-
url: 'https://nautil.us/articles/the-man-who-tried-to-redeem-the-world-with-logic',
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
name: 'Tegmark, M. (2014). Our Mathematical Universe: My Quest for the Ultimate Nature of Reality. Knopf.',
|
|
185
|
-
url: 'https://space.mit.edu/home/tegmark/mathematical-universe.html',
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
name: 'Tyson, N. deG. (2014). Welcome to the Universe: An Astrophysical Tour. Princeton University Press.',
|
|
189
|
-
url: 'https://www.haydenplanetarium.org/',
|
|
190
|
-
},
|
|
191
|
-
],
|
|
169
|
+
bibliography,
|
|
192
170
|
howTo,
|
|
193
171
|
|
|
194
172
|
schemas: [
|
|
@@ -224,3 +202,4 @@ export const content: ToolLocaleContent = {
|
|
|
224
202
|
},
|
|
225
203
|
],
|
|
226
204
|
};
|
|
205
|
+
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bibliography } from '../bibliography';
|
|
1
2
|
import type { ToolLocaleContent } from '../../../types';
|
|
2
3
|
|
|
3
4
|
const slug = 'simulation-probability-calculator';
|
|
@@ -19,10 +20,10 @@ const faq = [
|
|
|
19
20
|
},
|
|
20
21
|
{
|
|
21
22
|
question: '是否有科学证据表明我们处于模拟中?',
|
|
22
|
-
answer: '
|
|
23
|
+
answer: '目前还没有结论性的证据。一些物理学家将量子力学中的异常现象(如量子化、纠缠)视为可能的"计算优化",但这些都是推测性的解释。',
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
|
-
question: '
|
|
26
|
+
question: '我应该给"N"(模拟规模)赋予什么值?',
|
|
26
27
|
answer: '这取决于您对计算机未来的信念。低值(100-1000)假设资源有限。高值(数百万)假设拥有几乎无限的计算能力。大多数科学讨论使用介于 1000 到 1 万亿之间的值。',
|
|
27
28
|
},
|
|
28
29
|
];
|
|
@@ -50,8 +51,6 @@ export const content: ToolLocaleContent = {
|
|
|
50
51
|
slug,
|
|
51
52
|
title,
|
|
52
53
|
description,
|
|
53
|
-
faqTitle: '常见问题',
|
|
54
|
-
bibliographyTitle: '参考文献',
|
|
55
54
|
ui: {
|
|
56
55
|
copied: '已复制',
|
|
57
56
|
noHistory: '暂无历史记录',
|
|
@@ -85,7 +84,7 @@ export const content: ToolLocaleContent = {
|
|
|
85
84
|
},
|
|
86
85
|
{
|
|
87
86
|
type: 'paragraph',
|
|
88
|
-
html: '我们的现实可能是一个人造结构,一个极其先进的计算机模拟,这个想法已经从科幻小说变成了严肃的哲学和科学辩论。2003 年,牛津大学哲学家尼克·波斯特罗姆发表了一篇题为 <em>"你是否生活在计算机模拟中?"</em>
|
|
87
|
+
html: '我们的现实可能是一个人造结构,一个极其先进的计算机模拟,这个想法已经从科幻小说变成了严肃的哲学和科学辩论。2003 年,牛津大学哲学家尼克·波斯特罗姆发表了一篇题为 <em>"你是否生活在计算机模拟中?"</em> 的文章,他在文中提出了一个挑战我们存在认知的"三解困境"论证。',
|
|
89
88
|
},
|
|
90
89
|
{
|
|
91
90
|
type: 'paragraph',
|
|
@@ -142,7 +141,7 @@ export const content: ToolLocaleContent = {
|
|
|
142
141
|
},
|
|
143
142
|
{
|
|
144
143
|
type: 'paragraph',
|
|
145
|
-
html: '
|
|
144
|
+
html: '从量子物理学到宇宙学,一些科学家正在寻找现实分辨率中的"缺陷"或限制。如果宇宙具有最小长度(普朗克长度)或看起来像代码优化(如量子纠缠)的行为,那么该假设在数字物理学领域就会获得支持者。',
|
|
146
145
|
},
|
|
147
146
|
{
|
|
148
147
|
type: 'title',
|
|
@@ -169,28 +168,7 @@ export const content: ToolLocaleContent = {
|
|
|
169
168
|
},
|
|
170
169
|
],
|
|
171
170
|
faq,
|
|
172
|
-
bibliography
|
|
173
|
-
{
|
|
174
|
-
name: 'Bostrom, N. (2003). Are You Living in a Computer Simulation? The Philosophical Quarterly, 53(211), 243-255.',
|
|
175
|
-
url: 'https://www.nickbostrom.com/sim.html',
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
name: 'Chalmers, D. J. (2005). The Matrix as Metaphysics. Science Fiction and Philosophy, 132-142.',
|
|
179
|
-
url: 'https://consc.net/papers/matrix.html',
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: 'Gefter, A. (2014). The Man Who Tried to Redeem the World with Logic: The Life and Work of Kurt Gödel. Nautilus Magazine.',
|
|
183
|
-
url: 'https://nautil.us/articles/the-man-who-tried-to-redeem-the-world-with-logic',
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
name: 'Tegmark, M. (2014). Our Mathematical Universe: My Quest for the Ultimate Nature of Reality. Knopf.',
|
|
187
|
-
url: 'https://space.mit.edu/home/tegmark/mathematical-universe.html',
|
|
188
|
-
},
|
|
189
|
-
{
|
|
190
|
-
name: 'Tyson, N. deG. (2014). Welcome to the Universe: An Astrophysical Tour. Princeton University Press.',
|
|
191
|
-
url: 'https://www.haydenplanetarium.org/',
|
|
192
|
-
},
|
|
193
|
-
],
|
|
171
|
+
bibliography,
|
|
194
172
|
howTo,
|
|
195
173
|
schemas: [
|
|
196
174
|
{
|
|
@@ -225,3 +203,4 @@ export const content: ToolLocaleContent = {
|
|
|
225
203
|
},
|
|
226
204
|
],
|
|
227
205
|
};
|
|
206
|
+
|
|
@@ -9,6 +9,7 @@ interface Props {
|
|
|
9
9
|
|
|
10
10
|
const { locale = 'es' } = Astro.props;
|
|
11
11
|
const content = await simulationProbability.i18n[locale]?.();
|
|
12
|
+
if (!content) return null;
|
|
12
13
|
---
|
|
13
14
|
|
|
14
|
-
{content && <SEORenderer content={{ sections: content.seo
|
|
15
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { temperatureTimeline } 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 temperatureTimeline.i18n[locale]?.();
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
{content && <SharedBibliography links={content.bibliography} />}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BibliographyEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const bibliography: BibliographyEntry[] = [
|
|
4
|
+
{
|
|
5
|
+
name: 'Global temperatures in the Cenozoic - Nature Geoscience',
|
|
6
|
+
url: 'https://www.nature.com/nature-index/topics/l4/paleoceanographic-dynamics-of-cenozoic-climate-systems',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
name: 'Phanerozoic climate history and temperature trends - Science',
|
|
10
|
+
url: 'https://www.science.org/doi/10.1126/science.adk3705',
|
|
11
|
+
},
|
|
12
|
+
];
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
import './planet-temperature-timeline.css';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
ui: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const { ui } = Astro.props;
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<div class="timeline-root" id="temperature-timeline-root" data-ui={JSON.stringify(ui)}>
|
|
12
|
+
<div class="timeline-canvas-container" id="timeline-canvas-area">
|
|
13
|
+
<canvas id="timeline-thermal-canvas"></canvas>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div class="timeline-ruler-container" id="timeline-ruler">
|
|
17
|
+
<div class="timeline-ruler-track"></div>
|
|
18
|
+
<div class="timeline-ruler-notch" data-index="5">
|
|
19
|
+
<span class="timeline-notch-label">ANT</span>
|
|
20
|
+
<div class="timeline-notch-line"></div>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="timeline-ruler-notch" data-index="4">
|
|
23
|
+
<span class="timeline-notch-label">CEN</span>
|
|
24
|
+
<div class="timeline-notch-line"></div>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="timeline-ruler-notch" data-index="3">
|
|
27
|
+
<span class="timeline-notch-label">MES</span>
|
|
28
|
+
<div class="timeline-notch-line"></div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="timeline-ruler-notch" data-index="2">
|
|
31
|
+
<span class="timeline-notch-label">PAL</span>
|
|
32
|
+
<div class="timeline-notch-line"></div>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="timeline-ruler-notch" data-index="1">
|
|
35
|
+
<span class="timeline-notch-label">PRO</span>
|
|
36
|
+
<div class="timeline-notch-line"></div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="timeline-ruler-notch" data-index="0">
|
|
39
|
+
<span class="timeline-notch-label">ARC</span>
|
|
40
|
+
<div class="timeline-notch-line"></div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="timeline-info-panel">
|
|
45
|
+
<div class="timeline-meta-header">
|
|
46
|
+
<span id="timeline-era-age" class="timeline-age">---</span>
|
|
47
|
+
<h3 id="timeline-era-title" class="timeline-era-name">---</h3>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="timeline-temp">
|
|
51
|
+
<span id="timeline-era-temp-val">---</span><span class="timeline-temp-unit">°C</span>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<script>
|
|
57
|
+
import { TemperatureTimelineEngine } from './logic/TemperatureTimelineEngine';
|
|
58
|
+
|
|
59
|
+
const root = document.getElementById('temperature-timeline-root');
|
|
60
|
+
if (root) {
|
|
61
|
+
const ageEl = document.getElementById('timeline-era-age');
|
|
62
|
+
const titleEl = document.getElementById('timeline-era-title');
|
|
63
|
+
const tempValEl = document.getElementById('timeline-era-temp-val');
|
|
64
|
+
const canvas = document.getElementById('timeline-thermal-canvas') as HTMLCanvasElement;
|
|
65
|
+
const canvasArea = document.getElementById('timeline-canvas-area');
|
|
66
|
+
const notches = document.querySelectorAll('.timeline-ruler-notch');
|
|
67
|
+
|
|
68
|
+
const uiData = JSON.parse(root.getAttribute('data-ui') || '{}');
|
|
69
|
+
const engine = new TemperatureTimelineEngine();
|
|
70
|
+
const epochs = engine.getEpochs().map(epoch => ({
|
|
71
|
+
...epoch,
|
|
72
|
+
name: uiData[`epoch_${epoch.id}_name`] || epoch.name,
|
|
73
|
+
ageRange: uiData[`epoch_${epoch.id}_age`] || epoch.ageRange,
|
|
74
|
+
description: uiData[`epoch_${epoch.id}_desc`] || epoch.description,
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
let currentEraIndex = 4;
|
|
78
|
+
let targetRadius = 130;
|
|
79
|
+
let currentRadius = 130;
|
|
80
|
+
let targetSpeed = 0.015;
|
|
81
|
+
let currentSpeed = 0.015;
|
|
82
|
+
const targetColor = { r: 56, g: 189, b: 248 };
|
|
83
|
+
const currentColor = { r: 56, g: 189, b: 248 };
|
|
84
|
+
let isCold = false;
|
|
85
|
+
|
|
86
|
+
function getThemeConfig(temp: number, isDark: boolean) {
|
|
87
|
+
if (temp >= 25) {
|
|
88
|
+
return { color: { r: 234, g: 88, b: 12 }, radius: 160, speed: 0.04, cold: false };
|
|
89
|
+
} else if (temp >= 20) {
|
|
90
|
+
return { color: { r: 249, g: 115, b: 22 }, radius: 140, speed: 0.03, cold: false };
|
|
91
|
+
} else if (temp >= 15) {
|
|
92
|
+
return { color: { r: 217, g: 119, b: 6 }, radius: 130, speed: 0.02, cold: false };
|
|
93
|
+
} else if (temp >= 13) {
|
|
94
|
+
return { color: isDark ? { r: 56, g: 189, b: 248 } : { r: 2, g: 132, b: 199 }, radius: 110, speed: 0.01, cold: true };
|
|
95
|
+
}
|
|
96
|
+
return { color: isDark ? { r: 224, g: 242, b: 254 } : { r: 15, g: 23, b: 42 }, radius: 90, speed: 0.005, cold: true };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function updateNotchStates(index: number, color: { r: number; g: number; b: number }) {
|
|
100
|
+
notches.forEach(n => {
|
|
101
|
+
const notchIdx = parseInt(n.getAttribute('data-index') || '0');
|
|
102
|
+
const label = n.querySelector('.timeline-notch-label') as HTMLElement;
|
|
103
|
+
if (notchIdx === index) {
|
|
104
|
+
n.classList.add('active');
|
|
105
|
+
if (label) {
|
|
106
|
+
label.style.textShadow = `0 0 12px rgba(${color.r}, ${color.g}, ${color.b}, 0.8)`;
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
n.classList.remove('active');
|
|
110
|
+
if (label) {
|
|
111
|
+
label.style.textShadow = 'none';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function selectEpoch(index: number) {
|
|
118
|
+
if (index < 0) index = 0;
|
|
119
|
+
if (index >= epochs.length) index = epochs.length - 1;
|
|
120
|
+
currentEraIndex = index;
|
|
121
|
+
|
|
122
|
+
const epoch = epochs[index];
|
|
123
|
+
if (!epoch) return;
|
|
124
|
+
|
|
125
|
+
if (ageEl) ageEl.textContent = epoch.ageRange;
|
|
126
|
+
if (titleEl) titleEl.textContent = epoch.name;
|
|
127
|
+
if (tempValEl) tempValEl.textContent = epoch.avgTemp.toFixed(1);
|
|
128
|
+
|
|
129
|
+
const isDark = document.body.classList.contains('theme-dark') || document.documentElement.classList.contains('theme-dark');
|
|
130
|
+
const config = getThemeConfig(epoch.avgTemp, isDark);
|
|
131
|
+
|
|
132
|
+
targetColor.r = config.color.r;
|
|
133
|
+
targetColor.g = config.color.g;
|
|
134
|
+
targetColor.b = config.color.b;
|
|
135
|
+
targetRadius = config.radius;
|
|
136
|
+
targetSpeed = config.speed;
|
|
137
|
+
isCold = config.cold;
|
|
138
|
+
|
|
139
|
+
updateNotchStates(index, targetColor);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let isDragging = false;
|
|
143
|
+
let startY = 0;
|
|
144
|
+
let startEraIndex = 4;
|
|
145
|
+
|
|
146
|
+
function handleStart(y: number) {
|
|
147
|
+
isDragging = true;
|
|
148
|
+
startY = y;
|
|
149
|
+
startEraIndex = currentEraIndex;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function handleMove(y: number) {
|
|
153
|
+
if (!isDragging) return;
|
|
154
|
+
const dy = y - startY;
|
|
155
|
+
const height = root?.clientHeight || 600;
|
|
156
|
+
const deltaEra = -Math.round((dy / height) * epochs.length * 1.8);
|
|
157
|
+
let nextIndex = startEraIndex + deltaEra;
|
|
158
|
+
if (nextIndex < 0) nextIndex = 0;
|
|
159
|
+
if (nextIndex >= epochs.length) nextIndex = epochs.length - 1;
|
|
160
|
+
if (nextIndex !== currentEraIndex) {
|
|
161
|
+
selectEpoch(nextIndex);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
canvasArea?.addEventListener('mousedown', (e: MouseEvent) => handleStart(e.clientY));
|
|
166
|
+
window.addEventListener('mousemove', (e: MouseEvent) => handleMove(e.clientY));
|
|
167
|
+
window.addEventListener('mouseup', () => { isDragging = false; });
|
|
168
|
+
|
|
169
|
+
canvasArea?.addEventListener('touchstart', (e: TouchEvent) => {
|
|
170
|
+
if (e.touches[0]) handleStart(e.touches[0].clientY);
|
|
171
|
+
});
|
|
172
|
+
window.addEventListener('touchmove', (e: TouchEvent) => {
|
|
173
|
+
if (e.touches[0]) handleMove(e.touches[0].clientY);
|
|
174
|
+
});
|
|
175
|
+
window.addEventListener('touchend', () => { isDragging = false; });
|
|
176
|
+
|
|
177
|
+
notches.forEach(notch => {
|
|
178
|
+
notch.addEventListener('click', () => {
|
|
179
|
+
const idx = parseInt(notch.getAttribute('data-index') || '0');
|
|
180
|
+
selectEpoch(idx);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const particles: { angle: number; speed: number; radiusOffset: number; size: number }[] = [];
|
|
185
|
+
for (let i = 0; i < 150; i++) {
|
|
186
|
+
particles.push({
|
|
187
|
+
angle: Math.random() * Math.PI * 2,
|
|
188
|
+
speed: 0.005 + Math.random() * 0.015,
|
|
189
|
+
radiusOffset: -40 + Math.random() * 80,
|
|
190
|
+
size: 1.5 + Math.random() * 2.5
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let phase = 0;
|
|
195
|
+
|
|
196
|
+
function renderParticles(ctx: CanvasRenderingContext2D, cx: number, cy: number, colorString: string) {
|
|
197
|
+
particles.forEach(p => {
|
|
198
|
+
p.angle += p.speed * (currentSpeed * 50 + 0.5);
|
|
199
|
+
|
|
200
|
+
let warp = 0;
|
|
201
|
+
if (!isCold) {
|
|
202
|
+
warp = Math.sin(p.angle * 6 + phase) * 15;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const rad = currentRadius + p.radiusOffset + warp;
|
|
206
|
+
const px = cx + Math.cos(p.angle) * rad;
|
|
207
|
+
const py = cy + Math.sin(p.angle) * rad * 0.7;
|
|
208
|
+
|
|
209
|
+
ctx.beginPath();
|
|
210
|
+
ctx.fillStyle = colorString + `, ${0.15 + (1 - Math.abs(p.radiusOffset) / 80) * 0.65})`;
|
|
211
|
+
ctx.arc(px, py, p.size, 0, Math.PI * 2);
|
|
212
|
+
ctx.fill();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function renderAtmosphereCircles(ctx: CanvasRenderingContext2D, cx: number, cy: number, colorString: string) {
|
|
217
|
+
if (isCold) {
|
|
218
|
+
ctx.strokeStyle = colorString + ', 0.45)';
|
|
219
|
+
ctx.lineWidth = 1.5;
|
|
220
|
+
for (let i = 1; i < 4; i++) {
|
|
221
|
+
ctx.beginPath();
|
|
222
|
+
ctx.arc(cx, cy, currentRadius * (i / 4), 0, Math.PI * 2);
|
|
223
|
+
ctx.stroke();
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
ctx.strokeStyle = colorString + ', 0.25)';
|
|
227
|
+
ctx.lineWidth = 1;
|
|
228
|
+
ctx.beginPath();
|
|
229
|
+
ctx.arc(cx, cy, currentRadius + 30, 0, Math.PI * 2);
|
|
230
|
+
ctx.stroke();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function updateCurrentColor() {
|
|
235
|
+
currentColor.r += (targetColor.r - currentColor.r) * 0.08;
|
|
236
|
+
currentColor.g += (targetColor.g - currentColor.g) * 0.08;
|
|
237
|
+
currentColor.b += (targetColor.b - currentColor.b) * 0.08;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function animate() {
|
|
241
|
+
if (!canvas) return;
|
|
242
|
+
const ctx = canvas.getContext('2d');
|
|
243
|
+
if (!ctx) return;
|
|
244
|
+
|
|
245
|
+
const dpr = window.devicePixelRatio || 1;
|
|
246
|
+
canvas.width = canvas.clientWidth * dpr;
|
|
247
|
+
canvas.height = canvas.clientHeight * dpr;
|
|
248
|
+
ctx.scale(dpr, dpr);
|
|
249
|
+
|
|
250
|
+
const w = canvas.width / dpr;
|
|
251
|
+
const h = canvas.height / dpr;
|
|
252
|
+
|
|
253
|
+
ctx.clearRect(0, 0, w, h);
|
|
254
|
+
|
|
255
|
+
currentRadius += (targetRadius - currentRadius) * 0.08;
|
|
256
|
+
currentSpeed += (targetSpeed - currentSpeed) * 0.08;
|
|
257
|
+
updateCurrentColor();
|
|
258
|
+
|
|
259
|
+
phase += currentSpeed;
|
|
260
|
+
|
|
261
|
+
const cx = w / 2;
|
|
262
|
+
const cy = h / 2;
|
|
263
|
+
|
|
264
|
+
const colorString = `rgba(${Math.floor(currentColor.r)}, ${Math.floor(currentColor.g)}, ${Math.floor(currentColor.b)}`;
|
|
265
|
+
|
|
266
|
+
if (root) {
|
|
267
|
+
root.style.boxShadow = `0 20px 40px rgba(${currentColor.r}, ${currentColor.g}, ${currentColor.b}, 0.06)`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
renderParticles(ctx, cx, cy, colorString);
|
|
271
|
+
renderAtmosphereCircles(ctx, cx, cy, colorString);
|
|
272
|
+
|
|
273
|
+
ctx.beginPath();
|
|
274
|
+
ctx.strokeStyle = colorString + ', 0.8)';
|
|
275
|
+
ctx.lineWidth = 2.5;
|
|
276
|
+
ctx.arc(cx, cy, currentRadius, 0, Math.PI * 2);
|
|
277
|
+
ctx.stroke();
|
|
278
|
+
|
|
279
|
+
requestAnimationFrame(animate);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
selectEpoch(4);
|
|
283
|
+
animate();
|
|
284
|
+
|
|
285
|
+
window.addEventListener('resize', () => {
|
|
286
|
+
selectEpoch(currentEraIndex);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
</script>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ScienceToolEntry } from '../../types';
|
|
2
|
+
|
|
3
|
+
export const temperatureTimeline: ScienceToolEntry = {
|
|
4
|
+
id: 'planet-temperature-timeline',
|
|
5
|
+
icons: {
|
|
6
|
+
bg: 'mdi:weather-sunny',
|
|
7
|
+
fg: 'mdi:clock-outline',
|
|
8
|
+
},
|
|
9
|
+
i18n: {
|
|
10
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
11
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
12
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
13
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
14
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
15
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
16
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
17
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
18
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
19
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
20
|
+
pl: () => import('./i18n/pl').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
|
+
};
|