-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
187 lines (171 loc) · 19.2 KB
/
Copy pathindex.html
File metadata and controls
187 lines (171 loc) · 19.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<title>Civilis — Collapse, Sustainability & Civilization Simulator</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, interactive-widget=resizes-content">
<meta name="description" content="Civilis is a civilization trajectory simulator exploring collapse risk, sustainability, resilience, economics, governance, and Kardashev-scale advancement through Monte Carlo simulation modeling.">
<meta name="author" content="Michael Schwartz">
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="Civilis — Collapse, Sustainability & Civilization Simulator">
<meta name="theme-color" content="#13171f">
<meta name="apple-mobile-web-app-title" content="Civilis — Collapse, Sustainability & Civilization Simulator">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="./index.html">
<meta name="msapplication-navbutton-color" content="#13171f">
<meta property="og:url" content="https://michaelsboost.com/civilis" />
<meta property="og:type" content="website" />
<meta property="og:title" content="Civilis — Collapse, Sustainability & Civilization Simulator" />
<meta property="og:description" content="Civilis is a civilization trajectory simulator exploring collapse risk, sustainability, resilience, economics, governance, and Kardashev-scale advancement through Monte Carlo simulation modeling." />
<meta property="og:image" content="https://raw.githubusercontent.com/michaelsboost/Civilis/main/imgs/short.png" />
<link rel="manifest" href="manifest.json">
<link rel="shortcut icon" type="image/x-icon" href="imgs/logo.svg">
<link rel="icon" type="image/svg+xml" href="imgs/logo.svg" />
<link rel="apple-touch-icon" href="imgs/logo.svg">
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="dist/bundle.css">
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
</head>
<body>
<div x-data="civilisSimulator()" x-init="initApp()" class="max-w-7xl mx-auto space-y-4 p-3 md:p-5 antialiased">
<!-- ============================================================
HEADER: Branding, clock, status, and action buttons
============================================================ -->
<div class="glass-panel p-4 flex flex-wrap justify-between items-center gap-3">
<div>
<h1 class="text-2xl md:text-3xl font-bold tracking-tight"><span class="bg-gradient-to-r from-sky-300 to-blue-400 bg-clip-text text-transparent">CIVILIS</span></h1>
<p class="text-[10px] tracking-wider text-sky-300/70 font-mono">CIVILIZATION SIMULATOR · SURVIVE · STRATEGIZE · ASCEND</p>
</div>
<div class="flex gap-2 text-xs font-mono items-center">
<!-- Live clock -->
<div class="bg-black/40 px-2 py-1 rounded"><span class="text-sky-300">🕒</span> <span x-text="missionClock"></span></div>
<!-- Offline/online status indicator -->
<div class="bg-black/40 px-2 py-1 rounded text-center"><span class="text-sky-300">📡</span> <span :class="offlineStatus==='online'?'text-green-400':'text-yellow-400'" x-text="offlineStatus.toUpperCase()"></span></div>
<!-- Share button (navigator.share with clipboard fallback) -->
<button @click="shareApp()" class="bg-black/40 hover:bg-sky-800/40 px-2 py-1 rounded transition-all flex text-center items-center gap-1">🔗 Share</button>
<!-- Donate link -->
<a href="https://michaelsboost.com/donate" target="_blank" class="bg-black/40 hover:bg-sky-800/40 px-2 py-1 rounded transition-all flex text-center items-center gap-1">💙 Donate</a>
<!-- Source code repository link -->
<a href="https://github.com/michaelsboost/Civilis" target="_blank" class="bg-black/40 hover:bg-sky-800/40 px-2 py-1 rounded transition-all flex text-center items-center gap-1"></> Source</a>
</div>
</div>
<!-- ============================================================
AI ADVISOR: Dynamic contextual commentary
Provides feedback on events, breakthroughs, and collapse warnings
============================================================ -->
<div class="mission-card p-3 rounded-lg"><div class="flex gap-2 items-start"><span class="text-2xl">🤖</span><div><span class="text-xs font-bold text-sky-300">STRATEGIC AI ADVISOR</span><p class="text-xs text-gray-300" x-text="advisorMessage"></p></div></div></div>
<!-- ============================================================
MAIN GRID: 3-column layout (desktop)
Left: Model selector, policy controls, simulation core
Center: Leaderboard and event log
Right: Charts and current status
============================================================ -->
<div class="grid lg:grid-cols-12 gap-4">
<!-- LEFT PANEL: Controls -->
<div class="lg:col-span-3 space-y-4">
<!-- Doctrine/civilization model selector -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300 uppercase mb-2">Civilization Models</div><div class="grid grid-cols-2 gap-1 max-h-64 p-2 overflow-y-auto"><template x-for="modelName in doctrineList" :key="modelName"><button @click="selectModel(modelName)" class="text-[10px] px-2 py-1 rounded text-left truncate transition-all" :class="selectedModel===modelName ? 'bg-sky-800/80 text-white ring-1 ring-sky-400' : 'hover:bg-gray-800/50'"><span x-text="modelName.slice(0,22)"></span></button></template></div></div>
<!-- Policy Controls (parameter tuning for advanced users) -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300 uppercase mb-2">Policy Controls</div><button @click="showParams = !showParams" class="w-full text-xs bg-gray-800/50 p-1.5 rounded mb-2">⚙️ Tune Parameters</button><div x-show="showParams" class="space-y-2 max-h-80 overflow-y-auto"><template x-for="param in advancedParams" :key="param.key"><div><div class="flex justify-between text-[10px]"><span x-text="param.label"></span><span x-text="currentModelParams[param.key]?.toFixed(2)"></span></div><input type="range" x-model="currentModelParams[param.key]" min="0" max="1" step="0.01" class="w-full h-1"></div></template></div></div>
<!-- Simulation Core: Monte Carlo settings and run buttons -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300 uppercase mb-2">Simulation Core</div><div class="grid grid-cols-2 gap-2 text-xs"><div><label>Horizon</label><select x-model="simOptions.years" class="bg-black/60 w-full p-1 rounded"><option>250</option><option>500</option><option>1000</option><option>2500</option><option>5000</option></select></div><div><label>Runs</label><select x-model="simOptions.runs" class="bg-black/60 w-full p-1 rounded"><option>200</option><option>500</option><option>1000</option></select></div><div><label>Disaster Freq</label><input type="range" min="0.1" max="1.5" step="0.05" x-model="simOptions.disasterFreq"></div><div><label>Black Swan</label><input type="range" min="0" max="2" step="0.1" x-model="simOptions.blackSwanProb"></div></div><button @click="rankAllModels()" :disabled="rankingInProgress" class="w-full mt-2 bg-indigo-700 p-2 rounded-lg text-sm font-bold">🏆 RUN LEADERBOARD</button><button @click="runMonteCarlo()" class="w-full mt-1 bg-emerald-700 p-2 rounded-lg text-sm font-bold">▶ SIMULATE CURRENT</button><div class="mt-2 h-1 bg-gray-700 rounded"><div class="h-full bg-gradient-to-r from-sky-500 to-indigo-500 rounded" :style="`width: ${simProgress}%`"></div></div><div class="text-right text-[9px]" x-text="simProgressMsg"></div></div>
<!-- Scenario Presets: quick horizon selection (Planetary/Stellar/Galactic) -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300">Scenario Presets</div><div class="grid grid-cols-2 gap-1 mt-1"><button @click="setScenario('planetary')" class="text-[10px] p-1 rounded bg-gray-800/50 hover:bg-gray-700">🌍 Planetary (500y)</button><button @click="setScenario('stellar')" class="text-[10px] p-1 rounded bg-gray-800/50 hover:bg-gray-700">⭐ Stellar (2000y)</button><button @click="setScenario('galactic')" class="text-[10px] p-1 rounded bg-gray-800/50 hover:bg-gray-700">🌌 Galactic (8000y)</button></div></div>
<!-- Scoring Philosophy: Different weight profiles change ranking priorities -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300 uppercase mb-2">Scoring Philosophy</div><select x-model="scoreProfile" @change="rankAllModels()" class="bg-black/60 w-full p-2 rounded text-xs"><template x-for="(profile, key) in scoreProfiles" :key="key"><option :value="key" x-text="profile.label"></option></template></select><p class="text-[10px] text-gray-400 mt-2" x-text="scoreProfiles[scoreProfile]?.description || ''"></p></div>
</div>
<!-- CENTER PANEL: Leaderboard & Event Log -->
<div class="lg:col-span-6 space-y-4">
<!-- Champion card (#1 ranked doctrine) -->
<div class="mission-card p-4" x-show="rankedModelsList.length">
<div class="text-[10px] text-sky-300 mb-1">Scoring Profile: <span x-text="scoreProfiles[scoreProfile]?.label || 'Balanced Viability'"></span></div>
<div class="flex justify-between items-start flex-wrap"><div><span class="text-[10px] text-yellow-400">#1 STRATEGIC LEADER</span><h2 class="text-xl font-bold" x-text="rankedModelsList[0]?.modelName"></h2><div class="flex gap-2"><span :class="'grade-'+getGrade(rankedModelsList[0]?.viabilityScore)" class="text-3xl font-black" x-text="getGrade(rankedModelsList[0]?.viabilityScore)"></span><span class="text-3xl font-bold" x-text="rankedModelsList[0]?.viabilityScore.toFixed(1)"></span></div></div><div class="text-right"><span class="text-[10px] bg-sky-900/50 px-2 py-0.5 rounded">Max K: <strong x-text="rankedModelsList[0]?.maxK?.toFixed(2)"></strong></span><div class="text-[10px] mt-1">Survival: <strong x-text="rankedModelsList[0]?.yearsSurvived"></strong> years</div></div></div>
<div class="grid grid-cols-3 gap-2 mt-3 text-xs"><div>💀 Collapse: <strong :class="rankedModelsList[0]?.collapseProb>0.3?'text-red-400':'text-green-400'" x-text="(rankedModelsList[0]?.collapseProb*100).toFixed(0)+'%'"></strong></div><div>🌿 Sustain: <span x-text="rankedModelsList[0]?.sustainabilityScore?.toFixed(1)"></span></div><div>🚀 P(Type III): <span x-text="(rankedModelsList[0]?.typeIIIProb*100).toFixed(1)+'%'"></span></div></div>
<button @click="showDoctrineModal(rankedModelsList[0])" class="text-[10px] mt-2 text-sky-300">📊 View Doctrine Analysis →</button>
</div>
<!-- LEADERBOARD TABLE - Clean fixed row structure -->
<div class="glass-panel p-3 overflow-x-auto" x-show="rankedModelsList.length">
<div class="flex justify-between items-center mb-2"><span class="text-sm font-bold">CIVILIZATION LEADERBOARD</span><select x-model="rankSortBy" @change="sortRanking()" class="bg-black/50 text-xs p-1 rounded"><option value="viability">Viability</option><option value="maxK">Max K</option><option value="typeI">Type I</option><option value="typeIII">Type III</option><option value="sustainability">Sustainability</option><option value="collapseProb">Collapse Risk</option></select></div>
<table class="w-full text-xs">
<thead class="text-sky-300"><tr><th class="p-1">#</th><th>Model</th><th>Grade</th><th>Viability</th><th>Max K</th><th>P(I)</th><th>P(III)</th><th>Sustain</th><th>Collapse</th></tr></thead>
<tbody>
<template x-for="(item, idx) in sortedRankingList" :key="item.modelName">
<tr class="border-t border-white/10 hover:bg-white/5 cursor-pointer" @click="showDoctrineModal(item)">
<td class="p-1 text-center" x-text="idx+1"></td>
<td class="truncate max-w-[100px]" x-text="item.modelName.slice(0,18)"></td>
<td :class="'grade-'+getGrade(item.viabilityScore)" x-text="getGrade(item.viabilityScore)"></td>
<td x-text="item.viabilityScore.toFixed(1)"></td>
<td x-text="item.maxK?.toFixed(2)"></td>
<td x-text="(item.typeIProb*100).toFixed(0)+'%'"></td>
<td x-text="(item.typeIIIProb*100).toFixed(1)+'%'"></td>
<td x-text="item.sustainabilityScore?.toFixed(1)"></td>
<td x-text="(item.collapseProb*100).toFixed(0)+'%'"></td>
</tr>
</template>
</tbody>
</table>
</div>
<div x-show="!rankedModelsList.length && !rankingInProgress" class="glass-panel p-6 text-center text-gray-400">Run Leaderboard Analysis to compare models</div>
<div x-show="rankingInProgress" class="glass-panel p-3 text-center text-sky-300 animate-pulse" x-text="rankingProgressMsg"></div>
<!-- Strategic Event Log: Real-time simulation events -->
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300 uppercase mb-2">Strategic Event Log</div><div class="h-32 overflow-y-auto space-y-1 text-[10px]"><template x-for="evt in events.slice(0,8)" :key="evt.timestamp"><div :class="'p-1 rounded ' + evt.class"><span class="text-gray-500" x-text="evt.timestamp"></span> <span x-text="evt.message"></span></div></template><div x-show="events.length===0" class="text-center text-gray-500">Run simulation to see events</div></div></div>
</div>
<!-- RIGHT PANEL: Charts & Current Status -->
<div class="lg:col-span-3 space-y-4">
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300">Doctrine Radar</div><div class="radar-container"><canvas id="radarChart" width="250" height="250"></canvas></div></div>
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300">Kardashev Trajectory</div><canvas id="trajectoryChart" width="300" height="150"></canvas></div>
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300">Collapse Timeline</div><canvas id="collapseHistogram" width="300" height="150"></canvas></div>
<div class="glass-panel p-3"><div class="text-xs font-bold text-sky-300">Current Status</div><div x-show="lastSimulationResults"><div class="text-2xl font-bold" x-text="lastSimulationResults?.viabilityScore.toFixed(1)"></div><div>Viability Score</div><div class="grid grid-cols-2 gap-1 text-[10px] mt-2"><div>📈 Max K: <span x-text="lastSimulationResults?.maxK?.toFixed(2)"></span></div><div>💀 Collapse: <span x-text="(lastSimulationResults?.collapseProb*100).toFixed(0)+'%'"></span></div><div>🌿 Sustain: <span x-text="lastSimulationResults?.sustainabilityScore?.toFixed(1)"></span></div><div>🚀 P(III): <span x-text="(lastSimulationResults?.typeIIIProb*100).toFixed(1)+'%'"></span></div></div></div><div x-show="!lastSimulationResults" class="text-xs text-gray-400">No simulation yet</div></div>
</div>
</div>
<!-- ============================================================
DOCTRINE MODAL: Detailed analysis for selected doctrine
Shows description, strengths, weaknesses, failure mode, and metrics
============================================================ -->
<div x-show="selectedDoctrine" class="fixed inset-0 bg-black/90 flex items-center justify-center z-50 p-4 overflow-y-auto" x-cloak="" @click.away="selectedDoctrine = null">
<div class="glass-panel max-w-2xl w-full max-h-[85vh] overflow-y-auto p-5">
<div class="flex justify-between"><h3 class="text-xl font-bold" x-text="selectedDoctrine.modelName"></h3><span :class="'grade-'+getGrade(selectedDoctrine.viabilityScore)" class="text-2xl font-black" x-text="getGrade(selectedDoctrine.viabilityScore)"></span></div>
<div class="mt-2 text-xs bg-black/30 p-2 rounded"><span class="font-bold text-sky-300">Description:</span> <span x-text="getDoctrineAnalysis(selectedDoctrine.modelName).description"></span></div>
<div class="mt-3 grid grid-cols-1 md:grid-cols-2 gap-3 text-xs">
<div class="bg-black/30 p-2 rounded"><span class="font-bold text-green-300">Strengths</span><ul><template x-for="s in getDoctrineAnalysis(selectedDoctrine.modelName).strengths" :key="s"><li x-text="s" class="mt-1"></li></template></ul></div>
<div class="bg-black/30 p-2 rounded"><span class="font-bold text-red-300">Weaknesses</span><ul><template x-for="w in getDoctrineAnalysis(selectedDoctrine.modelName).weaknesses" :key="w"><li x-text="w" class="mt-1"></li></template></ul></div>
</div>
<div class="mt-2 text-xs bg-black/30 p-2 rounded"><span class="font-bold">Failure Mode:</span> <span x-text="getDoctrineAnalysis(selectedDoctrine.modelName).failureMode"></span></div>
<div class="grid grid-cols-2 gap-2 mt-3 text-xs">
<div>Viability: <strong x-text="selectedDoctrine.viabilityScore.toFixed(1)"></strong></div><div>Max K: <strong x-text="selectedDoctrine.maxK?.toFixed(2)"></strong></div>
<div>P(Type I): <strong x-text="(selectedDoctrine.typeIProb*100).toFixed(0)+'%'"></strong></div><div>P(Type III): <strong x-text="(selectedDoctrine.typeIIIProb*100).toFixed(1)+'%'"></strong></div>
<div>Collapse Risk: <strong x-text="(selectedDoctrine.collapseProb*100).toFixed(0)+'%'"></strong></div><div>Years Survived: <strong x-text="selectedDoctrine.yearsSurvived"></strong></div>
</div>
<button @click="selectedDoctrine = null" class="mt-4 w-full bg-gray-700 p-2 rounded text-sm">Close</button>
</div>
</div>
<!-- Footer with license and disclaimer -->
<div class="text-center text-[9px] text-gray-500 pt-2 border-t border-white/10">MIT License · Open Source · Educational sandbox exploring tradeoffs between growth, sustainability, resilience, and expansion. Results are speculative, not predictive.</div>
</div>
<script src="dist/script.js"></script>
<script src="https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').then(reg => {
reg.addEventListener('updatefound', () => {
const newSW = reg.installing;
newSW.addEventListener('statechange', () => {
if (newSW.state === 'installed' && navigator.serviceWorker.controller) {
// Notify the user and reload if they confirm
if (confirm('A new version is available. Reload now?')) {
window.location.reload();
}
}
});
});
});
// Ensure immediate activation of a new service worker
navigator.serviceWorker.ready.then(registration => {
registration.active.postMessage({ type: 'SKIP_WAITING' });
});
}
</script>
</body>
</html>