@jjlmoya/utils-science 1.26.0 → 1.27.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 (33) 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/natural-selection-drift/bibliography.astro +14 -0
  8. package/src/tool/natural-selection-drift/bibliography.ts +16 -0
  9. package/src/tool/natural-selection-drift/component.astro +104 -0
  10. package/src/tool/natural-selection-drift/entry.ts +29 -0
  11. package/src/tool/natural-selection-drift/i18n/de.ts +65 -0
  12. package/src/tool/natural-selection-drift/i18n/en.ts +180 -0
  13. package/src/tool/natural-selection-drift/i18n/es.ts +64 -0
  14. package/src/tool/natural-selection-drift/i18n/fr.ts +204 -0
  15. package/src/tool/natural-selection-drift/i18n/id.ts +48 -0
  16. package/src/tool/natural-selection-drift/i18n/it.ts +203 -0
  17. package/src/tool/natural-selection-drift/i18n/ja.ts +48 -0
  18. package/src/tool/natural-selection-drift/i18n/ko.ts +48 -0
  19. package/src/tool/natural-selection-drift/i18n/nl.ts +53 -0
  20. package/src/tool/natural-selection-drift/i18n/pl.ts +48 -0
  21. package/src/tool/natural-selection-drift/i18n/pt.ts +52 -0
  22. package/src/tool/natural-selection-drift/i18n/ru.ts +48 -0
  23. package/src/tool/natural-selection-drift/i18n/sv.ts +48 -0
  24. package/src/tool/natural-selection-drift/i18n/tr.ts +48 -0
  25. package/src/tool/natural-selection-drift/i18n/zh.ts +48 -0
  26. package/src/tool/natural-selection-drift/index.ts +9 -0
  27. package/src/tool/natural-selection-drift/logic.ts +114 -0
  28. package/src/tool/natural-selection-drift/natural-selection-drift.css +429 -0
  29. package/src/tool/natural-selection-drift/render.ts +219 -0
  30. package/src/tool/natural-selection-drift/runtime.ts +89 -0
  31. package/src/tool/natural-selection-drift/seo.astro +15 -0
  32. package/src/tool/natural-selection-drift/simulation.ts +161 -0
  33. package/src/tools.ts +2 -1
@@ -0,0 +1,52 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { NaturalSelectionLocaleContent } from '../entry';
3
+
4
+ const slug = 'simulador-selecao-natural-deriva-genetica';
5
+ const title = 'Simulador de selecao natural e deriva genetica';
6
+ const description =
7
+ 'Veja em tempo real como pressao seletiva, mutacao, deriva e reproducao alteram as frequencias alelicas.';
8
+
9
+ const howTo = [
10
+ { name: 'Defina a populacao', text: 'Escolha uma populacao pequena ou grande para ver o efeito do tamanho amostral.' },
11
+ ];
12
+
13
+ const faq = [
14
+ { question: 'Qual e a diferenca entre selecao natural e deriva genetica?', answer: 'Selecao natural nao e aleatoria. Deriva genetica e uma mudanca aleatoria nas frequencias alelicas.' },
15
+ ];
16
+
17
+ export const content: NaturalSelectionLocaleContent = {
18
+ slug,
19
+ title,
20
+ description,
21
+ ui: {
22
+ population: 'Tamanho da populacao',
23
+ generations: 'Geracoes',
24
+ mutationRate: 'Taxa de mutacao',
25
+ selectionPressure: 'Pressao seletiva',
26
+ driftIntensity: 'Intensidade da deriva',
27
+ alleleCount: 'Alelos iniciais',
28
+ innovationRate: 'Taxa de inovacao',
29
+ run: 'Executar simulacao',
30
+ dominantTrait: 'Traço dominante',
31
+ fitness: 'Fitness final',
32
+ diversity: 'Diversidade genetica',
33
+ evolutionConsole: 'Console evolutivo',
34
+ populationLabel: 'Populacao',
35
+ aliveLabel: 'vivos',
36
+ alleleCountsLabel: 'Contagem de alelos',
37
+ alleleDefault: 'Alelo 1',
38
+ populationValueLabel: 'Populacao',
39
+ },
40
+ seo: [
41
+ { type: 'title', text: 'Selecao natural vs deriva genetica: entenda a evolucao com uma populacao viva', level: 2 },
42
+ { type: 'paragraph', html: 'Este simulador mostra a selecao e a deriva ao vivo, de forma clara e pratica.' },
43
+ ],
44
+ faq,
45
+ bibliography,
46
+ howTo,
47
+ schemas: [
48
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'EducationalApplication', operatingSystem: 'Any' },
49
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
50
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })) },
51
+ ],
52
+ };
@@ -0,0 +1,48 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { NaturalSelectionLocaleContent } from '../entry';
3
+
4
+ const slug = 'simulyator-estestvennogo-otbora-geneticheskogo-drejfa';
5
+ const title = 'Simulyator estestvennogo otbora i geneticheskogo drejfa';
6
+ const description =
7
+ 'V realnom vremeni nablyudajte, kak davlenie otbora, mutacii, drejf i razmnozhenie menyayut chastoty allelej.';
8
+
9
+ const faq = [
10
+ { question: 'V chem raznica mezhdu estestvennym otborom i geneticheskim drejfom?', answer: 'Estestvennyj otbor ne sluchaen. Poleznye priznaki stanyatsya chashche. Geneticheskij drejf - sluchajnoe izmenenie chastot allelej.' },
11
+ ];
12
+
13
+ export const content: NaturalSelectionLocaleContent = {
14
+ slug,
15
+ title,
16
+ description,
17
+ ui: {
18
+ population: 'Razmer populyacii',
19
+ generations: 'Pokoleniya',
20
+ mutationRate: 'Chastota mutacij',
21
+ selectionPressure: 'Davlenie otbora',
22
+ driftIntensity: 'Sila drejfa',
23
+ alleleCount: 'Nachalnye alleli',
24
+ innovationRate: 'Chastota innovacij',
25
+ run: 'Zapustit simulyaciyu',
26
+ dominantTrait: 'Dominiruyushij priznak',
27
+ fitness: 'Itogovyj fitness',
28
+ diversity: 'Geneticheskoe raznoobrazie',
29
+ evolutionConsole: 'Evolyucionnaya konsol',
30
+ populationLabel: 'Populyaciya',
31
+ aliveLabel: 'zhivyx',
32
+ alleleCountsLabel: 'Schetchik allelej',
33
+ alleleDefault: 'Allel 1',
34
+ populationValueLabel: 'Populyaciya',
35
+ },
36
+ seo: [
37
+ { type: 'title', text: 'Estestvennyj otbor vs geneticheskij drejf: ponyat evolyuciyu s zhivoj populyaciej', level: 2 },
38
+ { type: 'paragraph', html: 'Eta model pomogaet uvidet raznicu mezhdu otborom i drejfom cherez zhivuyu vizualizaciyu.' },
39
+ ],
40
+ faq,
41
+ bibliography,
42
+ howTo: [],
43
+ schemas: [
44
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'EducationalApplication', operatingSystem: 'Any' },
45
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
46
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: [] },
47
+ ],
48
+ };
@@ -0,0 +1,48 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { NaturalSelectionLocaleContent } from '../entry';
3
+
4
+ const slug = 'simulering-av-naturligt-urval-genetisk-drift';
5
+ const title = 'Simulering av naturligt urval och genetisk drift';
6
+ const description =
7
+ 'Se i realtid hur selektionstryck, mutation, drift och reproduktion andrar allelfrekvenser.';
8
+
9
+ const faq = [
10
+ { question: 'Vad ar skillnaden mellan naturligt urval och genetisk drift?', answer: 'Naturligt urval ar inte slumpmassigt. Genetisk drift ar en slumpmassig andring av allelfrekvenser.' },
11
+ ];
12
+
13
+ export const content: NaturalSelectionLocaleContent = {
14
+ slug,
15
+ title,
16
+ description,
17
+ ui: {
18
+ population: 'Populationsstorlek',
19
+ generations: 'Generationer',
20
+ mutationRate: 'Mutationshastighet',
21
+ selectionPressure: 'Selektionstryck',
22
+ driftIntensity: 'Driftintensitet',
23
+ alleleCount: 'Startalleler',
24
+ innovationRate: 'Innovationshastighet',
25
+ run: 'Starta simulering',
26
+ dominantTrait: 'Dominerande egenskap',
27
+ fitness: 'Slutlig fitness',
28
+ diversity: 'Genetisk variation',
29
+ evolutionConsole: 'Evolutionskonsol',
30
+ populationLabel: 'Population',
31
+ aliveLabel: 'levande',
32
+ alleleCountsLabel: 'Allelrakning',
33
+ alleleDefault: 'Allel 1',
34
+ populationValueLabel: 'Population',
35
+ },
36
+ seo: [
37
+ { type: 'title', text: 'Naturligt urval vs genetisk drift: forsta evolution med en levande population', level: 2 },
38
+ { type: 'paragraph', html: 'Denna simulator hjalper dig att se skillnaden mellan selektion och drift pa ett tydligt satt.' },
39
+ ],
40
+ faq,
41
+ bibliography,
42
+ howTo: [],
43
+ schemas: [
44
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'EducationalApplication', operatingSystem: 'Any' },
45
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
46
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: [] },
47
+ ],
48
+ };
@@ -0,0 +1,48 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { NaturalSelectionLocaleContent } from '../entry';
3
+
4
+ const slug = 'dogal-secilim-genetik-suruklenme-simulatoru';
5
+ const title = 'Dogal secilim ve genetik suruklenme simulatörü';
6
+ const description =
7
+ 'Secilim baskisi, mutasyon, suruklenme ve uremenin alel frekanslarini gercek zamanli nasil degistirdigini gorun.';
8
+
9
+ const faq = [
10
+ { question: 'Dogal secilim ile genetik suruklenme arasindaki fark nedir?', answer: 'Dogal secilim rastgele degildir. Genetik suruklenme alel frekanslarinda rastgele bir degisikliktir.' },
11
+ ];
12
+
13
+ export const content: NaturalSelectionLocaleContent = {
14
+ slug,
15
+ title,
16
+ description,
17
+ ui: {
18
+ population: 'Populasyon buyuklugu',
19
+ generations: 'Nesiller',
20
+ mutationRate: 'Mutasyon orani',
21
+ selectionPressure: 'Secilim baskisi',
22
+ driftIntensity: 'Suruklenme yogunlugu',
23
+ alleleCount: 'Baslangic allelleri',
24
+ innovationRate: 'Inovasyon orani',
25
+ run: 'Simulasyonu baslat',
26
+ dominantTrait: 'Baskin ozellik',
27
+ fitness: 'Nihai fitness',
28
+ diversity: 'Genetik cesitlilik',
29
+ evolutionConsole: 'Evrim konsolu',
30
+ populationLabel: 'Populasyon',
31
+ aliveLabel: 'canli',
32
+ alleleCountsLabel: 'Alel sayilari',
33
+ alleleDefault: 'Alel 1',
34
+ populationValueLabel: 'Populasyon',
35
+ },
36
+ seo: [
37
+ { type: 'title', text: 'Dogal secilim vs genetik suruklenme: canli populasyonla evrimi anlayin', level: 2 },
38
+ { type: 'paragraph', html: 'Bu simulatör dogal secilim ve genetik suruklenmeyi birlikte gosterir.' },
39
+ ],
40
+ faq,
41
+ bibliography,
42
+ howTo: [],
43
+ schemas: [
44
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'EducationalApplication', operatingSystem: 'Any' },
45
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
46
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: [] },
47
+ ],
48
+ };
@@ -0,0 +1,48 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { NaturalSelectionLocaleContent } from '../entry';
3
+
4
+ const slug = 'natural-selection-drift';
5
+ const title = '自然选择和遗传漂变模拟器';
6
+ const description =
7
+ '实时观察选择压力、突变、漂变和繁殖如何改变等位基因频率。';
8
+
9
+ const faq = [
10
+ { question: '自然选择和遗传漂变有什么区别?', answer: '自然选择不是随机的。遗传漂变是等位基因频率的随机变化。' },
11
+ ];
12
+
13
+ export const content: NaturalSelectionLocaleContent = {
14
+ slug,
15
+ title,
16
+ description,
17
+ ui: {
18
+ population: '种群规模',
19
+ generations: '世代',
20
+ mutationRate: '突变率',
21
+ selectionPressure: '选择压力',
22
+ driftIntensity: '漂变强度',
23
+ alleleCount: '初始等位基因',
24
+ innovationRate: '创新率',
25
+ run: '开始模拟',
26
+ dominantTrait: '优势性状',
27
+ fitness: '最终适应度',
28
+ diversity: '遗传多样性',
29
+ evolutionConsole: '进化控制台',
30
+ populationLabel: '种群',
31
+ aliveLabel: '存活',
32
+ alleleCountsLabel: '等位基因数量',
33
+ alleleDefault: '等位基因 1',
34
+ populationValueLabel: '种群',
35
+ },
36
+ seo: [
37
+ { type: 'title', text: '用动态种群理解自然选择和遗传漂变', level: 2 },
38
+ { type: 'paragraph', html: '这个模拟器帮助你把进化概念和实时变化联系起来。' },
39
+ ],
40
+ faq,
41
+ bibliography,
42
+ howTo: [],
43
+ schemas: [
44
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'EducationalApplication', operatingSystem: 'Any' },
45
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) },
46
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, step: [] },
47
+ ],
48
+ };
@@ -0,0 +1,9 @@
1
+ import { naturalSelectionDrift } from './entry';
2
+ import type { ToolDefinition } from '../../types';
3
+ export * from './entry';
4
+ export const NATURAL_SELECTION_DRIFT_TOOL: ToolDefinition = {
5
+ entry: naturalSelectionDrift,
6
+ Component: () => import('./component.astro'),
7
+ SEOComponent: () => import('./seo.astro'),
8
+ BibliographyComponent: () => import('./bibliography.astro'),
9
+ };
@@ -0,0 +1,114 @@
1
+ export type Habitat = 'forest' | 'desert' | 'island';
2
+ export type Trait = 'camouflage' | 'speed' | 'endurance';
3
+
4
+ export interface SimulationConfig {
5
+ population: number;
6
+ generations: number;
7
+ mutationRate: number;
8
+ selectionPressure: number;
9
+ driftIntensity: number;
10
+ alleleCount: number;
11
+ innovationRate: number;
12
+ seed?: number;
13
+ habitat: Habitat;
14
+ trait: Trait;
15
+ }
16
+
17
+ export interface GenerationPoint {
18
+ generation: number;
19
+ alleleA: number;
20
+ alleleB: number;
21
+ fitness: number;
22
+ }
23
+
24
+ function clamp01(value: number) {
25
+ return Math.max(0, Math.min(1, value));
26
+ }
27
+
28
+ function seededRandom(seed: number) {
29
+ let state = seed % 2147483647;
30
+ if (state <= 0) state += 2147483646;
31
+ return () => {
32
+ state = (state * 16807) % 2147483647;
33
+ return (state - 1) / 2147483646;
34
+ };
35
+ }
36
+
37
+ function habitatBias(habitat: Habitat, trait: Trait) {
38
+ if (habitat === 'forest' && trait === 'camouflage') return 0.18;
39
+ if (habitat === 'desert' && trait === 'endurance') return 0.18;
40
+ if (habitat === 'island' && trait === 'speed') return 0.18;
41
+ return 0.04;
42
+ }
43
+
44
+ function makeSeed(config: SimulationConfig) {
45
+ return Math.round(
46
+ config.population * 17 +
47
+ config.generations * 31 +
48
+ config.mutationRate * 1000 +
49
+ config.selectionPressure * 1000 +
50
+ config.driftIntensity * 1000 +
51
+ (config.seed || 0)
52
+ );
53
+ }
54
+
55
+ function advanceAlleles(
56
+ alleleA: number,
57
+ config: SimulationConfig,
58
+ random: () => number
59
+ ) {
60
+ const traitBonus = habitatBias(config.habitat, config.trait);
61
+ const pressure = config.selectionPressure * (0.5 + traitBonus);
62
+ const drift = (random() - 0.5) * config.driftIntensity;
63
+ const mutation = (random() - 0.5) * config.mutationRate;
64
+
65
+ const nextAlleleA = clamp01(alleleA + pressure * 0.08 + drift + mutation);
66
+ return {
67
+ alleleA: nextAlleleA,
68
+ alleleB: 1 - nextAlleleA,
69
+ fitness: clamp01(0.35 + nextAlleleA * 0.55 + traitBonus * 0.5 - config.driftIntensity * 0.12),
70
+ };
71
+ }
72
+
73
+ export function runSelectionDrift(config: SimulationConfig): GenerationPoint[] {
74
+ const random = seededRandom(makeSeed(config));
75
+
76
+ let alleleA = 0.5 + habitatBias(config.habitat, config.trait);
77
+ let alleleB = 1 - alleleA;
78
+ const points: GenerationPoint[] = [];
79
+
80
+ for (let generation = 0; generation <= config.generations; generation++) {
81
+ const next = advanceAlleles(alleleA, config, random);
82
+ alleleA = next.alleleA;
83
+ alleleB = next.alleleB;
84
+
85
+ points.push({
86
+ generation,
87
+ alleleA,
88
+ alleleB,
89
+ fitness: next.fitness,
90
+ });
91
+ }
92
+
93
+ return points;
94
+ }
95
+
96
+ export function summarizeOutcome(points: GenerationPoint[]) {
97
+ const finalPoint = points[points.length - 1];
98
+ if (!finalPoint) {
99
+ return {
100
+ dominant: 'alleleA' as const,
101
+ score: 0,
102
+ diversity: 1,
103
+ };
104
+ }
105
+
106
+ const dominant = finalPoint.alleleA >= finalPoint.alleleB ? 'alleleA' : 'alleleB';
107
+ const diversity = clamp01(1 - Math.abs(finalPoint.alleleA - finalPoint.alleleB));
108
+
109
+ return {
110
+ dominant,
111
+ score: Math.round(finalPoint.fitness * 100),
112
+ diversity: Math.round(diversity * 100),
113
+ };
114
+ }