ghost-logic commited on
Commit
dfd45fc
·
verified ·
1 Parent(s): 14f083d

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +1031 -0
templates/index.html ADDED
@@ -0,0 +1,1031 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>🐉 D&D Campaign Manager</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
10
+ <script src="https://cdn.tailwindcss.com"></script>
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
+ <style>
13
+ @keyframes glitch {
14
+ 0% { text-shadow: 0 0 2px #0f0, 0 0 5px #0f0, 0 0 10px #0f0; }
15
+ 25% { text-shadow: 0 0 2px #f0f, 0 0 5px #f0f, 0 0 10px #f0f; }
16
+ 50% { text-shadow: 0 0 2px #0ff, 0 0 5px #0ff, 0 0 10px #0ff; }
17
+ 75% { text-shadow: 0 0 2px #ff0, 0 0 5px #ff0, 0 0 10px #ff0; }
18
+ 100% { text-shadow: 0 0 2px #f00, 0 0 5px #f00, 0 0 10px #f00; }
19
+ }
20
+
21
+ @keyframes fadeIn {
22
+ from { opacity: 0; transform: translateY(10px); }
23
+ to { opacity: 1; transform: translateY(0); }
24
+ }
25
+
26
+ @keyframes gentlePulse {
27
+ 0% { transform: scale(1); }
28
+ 50% { transform: scale(1.02); }
29
+ 100% { transform: scale(1); }
30
+ }
31
+
32
+ .tab-content {
33
+ animation: fadeIn 0.5s ease-out;
34
+ }
35
+
36
+ * {
37
+ transition: background-color 0.3s ease, color 0.3s ease;
38
+ }
39
+
40
+ .character-sheet:hover, .npc-card:hover, .location-card:hover {
41
+ animation: gentlePulse 3s ease-in-out infinite;
42
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
43
+ }
44
+
45
+ .dice-roller:hover {
46
+ transform: translateY(-3px);
47
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
48
+ transition: all 0.3s ease;
49
+ }
50
+
51
+ .agent-card {
52
+ background: linear-gradient(135deg, #6b21a8 0%, #7e22ce 100%);
53
+ padding: 20px;
54
+ border-radius: 15px;
55
+ margin: 10px 0;
56
+ color: white;
57
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
58
+ }
59
+
60
+ .output-box {
61
+ background: #111827;
62
+ border: 1px solid #4b5563;
63
+ border-radius: 10px;
64
+ padding: 15px;
65
+ margin: 10px 0;
66
+ color: #e5e7eb;
67
+ max-height: 300px;
68
+ overflow-y: auto;
69
+ }
70
+
71
+ .tab-content {
72
+ display: none;
73
+ }
74
+
75
+ .tab-content.active {
76
+ display: block;
77
+ }
78
+
79
+ .tab-button {
80
+ transition: all 0.3s ease;
81
+ }
82
+
83
+ .tab-button.active {
84
+ background-color: #4f46e5;
85
+ color: white;
86
+ }
87
+
88
+ .character-sheet {
89
+ background-color: #1f2937;
90
+ border-radius: 0.5rem;
91
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
92
+ color: #e5e7eb;
93
+ }
94
+
95
+ .ability-score {
96
+ background-color: #374151;
97
+ border-radius: 0.25rem;
98
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
99
+ color: #f3f4f6;
100
+ }
101
+
102
+ .dice-roller {
103
+ background-color: #7c3aed;
104
+ color: white;
105
+ transition: all 0.3s ease;
106
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
107
+ font-family: 'Quicksand', sans-serif;
108
+ }
109
+
110
+ .dice-roller:hover {
111
+ transform: translateY(-3px);
112
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
113
+ filter: brightness(1.05);
114
+ }
115
+
116
+ .loading {
117
+ opacity: 0.6;
118
+ pointer-events: none;
119
+ }
120
+
121
+ .spinner {
122
+ display: inline-block;
123
+ width: 20px;
124
+ height: 20px;
125
+ border: 3px solid rgba(255,255,255,.3);
126
+ border-radius: 50%;
127
+ border-top-color: #fff;
128
+ animation: spin 1s ease-in-out infinite;
129
+ }
130
+
131
+ @keyframes spin {
132
+ to { transform: rotate(360deg); }
133
+ }
134
+
135
+ .glitch-title {
136
+ animation: glitch 2s infinite alternate;
137
+ }
138
+ </style>
139
+ </head>
140
+ <body class="bg-gray-900" style="font-family: 'Press Start 2P', cursive;">
141
+ <div class="container mx-auto px-4 py-8">
142
+ <!-- Header -->
143
+ <header class="mb-8 text-center">
144
+ <h1 class="text-4xl font-bold text-purple-400 mb-2 glitch-title" style="font-family: 'Press Start 2P', cursive;">
145
+ <i class="fas fa-dragon mr-2"></i> D&D CAMPAIGN MANAGER
146
+ </h1>
147
+ <p class="text-lg text-gray-400 mb-4">
148
+ 🤖 AI-POWERED TOOLKIT FOR EPIC ADVENTURES 🎲
149
+ </p>
150
+ <div class="bg-indigo-900 rounded-lg p-4 max-w-4xl mx-auto border border-purple-500">
151
+ <p class="text-purple-300 font-medium mb-2">
152
+ <i class="fas fa-star mr-2"></i> FEATURES ONLINE:
153
+ </p>
154
+ <div class="flex flex-wrap justify-center gap-2">
155
+ <span class="bg-purple-700 px-3 py-1 rounded-full text-sm text-white">
156
+ <i class="fas fa-user mr-1"></i> CHARACTER CREATOR
157
+ </span>
158
+ <span class="bg-purple-700 px-3 py-1 rounded-full text-sm text-white">
159
+ <i class="fas fa-theater-masks mr-1"></i> AI DUNGEON MASTER
160
+ </span>
161
+ <span class="bg-purple-700 px-3 py-1 rounded-full text-sm text-white">
162
+ <i class="fas fa-users mr-1"></i> NPC GENERATOR
163
+ </span>
164
+ <span class="bg-purple-700 px-3 py-1 rounded-full text-sm text-white">
165
+ <i class="fas fa-dice mr-1"></i> RANDOM TOOLS
166
+ </span>
167
+ </div>
168
+ </div>
169
+ </header>
170
+
171
+ <!-- Navigation Tabs -->
172
+ <div class="flex overflow-x-auto mb-8 bg-gray-800 rounded-lg shadow-lg p-1">
173
+ <button class="tab-button px-4 py-3 text-sm font-bold text-purple-300 active hover:bg-gray-700 transition-all duration-200" data-tab="character-creator" style="font-family: 'Press Start 2P', cursive;">
174
+ <i class="fas fa-user mr-2"></i> CHARACTER
175
+ </button>
176
+ <button class="tab-button px-4 py-3 text-sm font-bold text-gray-400 hover:text-purple-300 hover:bg-gray-700 transition-all duration-200" data-tab="campaign-manager" style="font-family: 'Press Start 2P', cursive;">
177
+ <i class="fas fa-scroll mr-2"></i> CAMPAIGN
178
+ </button>
179
+ <button class="tab-button px-4 py-3 text-sm font-bold text-gray-400 hover:text-purple-300 hover:bg-gray-700 transition-all duration-200" data-tab="npc-creator" style="font-family: 'Press Start 2P', cursive;">
180
+ <i class="fas fa-users mr-2"></i> NPC
181
+ </button>
182
+ <button class="tab-button px-4 py-3 text-sm font-bold text-gray-400 hover:text-purple-300 hover:bg-gray-700 transition-all duration-200" data-tab="random-tools" style="font-family: 'Press Start 2P', cursive;">
183
+ <i class="fas fa-dice mr-2"></i> RANDOM
184
+ </button>
185
+ </div>
186
+
187
+ <!-- Tab Contents -->
188
+ <div class="bg-gray-800 rounded-lg shadow-lg p-6 mb-8">
189
+
190
+ <!-- CHARACTER CREATOR TAB -->
191
+ <div id="character-creator" class="tab-content active">
192
+ <h2 class="text-2xl font-bold text-purple-400 mb-6">
193
+ <i class="fas fa-user mr-2"></i> CHARACTER CREATOR
194
+ </h2>
195
+
196
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
197
+ <!-- Character Form -->
198
+ <div class="lg:col-span-2">
199
+ <div class="character-sheet p-6 mb-6">
200
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
201
+ <i class="fas fa-scroll mr-2"></i> CHARACTER DETAILS
202
+ </h3>
203
+
204
+ <!-- Name Section -->
205
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
206
+ <div>
207
+ <label class="block text-sm font-medium text-gray-300 mb-2">CHARACTER NAME</label>
208
+ <input type="text" id="character-name" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" placeholder="Enter name...">
209
+ </div>
210
+ <div>
211
+ <button id="generate-name-btn" class="w-full mt-6 px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 transition">
212
+ <i class="fas fa-magic mr-2"></i> GENERATE NAME
213
+ </button>
214
+ </div>
215
+ </div>
216
+
217
+ <!-- Basic Info -->
218
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
219
+ <div>
220
+ <label class="block text-sm font-medium text-gray-300 mb-2">RACE</label>
221
+ <select id="character-race" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
222
+ <option>Human</option>
223
+ <option>Elf</option>
224
+ <option>Dwarven</option>
225
+ <option>Fantasy Place</option>
226
+ <option>Tavern</option>
227
+ </select>
228
+ </div>
229
+
230
+ <button id="gen-name-btn" class="dice-roller w-full px-4 py-2 rounded-md font-bold mb-2">
231
+ <i class="fas fa-dice mr-2"></i> GENERATE NAME
232
+ </button>
233
+
234
+ <input type="text" id="random-name" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" placeholder="Generated name will appear here" readonly>
235
+ </div>
236
+
237
+ <!-- Plot Hook Generator -->
238
+ <div class="character-sheet p-6">
239
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
240
+ <i class="fas fa-fish mr-2"></i> PLOT HOOKS
241
+ </h3>
242
+
243
+ <div class="mb-4">
244
+ <label class="block text-sm font-medium text-gray-300 mb-2">THEME</label>
245
+ <select id="hook-theme" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
246
+ <option>Mystery</option>
247
+ <option>Adventure</option>
248
+ <option>Political</option>
249
+ <option>Personal</option>
250
+ <option>Rescue</option>
251
+ <option>Exploration</option>
252
+ </select>
253
+ </div>
254
+
255
+ <button id="gen-hook-btn" class="dice-roller w-full px-4 py-2 rounded-md font-bold mb-2">
256
+ <i class="fas fa-dice mr-2"></i> GENERATE HOOK
257
+ </button>
258
+
259
+ <textarea id="plot-hook" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" rows="3" placeholder="Generated plot hook will appear here" readonly></textarea>
260
+ </div>
261
+
262
+ <!-- Encounter Generator -->
263
+ <div class="character-sheet p-6">
264
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
265
+ <i class="fas fa-swords mr-2"></i> ENCOUNTERS
266
+ </h3>
267
+
268
+ <div class="grid grid-cols-2 gap-4 mb-4">
269
+ <div>
270
+ <label class="block text-sm font-medium text-gray-300 mb-2">PARTY LEVEL</label>
271
+ <input type="range" id="encounter-level" min="1" max="20" value="5" class="w-full">
272
+ <div id="encounter-level-display" class="text-center text-sm font-medium text-gray-300">Level 5</div>
273
+ </div>
274
+ <div>
275
+ <label class="block text-sm font-medium text-gray-300 mb-2">DIFFICULTY</label>
276
+ <select id="encounter-difficulty" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
277
+ <option>Easy</option>
278
+ <option>Medium</option>
279
+ <option>Hard</option>
280
+ <option>Deadly</option>
281
+ </select>
282
+ </div>
283
+ </div>
284
+
285
+ <button id="gen-encounter-btn" class="dice-roller w-full px-4 py-2 rounded-md font-bold mb-2">
286
+ <i class="fas fa-dice-d20 mr-2"></i> GENERATE ENCOUNTER
287
+ </button>
288
+
289
+ <textarea id="random-encounter" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" rows="3" placeholder="Generated encounter will appear here" readonly></textarea>
290
+ </div>
291
+
292
+ <!-- Weather Generator -->
293
+ <div class="character-sheet p-6">
294
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
295
+ <i class="fas fa-cloud-sun-rain mr-2"></i> WEATHER
296
+ </h3>
297
+
298
+ <div class="mb-4">
299
+ <label class="block text-sm font-medium text-gray-300 mb-2">CLIMATE</label>
300
+ <select id="climate" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
301
+ <option>Temperate</option>
302
+ <option>Tropical</option>
303
+ <option>Arctic</option>
304
+ <option>Desert</option>
305
+ <option>Mountainous</option>
306
+ </select>
307
+ </div>
308
+
309
+ <button id="gen-weather-btn" class="dice-roller w-full px-4 py-2 rounded-md font-bold mb-2">
310
+ <i class="fas fa-dice mr-2"></i> GENERATE WEATHER
311
+ </button>
312
+
313
+ <textarea id="weather" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" rows="2" placeholder="Generated weather will appear here" readonly></textarea>
314
+ </div>
315
+ </div>
316
+ </div>
317
+ </div>
318
+
319
+ <!-- Footer -->
320
+ <footer class="text-center text-gray-500 text-sm mt-8">
321
+ <p>🐉 Powered by AI • Built for Epic Adventures • <span class="text-purple-400">HuggingFace Spaces</span></p>
322
+ </footer>
323
+ </div>
324
+
325
+ <script>
326
+ // Global state
327
+ let currentCharacter = {};
328
+ let campaignContext = '';
329
+
330
+ // Utility functions
331
+ function showLoading(button) {
332
+ const originalHTML = button.innerHTML;
333
+ button.innerHTML = '<div class="spinner mr-2"></div>Loading...';
334
+ button.classList.add('loading');
335
+ return originalHTML;
336
+ }
337
+
338
+ function hideLoading(button, originalHTML) {
339
+ button.innerHTML = originalHTML;
340
+ button.classList.remove('loading');
341
+ }
342
+
343
+ async function makeAPICall(endpoint, data = {}, method = 'POST') {
344
+ try {
345
+ const response = await fetch(endpoint, {
346
+ method: method,
347
+ headers: {
348
+ 'Content-Type': 'application/json',
349
+ },
350
+ body: method === 'POST' ? JSON.stringify(data) : undefined
351
+ });
352
+
353
+ if (!response.ok) {
354
+ throw new Error(`HTTP error! status: ${response.status}`);
355
+ }
356
+
357
+ return await response.json();
358
+ } catch (error) {
359
+ console.error('API call failed:', error);
360
+ throw error;
361
+ }
362
+ }
363
+
364
+ // Tab switching
365
+ document.querySelectorAll('.tab-button').forEach(button => {
366
+ button.addEventListener('click', () => {
367
+ document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
368
+ document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
369
+
370
+ button.classList.add('active');
371
+ document.getElementById(button.getAttribute('data-tab')).classList.add('active');
372
+ });
373
+ });
374
+
375
+ // Character Creator Functions
376
+ document.getElementById('roll-abilities-btn').addEventListener('click', async function() {
377
+ const originalHTML = showLoading(this);
378
+
379
+ try {
380
+ const response = await makeAPICall('/api/character/roll-abilities');
381
+
382
+ if (response.success) {
383
+ const abilities = response.abilities;
384
+
385
+ Object.entries(abilities).forEach(([ability, value]) => {
386
+ const abilityElement = document.querySelector(`[data-ability="${ability.substring(0,3).toUpperCase()}"]`);
387
+ if (abilityElement) {
388
+ const valueElement = abilityElement.querySelector('.ability-value');
389
+ const modifierElement = abilityElement.querySelector('.ability-modifier');
390
+
391
+ valueElement.textContent = value;
392
+ const modifier = Math.floor((value - 10) / 2);
393
+ modifierElement.textContent = `(${modifier >= 0 ? '+' : ''}${modifier})`;
394
+ }
395
+ });
396
+
397
+ currentCharacter.abilities = abilities;
398
+ updateCharacterSummary();
399
+ }
400
+ } catch (error) {
401
+ alert('Error rolling abilities: ' + error.message);
402
+ } finally {
403
+ hideLoading(this, originalHTML);
404
+ }
405
+ });
406
+
407
+ document.getElementById('generate-name-btn').addEventListener('click', async function() {
408
+ const originalHTML = showLoading(this);
409
+
410
+ try {
411
+ const data = {
412
+ race: document.getElementById('character-race').value,
413
+ class: document.getElementById('character-class').value,
414
+ gender: document.getElementById('character-gender').value
415
+ };
416
+
417
+ const response = await makeAPICall('/api/character/generate-name', data);
418
+
419
+ if (response.success) {
420
+ document.getElementById('character-name').value = response.name;
421
+ updateCharacterSummary();
422
+ }
423
+ } catch (error) {
424
+ alert('Error generating name: ' + error.message);
425
+ } finally {
426
+ hideLoading(this, originalHTML);
427
+ }
428
+ });
429
+
430
+ document.getElementById('generate-backstory-btn').addEventListener('click', async function() {
431
+ const originalHTML = showLoading(this);
432
+
433
+ try {
434
+ const data = {
435
+ name: document.getElementById('character-name').value || 'Character',
436
+ race: document.getElementById('character-race').value,
437
+ class: document.getElementById('character-class').value,
438
+ background: document.getElementById('character-background').value
439
+ };
440
+
441
+ const response = await makeAPICall('/api/character/generate-backstory', data);
442
+
443
+ if (response.success) {
444
+ document.getElementById('character-backstory').value = response.backstory;
445
+ updateCharacterSummary();
446
+ }
447
+ } catch (error) {
448
+ alert('Error generating backstory: ' + error.message);
449
+ } finally {
450
+ hideLoading(this, originalHTML);
451
+ }
452
+ });
453
+
454
+ document.getElementById('generate-portrait-btn').addEventListener('click', async function() {
455
+ const originalHTML = showLoading(this);
456
+
457
+ try {
458
+ const data = {
459
+ race: document.getElementById('character-race').value,
460
+ class: document.getElementById('character-class').value,
461
+ gender: document.getElementById('character-gender').value
462
+ };
463
+
464
+ const response = await makeAPICall('/api/character/generate-portrait', data);
465
+
466
+ if (response.success) {
467
+ const portraitDiv = document.getElementById('character-portrait');
468
+ portraitDiv.innerHTML = `<img src="${response.image_url}" alt="Character Portrait" class="w-full h-full object-cover rounded-lg">`;
469
+ }
470
+ } catch (error) {
471
+ alert('Error generating portrait: ' + error.message);
472
+ } finally {
473
+ hideLoading(this, originalHTML);
474
+ }
475
+ });
476
+
477
+ // Campaign Functions
478
+ document.getElementById('generate-campaign-btn').addEventListener('click', async function() {
479
+ const originalHTML = showLoading(this);
480
+
481
+ try {
482
+ const data = {
483
+ theme: document.getElementById('campaign-theme').value,
484
+ level: parseInt(document.getElementById('campaign-level').value),
485
+ players: parseInt(document.getElementById('campaign-players').value)
486
+ };
487
+
488
+ const response = await makeAPICall('/api/campaign/generate-concept', data);
489
+
490
+ if (response.success) {
491
+ document.getElementById('campaign-output').innerHTML = `<p class="text-gray-300 whitespace-pre-wrap">${response.content}</p>`;
492
+ campaignContext = response.content;
493
+ }
494
+ } catch (error) {
495
+ alert('Error generating campaign: ' + error.message);
496
+ } finally {
497
+ hideLoading(this, originalHTML);
498
+ }
499
+ });
500
+
501
+ document.getElementById('generate-campaign-art-btn').addEventListener('click', async function() {
502
+ const originalHTML = showLoading(this);
503
+
504
+ try {
505
+ const data = {
506
+ theme: document.getElementById('campaign-theme').value,
507
+ level: parseInt(document.getElementById('campaign-level').value)
508
+ };
509
+
510
+ const response = await makeAPICall('/api/campaign/generate-art', data);
511
+
512
+ if (response.success) {
513
+ const imageDiv = document.getElementById('campaign-image');
514
+ imageDiv.innerHTML = `<img src="${response.image_url}" alt="Campaign Art" class="w-full h-full object-cover rounded-lg">`;
515
+ }
516
+ } catch (error) {
517
+ alert('Error generating campaign art: ' + error.message);
518
+ } finally {
519
+ hideLoading(this, originalHTML);
520
+ }
521
+ });
522
+
523
+ document.getElementById('generate-session-btn').addEventListener('click', async function() {
524
+ const originalHTML = showLoading(this);
525
+
526
+ try {
527
+ const data = {
528
+ campaign_context: campaignContext || 'General D&D campaign',
529
+ session_number: parseInt(document.getElementById('session-number').value)
530
+ };
531
+
532
+ const response = await makeAPICall('/api/campaign/generate-session', data);
533
+
534
+ if (response.success) {
535
+ document.getElementById('session-output').innerHTML = `<p class="text-white whitespace-pre-wrap">${response.content}</p>`;
536
+ }
537
+ } catch (error) {
538
+ alert('Error generating session: ' + error.message);
539
+ } finally {
540
+ hideLoading(this, originalHTML);
541
+ }
542
+ });
543
+
544
+ // NPC Functions
545
+ document.getElementById('create-npc-btn').addEventListener('click', async function() {
546
+ const originalHTML = showLoading(this);
547
+
548
+ try {
549
+ const data = {
550
+ context: document.getElementById('npc-context').value,
551
+ role: document.getElementById('npc-role').value,
552
+ importance: document.getElementById('npc-importance').value,
553
+ gender: document.getElementById('npc-gender').value
554
+ };
555
+
556
+ const response = await makeAPICall('/api/npc/create', data);
557
+
558
+ if (response.success) {
559
+ document.getElementById('npc-output').innerHTML = `<p class="text-gray-300 whitespace-pre-wrap">${response.content}</p>`;
560
+ }
561
+ } catch (error) {
562
+ alert('Error creating NPC: ' + error.message);
563
+ } finally {
564
+ hideLoading(this, originalHTML);
565
+ }
566
+ });
567
+
568
+ // Random Generator Functions
569
+ document.getElementById('gen-name-btn').addEventListener('click', async function() {
570
+ try {
571
+ const data = { type: document.getElementById('name-type').value };
572
+ const response = await makeAPICall('/api/random/name', data);
573
+
574
+ if (response.success) {
575
+ document.getElementById('random-name').value = response.name;
576
+ }
577
+ } catch (error) {
578
+ alert('Error generating name: ' + error.message);
579
+ }
580
+ });
581
+
582
+ document.getElementById('gen-hook-btn').addEventListener('click', async function() {
583
+ try {
584
+ const data = { theme: document.getElementById('hook-theme').value };
585
+ const response = await makeAPICall('/api/random/plot-hook', data);
586
+
587
+ if (response.success) {
588
+ document.getElementById('plot-hook').value = response.hook;
589
+ }
590
+ } catch (error) {
591
+ alert('Error generating plot hook: ' + error.message);
592
+ }
593
+ });
594
+
595
+ document.getElementById('gen-encounter-btn').addEventListener('click', async function() {
596
+ try {
597
+ const data = {
598
+ level: parseInt(document.getElementById('encounter-level').value),
599
+ difficulty: document.getElementById('encounter-difficulty').value
600
+ };
601
+ const response = await makeAPICall('/api/random/encounter', data);
602
+
603
+ if (response.success) {
604
+ document.getElementById('random-encounter').value = response.encounter;
605
+ }
606
+ } catch (error) {
607
+ alert('Error generating encounter: ' + error.message);
608
+ }
609
+ });
610
+
611
+ document.getElementById('gen-weather-btn').addEventListener('click', async function() {
612
+ try {
613
+ const data = { climate: document.getElementById('climate').value };
614
+ const response = await makeAPICall('/api/random/weather', data);
615
+
616
+ if (response.success) {
617
+ document.getElementById('weather').value = response.weather;
618
+ }
619
+ } catch (error) {
620
+ alert('Error generating weather: ' + error.message);
621
+ }
622
+ });
623
+
624
+ // Level sliders
625
+ document.getElementById('character-level').addEventListener('input', function() {
626
+ document.getElementById('level-display').textContent = `Level ${this.value}`;
627
+ updateCharacterSummary();
628
+ });
629
+
630
+ document.getElementById('campaign-level').addEventListener('input', function() {
631
+ document.getElementById('campaign-level-display').textContent = `Level ${this.value}`;
632
+ });
633
+
634
+ document.getElementById('campaign-players').addEventListener('input', function() {
635
+ document.getElementById('campaign-players-display').textContent = `${this.value} Players`;
636
+ });
637
+
638
+ document.getElementById('encounter-level').addEventListener('input', function() {
639
+ document.getElementById('encounter-level-display').textContent = `Level ${this.value}`;
640
+ });
641
+
642
+ // Character form listeners
643
+ ['character-name', 'character-race', 'character-class', 'character-gender', 'character-background', 'character-backstory'].forEach(id => {
644
+ document.getElementById(id).addEventListener('change', updateCharacterSummary);
645
+ });
646
+
647
+ function updateCharacterSummary() {
648
+ const name = document.getElementById('character-name').value || 'Unnamed Character';
649
+ const race = document.getElementById('character-race').value;
650
+ const charClass = document.getElementById('character-class').value;
651
+ const gender = document.getElementById('character-gender').value;
652
+ const level = document.getElementById('character-level').value;
653
+ const background = document.getElementById('character-background').value;
654
+ const backstory = document.getElementById('character-backstory').value;
655
+
656
+ // Get ability scores
657
+ const abilities = {};
658
+ document.querySelectorAll('.ability-score').forEach(element => {
659
+ const ability = element.getAttribute('data-ability');
660
+ const value = parseInt(element.querySelector('.ability-value').textContent);
661
+ abilities[ability] = value;
662
+ });
663
+
664
+ const summary = `
665
+ <div class="text-white">
666
+ <h4 class="text-lg font-bold mb-2 text-purple-300">${name}</h4>
667
+ <p class="text-gray-400 mb-2"><em>Level ${level} ${gender} ${race} ${charClass}</em></p>
668
+
669
+ <div class="mb-3">
670
+ <h5 class="font-bold mb-1 text-purple-300">Ability Scores:</h5>
671
+ <div class="grid grid-cols-2 gap-1 text-sm">
672
+ ${Object.entries(abilities).map(([ability, value]) => {
673
+ const modifier = Math.floor((value - 10) / 2);
674
+ return `<div>• ${ability}: ${value} (${modifier >= 0 ? '+' : ''}${modifier})</div>`;
675
+ }).join('')}
676
+ </div>
677
+ </div>
678
+
679
+ <div class="mb-3">
680
+ <h5 class="font-bold mb-1 text-purple-300">Background:</h5>
681
+ <p class="text-sm">${background}</p>
682
+ </div>
683
+
684
+ ${backstory ? `
685
+ <div>
686
+ <h5 class="font-bold mb-1 text-purple-300">Backstory:</h5>
687
+ <p class="text-sm text-gray-400">${backstory}</p>
688
+ </div>
689
+ ` : ''}
690
+ </div>
691
+ `;
692
+
693
+ document.getElementById('character-summary').innerHTML = summary;
694
+
695
+ currentCharacter = {
696
+ name, race, class: charClass, gender, level: parseInt(level),
697
+ background, backstory, abilities
698
+ };
699
+ }
700
+
701
+ // Initialize
702
+ updateCharacterSummary();
703
+
704
+ </script>
705
+ </body>
706
+ </html>f</option>
707
+ <option>Halfling</option>
708
+ <option>Dragonborn</option>
709
+ <option>Gnome</option>
710
+ <option>Half-Elf</option>
711
+ <option>Half-Orc</option>
712
+ <option>Tiefling</option>
713
+ </select>
714
+ </div>
715
+ <div>
716
+ <label class="block text-sm font-medium text-gray-300 mb-2">CLASS</label>
717
+ <select id="character-class" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
718
+ <option>Fighter</option>
719
+ <option>Wizard</option>
720
+ <option>Rogue</option>
721
+ <option>Cleric</option>
722
+ <option>Barbarian</option>
723
+ <option>Bard</option>
724
+ <option>Druid</option>
725
+ <option>Monk</option>
726
+ <option>Paladin</option>
727
+ <option>Ranger</option>
728
+ <option>Sorcerer</option>
729
+ <option>Warlock</option>
730
+ </select>
731
+ </div>
732
+ <div>
733
+ <label class="block text-sm font-medium text-gray-300 mb-2">GENDER</label>
734
+ <select id="character-gender" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
735
+ <option>Male</option>
736
+ <option>Female</option>
737
+ <option>Non-binary</option>
738
+ <option>Other</option>
739
+ </select>
740
+ </div>
741
+ </div>
742
+
743
+ <!-- Level and Background -->
744
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
745
+ <div>
746
+ <label class="block text-sm font-medium text-gray-300 mb-2">LEVEL</label>
747
+ <input type="range" id="character-level" min="1" max="20" value="1" class="w-full">
748
+ <div id="level-display" class="text-center text-sm font-medium text-gray-300">Level 1</div>
749
+ </div>
750
+ <div>
751
+ <label class="block text-sm font-medium text-gray-300 mb-2">BACKGROUND</label>
752
+ <select id="character-background" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
753
+ <option>Folk Hero</option>
754
+ <option>Acolyte</option>
755
+ <option>Criminal</option>
756
+ <option>Noble</option>
757
+ <option>Sage</option>
758
+ <option>Soldier</option>
759
+ <option>Entertainer</option>
760
+ <option>Guild Artisan</option>
761
+ <option>Hermit</option>
762
+ <option>Outlander</option>
763
+ <option>Sailor</option>
764
+ </select>
765
+ </div>
766
+ </div>
767
+
768
+ <!-- Backstory -->
769
+ <div class="mb-4">
770
+ <label class="block text-sm font-medium text-gray-300 mb-2">BACKSTORY</label>
771
+ <textarea id="character-backstory" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" rows="3" placeholder="Character background..."></textarea>
772
+ </div>
773
+
774
+ <button id="generate-backstory-btn" class="w-full px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 transition">
775
+ <i class="fas fa-book mr-2"></i> GENERATE BACKSTORY
776
+ </button>
777
+ </div>
778
+
779
+ <!-- Ability Scores -->
780
+ <div class="character-sheet p-6">
781
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
782
+ <i class="fas fa-dice-d20 mr-2"></i> ABILITY SCORES
783
+ </h3>
784
+
785
+ <div class="grid grid-cols-2 md:grid-cols-3 gap-4 mb-6">
786
+ <div class="ability-score p-4 text-center" data-ability="STR">
787
+ <div class="text-lg font-bold">STR</div>
788
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
789
+ <div class="text-sm ability-modifier">(+0)</div>
790
+ </div>
791
+ <div class="ability-score p-4 text-center" data-ability="DEX">
792
+ <div class="text-lg font-bold">DEX</div>
793
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
794
+ <div class="text-sm ability-modifier">(+0)</div>
795
+ </div>
796
+ <div class="ability-score p-4 text-center" data-ability="CON">
797
+ <div class="text-lg font-bold">CON</div>
798
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
799
+ <div class="text-sm ability-modifier">(+0)</div>
800
+ </div>
801
+ <div class="ability-score p-4 text-center" data-ability="INT">
802
+ <div class="text-lg font-bold">INT</div>
803
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
804
+ <div class="text-sm ability-modifier">(+0)</div>
805
+ </div>
806
+ <div class="ability-score p-4 text-center" data-ability="WIS">
807
+ <div class="text-lg font-bold">WIS</div>
808
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
809
+ <div class="text-sm ability-modifier">(+0)</div>
810
+ </div>
811
+ <div class="ability-score p-4 text-center" data-ability="CHA">
812
+ <div class="text-lg font-bold">CHA</div>
813
+ <div class="text-3xl font-bold my-2 ability-value">10</div>
814
+ <div class="text-sm ability-modifier">(+0)</div>
815
+ </div>
816
+ </div>
817
+
818
+ <button id="roll-abilities-btn" class="dice-roller w-full px-4 py-3 rounded-md font-bold">
819
+ <i class="fas fa-dice mr-2"></i> ROLL ABILITY SCORES
820
+ </button>
821
+ </div>
822
+ </div>
823
+
824
+ <!-- Portrait and Summary -->
825
+ <div class="space-y-6">
826
+ <!-- Portrait -->
827
+ <div class="character-sheet p-6">
828
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
829
+ <i class="fas fa-portrait mr-2"></i> PORTRAIT
830
+ </h3>
831
+ <div id="character-portrait" class="bg-gray-700 rounded-lg w-full h-64 flex items-center justify-center text-gray-400 mb-4">
832
+ <i class="fas fa-user fa-4x"></i>
833
+ </div>
834
+ <button id="generate-portrait-btn" class="dice-roller w-full px-4 py-2 rounded-md font-medium">
835
+ <i class="fas fa-magic mr-2"></i> GENERATE PORTRAIT
836
+ </button>
837
+ </div>
838
+
839
+ <!-- Character Summary -->
840
+ <div class="character-sheet p-6">
841
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
842
+ <i class="fas fa-scroll mr-2"></i> SUMMARY
843
+ </h3>
844
+ <div id="character-summary" class="output-box" style="min-height: 200px;">
845
+ <p class="text-gray-400 italic">Create character to see summary</p>
846
+ </div>
847
+ </div>
848
+ </div>
849
+ </div>
850
+ </div>
851
+
852
+ <!-- CAMPAIGN MANAGER TAB -->
853
+ <div id="campaign-manager" class="tab-content">
854
+ <h2 class="text-2xl font-bold text-purple-400 mb-6">
855
+ <i class="fas fa-scroll mr-2"></i> CAMPAIGN MANAGER
856
+ </h2>
857
+
858
+ <div class="agent-card mb-6">
859
+ <h3 class="text-xl font-semibold text-white mb-4">
860
+ <i class="fas fa-magic mr-2"></i> AI CAMPAIGN GENERATOR
861
+ </h3>
862
+
863
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
864
+ <div>
865
+ <div class="mb-4">
866
+ <label class="block text-sm font-medium text-white mb-2">CAMPAIGN THEME</label>
867
+ <select id="campaign-theme" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
868
+ <option>High Fantasy</option>
869
+ <option>Dark Fantasy</option>
870
+ <option>Urban Fantasy</option>
871
+ <option>Steampunk</option>
872
+ <option>Horror</option>
873
+ <option>Comedy</option>
874
+ <option>Political Intrigue</option>
875
+ <option>Exploration</option>
876
+ </select>
877
+ </div>
878
+
879
+ <div class="grid grid-cols-2 gap-4 mb-4">
880
+ <div>
881
+ <label class="block text-sm font-medium text-white mb-2">STARTING LEVEL</label>
882
+ <input type="range" id="campaign-level" min="1" max="20" value="5" class="w-full">
883
+ <div id="campaign-level-display" class="text-center text-sm font-medium text-white">Level 5</div>
884
+ </div>
885
+ <div>
886
+ <label class="block text-sm font-medium text-white mb-2">PLAYERS</label>
887
+ <input type="range" id="campaign-players" min="1" max="8" value="4" class="w-full">
888
+ <div id="campaign-players-display" class="text-center text-sm font-medium text-white">4 Players</div>
889
+ </div>
890
+ </div>
891
+
892
+ <button id="generate-campaign-btn" class="dice-roller w-full px-4 py-3 rounded-md font-bold mb-4">
893
+ <i class="fas fa-dice-d20 mr-2"></i> GENERATE CAMPAIGN
894
+ </button>
895
+ </div>
896
+
897
+ <div>
898
+ <div id="campaign-image" class="bg-gray-700 rounded-lg w-full h-48 flex items-center justify-center text-gray-400 mb-4">
899
+ <i class="fas fa-image fa-3x"></i>
900
+ </div>
901
+ <button id="generate-campaign-art-btn" class="w-full px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 transition">
902
+ <i class="fas fa-paint-brush mr-2"></i> GENERATE ART
903
+ </button>
904
+ </div>
905
+ </div>
906
+ </div>
907
+
908
+ <div class="output-box mb-6">
909
+ <h4 class="text-lg font-bold text-purple-300 mb-2">CAMPAIGN CONCEPT</h4>
910
+ <div id="campaign-output">
911
+ <p class="text-gray-400 italic">Generate a campaign to see the results</p>
912
+ </div>
913
+ </div>
914
+
915
+ <!-- Session Generator -->
916
+ <div class="agent-card">
917
+ <h3 class="text-xl font-semibold text-white mb-4">
918
+ <i class="fas fa-calendar mr-2"></i> SESSION GENERATOR
919
+ </h3>
920
+
921
+ <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-4">
922
+ <div>
923
+ <label class="block text-sm font-medium text-white mb-2">SESSION NUMBER</label>
924
+ <input type="number" id="session-number" min="1" value="1" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
925
+ </div>
926
+ <div class="md:col-span-3 flex items-end">
927
+ <button id="generate-session-btn" class="w-full px-4 py-2 bg-white text-purple-800 rounded-md hover:bg-gray-100 transition">
928
+ <i class="fas fa-scroll mr-2"></i> GENERATE SESSION CONTENT
929
+ </button>
930
+ </div>
931
+ </div>
932
+
933
+ <div class="output-box bg-white bg-opacity-20">
934
+ <h4 class="text-lg font-bold text-white mb-2">SESSION CONTENT</h4>
935
+ <div id="session-output">
936
+ <p class="text-white italic">Generate session content to see the results</p>
937
+ </div>
938
+ </div>
939
+ </div>
940
+ </div>
941
+
942
+ <!-- NPC CREATOR TAB -->
943
+ <div id="npc-creator" class="tab-content">
944
+ <h2 class="text-2xl font-bold text-purple-400 mb-6">
945
+ <i class="fas fa-users mr-2"></i> NPC CREATOR
946
+ </h2>
947
+
948
+ <div class="agent-card">
949
+ <h3 class="text-xl font-semibold text-white mb-4">
950
+ <i class="fas fa-user-plus mr-2"></i> AI NPC GENERATOR
951
+ </h3>
952
+
953
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
954
+ <div>
955
+ <div class="mb-4">
956
+ <label class="block text-sm font-medium text-white mb-2">CONTEXT</label>
957
+ <textarea id="npc-context" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white" rows="2" placeholder="Describe the setting or situation..."></textarea>
958
+ </div>
959
+
960
+ <div class="grid grid-cols-2 gap-4 mb-4">
961
+ <div>
962
+ <label class="block text-sm font-medium text-white mb-2">ROLE</label>
963
+ <select id="npc-role" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
964
+ <option>Ally</option>
965
+ <option>Neutral</option>
966
+ <option>Antagonist</option>
967
+ <option>Quest Giver</option>
968
+ <option>Merchant</option>
969
+ <option>Authority Figure</option>
970
+ <option>Mysterious Stranger</option>
971
+ </select>
972
+ </div>
973
+ <div>
974
+ <label class="block text-sm font-medium text-white mb-2">IMPORTANCE</label>
975
+ <select id="npc-importance" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
976
+ <option>Minor</option>
977
+ <option>Moderate</option>
978
+ <option>Major</option>
979
+ <option>Recurring</option>
980
+ </select>
981
+ </div>
982
+ </div>
983
+
984
+ <div class="mb-4">
985
+ <label class="block text-sm font-medium text-white mb-2">GENDER (Optional)</label>
986
+ <select id="npc-gender" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
987
+ <option value="">Random</option>
988
+ <option>Male</option>
989
+ <option>Female</option>
990
+ <option>Non-binary</option>
991
+ <option>Other</option>
992
+ </select>
993
+ </div>
994
+
995
+ <button id="create-npc-btn" class="dice-roller w-full px-4 py-3 rounded-md font-bold">
996
+ <i class="fas fa-user-plus mr-2"></i> GENERATE NPC
997
+ </button>
998
+ </div>
999
+
1000
+ <div>
1001
+ <div class="output-box" style="min-height: 300px;">
1002
+ <h4 class="text-lg font-bold text-purple-300 mb-2">GENERATED NPC</h4>
1003
+ <div id="npc-output">
1004
+ <p class="text-gray-400 italic">Generate an NPC to see the results</p>
1005
+ </div>
1006
+ </div>
1007
+ </div>
1008
+ </div>
1009
+ </div>
1010
+ </div>
1011
+
1012
+ <!-- RANDOM TOOLS TAB -->
1013
+ <div id="random-tools" class="tab-content">
1014
+ <h2 class="text-2xl font-bold text-purple-400 mb-6">
1015
+ <i class="fas fa-dice mr-2"></i> RANDOM GENERATORS
1016
+ </h2>
1017
+
1018
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
1019
+ <!-- Name Generator -->
1020
+ <div class="character-sheet p-6">
1021
+ <h3 class="text-xl font-semibold text-gray-300 mb-4">
1022
+ <i class="fas fa-signature mr-2"></i> NAME GENERATOR
1023
+ </h3>
1024
+
1025
+ <div class="mb-4">
1026
+ <label class="block text-sm font-medium text-gray-300 mb-2">NAME TYPE</label>
1027
+ <select id="name-type" class="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white">
1028
+ <option>Human Male</option>
1029
+ <option>Human Female</option>
1030
+ <option>Elven</option>
1031
+ <option>Dwar