Isaiahsouf commited on
Commit
3f1f9e2
·
verified ·
1 Parent(s): 407505b

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1070 -19
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Dnd 5e Character Creator
3
- emoji: 🐨
4
- colorFrom: green
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: dnd-5e-character-creator
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1070 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 5e Random Character Generator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
9
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ body {
12
+ font-family: 'Roboto', sans-serif;
13
+ background-color: #f5f5f5;
14
+ color: #212121;
15
+ }
16
+
17
+ .card {
18
+ background-color: white;
19
+ border-radius: 8px;
20
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
21
+ transition: all 0.3s ease;
22
+ }
23
+
24
+ .card:hover {
25
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
26
+ transform: translateY(-2px);
27
+ }
28
+
29
+ .stat-block {
30
+ background-color: #f5f5f5;
31
+ border-radius: 4px;
32
+ transition: all 0.3s ease;
33
+ }
34
+
35
+ .stat-block:hover {
36
+ background-color: #e0e0e0;
37
+ }
38
+
39
+ .btn-primary {
40
+ background-color: #212121;
41
+ color: white;
42
+ transition: all 0.3s ease;
43
+ }
44
+
45
+ .btn-primary:hover {
46
+ background-color: #424242;
47
+ transform: translateY(-2px);
48
+ }
49
+
50
+ .btn-secondary {
51
+ background-color: #e0e0e0;
52
+ color: #212121;
53
+ transition: all 0.3s ease;
54
+ }
55
+
56
+ .btn-secondary:hover {
57
+ background-color: #bdbdbd;
58
+ transform: translateY(-2px);
59
+ }
60
+
61
+ .tab-active {
62
+ border-bottom: 2px solid #212121;
63
+ font-weight: 500;
64
+ }
65
+
66
+ @keyframes fadeIn {
67
+ from { opacity: 0; transform: translateY(10px); }
68
+ to { opacity: 1; transform: translateY(0); }
69
+ }
70
+
71
+ .animate-fade-in {
72
+ animation: fadeIn 0.4s ease-out forwards;
73
+ }
74
+
75
+ @keyframes pulse {
76
+ 0% { transform: scale(1); }
77
+ 50% { transform: scale(1.05); }
78
+ 100% { transform: scale(1); }
79
+ }
80
+
81
+ .animate-pulse {
82
+ animation: pulse 0.5s ease-in-out;
83
+ }
84
+
85
+ .material-icons {
86
+ vertical-align: middle;
87
+ }
88
+
89
+ @keyframes spin {
90
+ 0% { transform: rotate(0deg); }
91
+ 100% { transform: rotate(360deg); }
92
+ }
93
+
94
+ .animate-spin {
95
+ animation: spin 1s linear infinite;
96
+ }
97
+ </style>
98
+ </head>
99
+ <body class="min-h-screen py-8 px-4">
100
+ <div class="max-w-6xl mx-auto">
101
+ <header class="text-center mb-8">
102
+ <h1 class="text-3xl md:text-4xl font-bold mb-2">D&D 5e Character Generator</h1>
103
+ <p class="text-gray-600">Create your next adventurer with a single click</p>
104
+ </header>
105
+
106
+ <div class="flex flex-wrap gap-3 mb-6 justify-center">
107
+ <button id="generateAll" class="btn-primary px-6 py-3 rounded-lg font-medium flex items-center gap-2">
108
+ <span class="material-icons">casino</span> Generate Full Character
109
+ </button>
110
+ <button id="generateStats" class="btn-secondary px-4 py-2 rounded-lg font-medium flex items-center gap-2">
111
+ <span class="material-icons">swap_vert</span> Reroll Stats
112
+ </button>
113
+ <button id="generateVisuals" class="btn-secondary px-4 py-2 rounded-lg font-medium flex items-center gap-2">
114
+ <span class="material-icons">palette</span> Reroll Appearance
115
+ </button>
116
+ <button id="saveCharacter" class="btn-primary px-4 py-2 rounded-lg font-medium flex items-center gap-2">
117
+ <span class="material-icons">save</span> Save Character
118
+ </button>
119
+ </div>
120
+
121
+ <div class="card p-6 mb-8">
122
+ <div class="flex border-b border-gray-200 mb-6">
123
+ <button class="tab tab-active px-4 py-2 mr-2" data-tab="basic">
124
+ <span class="material-icons mr-1">person</span> Basic Info
125
+ </button>
126
+ <button class="tab px-4 py-2 mr-2" data-tab="stats">
127
+ <span class="material-icons mr-1">assessment</span> Stats & Skills
128
+ </button>
129
+ <button class="tab px-4 py-2" data-tab="equipment">
130
+ <span class="material-icons mr-1">backpack</span> Equipment
131
+ </button>
132
+ </div>
133
+
134
+ <div id="basicTab" class="tab-content">
135
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
136
+ <div class="card p-4">
137
+ <h3 class="font-medium text-lg mb-3 flex items-center">
138
+ <span class="material-icons mr-2">badge</span> Character
139
+ </h3>
140
+ <div class="space-y-2">
141
+ <p><span class="font-medium">Name:</span> <span id="charName">-</span></p>
142
+ <p><span class="font-medium">Race:</span> <span id="race">-</span></p>
143
+ <p><span class="font-medium">Subrace:</span> <span id="subrace">-</span></p>
144
+ <p><span class="font-medium">Class:</span> <span id="class">-</span></p>
145
+ <p><span class="font-medium">Subclass:</span> <span id="subclass">-</span></p>
146
+ <p><span class="font-medium">Level:</span> <span id="level">1</span></p>
147
+ </div>
148
+ </div>
149
+
150
+ <div class="card p-4">
151
+ <h3 class="font-medium text-lg mb-3 flex items-center">
152
+ <span class="material-icons mr-2">history_edu</span> Background
153
+ </h3>
154
+ <div class="space-y-2">
155
+ <p><span class="font-medium">Background:</span> <span id="background">-</span></p>
156
+ <p><span class="font-medium">Alignment:</span> <span id="alignment">-</span></p>
157
+ <p><span class="font-medium">Personality:</span> <span id="personality">-</span></p>
158
+ <p><span class="font-medium">Ideal:</span> <span id="ideal">-</span></p>
159
+ <p><span class="font-medium">Bond:</span> <span id="bond">-</span></p>
160
+ <p><span class="font-medium">Flaw:</span> <span id="flaw">-</span></p>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
166
+ <div class="card p-4">
167
+ <h3 class="font-medium text-lg mb-3 flex items-center">
168
+ <span class="material-icons mr-2">accessibility</span> Physical Traits
169
+ </h3>
170
+ <div class="grid grid-cols-2 gap-2">
171
+ <p><span class="font-medium">Age:</span> <span id="age">-</span></p>
172
+ <p><span class="font-medium">Height:</span> <span id="height">-</span></p>
173
+ <p><span class="font-medium">Weight:</span> <span id="weight">-</span></p>
174
+ <p><span class="font-medium">Eyes:</span> <span id="eyes">-</span></p>
175
+ <p><span class="font-medium">Skin:</span> <span id="skin">-</span></p>
176
+ <p><span class="font-medium">Hair:</span> <span id="hair">-</span></p>
177
+ </div>
178
+ </div>
179
+
180
+ <div class="card p-4">
181
+ <h3 class="font-medium text-lg mb-3 flex items-center">
182
+ <span class="material-icons mr-2">star</span> Distinctive Features
183
+ </h3>
184
+ <p id="distinctive">-</p>
185
+ </div>
186
+ </div>
187
+
188
+ <div class="card p-4">
189
+ <h3 class="font-medium text-lg mb-3 flex items-center">
190
+ <span class="material-icons mr-2">menu_book</span> Backstory
191
+ </h3>
192
+ <p id="backstory" class="text-gray-700">Your character's unique backstory will appear here...</p>
193
+ </div>
194
+ </div>
195
+
196
+ <div id="statsTab" class="tab-content hidden">
197
+ <div class="grid grid-cols-2 md:grid-cols-6 gap-3 mb-6">
198
+ <div class="stat-block p-3 text-center">
199
+ <div class="text-xs uppercase tracking-wider text-gray-600">Strength</div>
200
+ <div class="text-3xl font-medium" id="str">10</div>
201
+ <div class="text-sm" id="strMod">+0</div>
202
+ </div>
203
+ <div class="stat-block p-3 text-center">
204
+ <div class="text-xs uppercase tracking-wider text-gray-600">Dexterity</div>
205
+ <div class="text-3xl font-medium" id="dex">10</div>
206
+ <div class="text-sm" id="dexMod">+0</div>
207
+ </div>
208
+ <div class="stat-block p-3 text-center">
209
+ <div class="text-xs uppercase tracking-wider text-gray-600">Constitution</div>
210
+ <div class="text-3xl font-medium" id="con">10</div>
211
+ <div class="text-sm" id="conMod">+0</div>
212
+ </div>
213
+ <div class="stat-block p-3 text-center">
214
+ <div class="text-xs uppercase tracking-wider text-gray-600">Intelligence</div>
215
+ <div class="text-3xl font-medium" id="int">10</div>
216
+ <div class="text-sm" id="intMod">+0</div>
217
+ </div>
218
+ <div class="stat-block p-3 text-center">
219
+ <div class="text-xs uppercase tracking-wider text-gray-600">Wisdom</div>
220
+ <div class="text-3xl font-medium" id="wis">10</div>
221
+ <div class="text-sm" id="wisMod">+0</div>
222
+ </div>
223
+ <div class="stat-block p-3 text-center">
224
+ <div class="text-xs uppercase tracking-wider text-gray-600">Charisma</div>
225
+ <div class="text-3xl font-medium" id="cha">10</div>
226
+ <div class="text-sm" id="chaMod">+0</div>
227
+ </div>
228
+ </div>
229
+
230
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
231
+ <div class="card p-4">
232
+ <h3 class="font-medium text-lg mb-3 flex items-center">
233
+ <span class="material-icons mr-2">check_circle</span> Proficiencies
234
+ </h3>
235
+ <ul id="proficiencies" class="list-disc pl-5 space-y-1">
236
+ <li>None generated yet</li>
237
+ </ul>
238
+ </div>
239
+ <div class="card p-4">
240
+ <h3 class="font-medium text-lg mb-3 flex items-center">
241
+ <span class="material-icons mr-2">auto_awesome</span> Features & Traits
242
+ </h3>
243
+ <ul id="features" class="list-disc pl-5 space-y-1">
244
+ <li>None generated yet</li>
245
+ </ul>
246
+ </div>
247
+ </div>
248
+ </div>
249
+
250
+ <div id="equipmentTab" class="tab-content hidden">
251
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
252
+ <div class="card p-4">
253
+ <h3 class="font-medium text-lg mb-3 flex items-center">
254
+ <span class="material-icons mr-2">shield</span> Equipment
255
+ </h3>
256
+ <ul id="equipmentList" class="list-disc pl-5 space-y-1">
257
+ <li>None generated yet</li>
258
+ </ul>
259
+ </div>
260
+ <div class="card p-4">
261
+ <h3 class="font-medium text-lg mb-3 flex items-center">
262
+ <span class="material-icons mr-2">auto_fix_high</span> Spells
263
+ </h3>
264
+ <ul id="spellsList" class="list-disc pl-5 space-y-1">
265
+ <li>None generated yet</li>
266
+ </ul>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="text-center text-gray-600">
273
+ <p>Click the dice to generate your next D&D 5e character!</p>
274
+ </div>
275
+ </div>
276
+
277
+ <script>
278
+ // Data for character generation
279
+ const races = [
280
+ "Dragonborn", "Dwarf", "Elf", "Gnome", "Half-Elf",
281
+ "Halfling", "Half-Orc", "Human", "Tiefling"
282
+ ];
283
+
284
+ const subraces = {
285
+ "Dragonborn": ["Black", "Blue", "Brass", "Bronze", "Copper", "Gold", "Green", "Red", "Silver", "White"],
286
+ "Dwarf": ["Hill Dwarf", "Mountain Dwarf"],
287
+ "Elf": ["High Elf", "Wood Elf", "Dark Elf (Drow)"],
288
+ "Gnome": ["Forest Gnome", "Rock Gnome"],
289
+ "Half-Elf": ["Standard", "Aquatic", "Drow", "Wood Elf"],
290
+ "Halfling": ["Lightfoot", "Stout"],
291
+ "Half-Orc": ["Standard"],
292
+ "Human": ["Standard", "Variant"],
293
+ "Tiefling": ["Asmodeus", "Baalzebul", "Dispater", "Fierna", "Glasya", "Levistus", "Mammon", "Mephistopheles", "Zariel"]
294
+ };
295
+
296
+ const classes = [
297
+ "Barbarian", "Bard", "Cleric", "Druid", "Fighter",
298
+ "Monk", "Paladin", "Ranger", "Rogue", "Sorcerer",
299
+ "Warlock", "Wizard"
300
+ ];
301
+
302
+ const subclasses = {
303
+ "Barbarian": ["Path of the Berserker", "Path of the Totem Warrior", "Path of the Ancestral Guardian", "Path of the Storm Herald", "Path of the Zealot"],
304
+ "Bard": ["College of Lore", "College of Valor", "College of Glamour", "College of Swords", "College of Whispers"],
305
+ "Cleric": ["Knowledge Domain", "Life Domain", "Light Domain", "Nature Domain", "Tempest Domain", "Trickery Domain", "War Domain", "Forge Domain", "Grave Domain"],
306
+ "Druid": ["Circle of the Land", "Circle of the Moon", "Circle of Dreams", "Circle of the Shepherd", "Circle of Spores"],
307
+ "Fighter": ["Champion", "Battle Master", "Eldritch Knight", "Arcane Archer", "Cavalier", "Samurai"],
308
+ "Monk": ["Way of the Open Hand", "Way of Shadow", "Way of the Four Elements", "Way of the Drunken Master", "Way of the Kensei", "Way of the Sun Soul"],
309
+ "Paladin": ["Oath of Devotion", "Oath of the Ancients", "Oath of Vengeance", "Oath of Conquest", "Oath of Redemption", "Oathbreaker"],
310
+ "Ranger": ["Hunter", "Beast Master", "Gloom Stalker", "Horizon Walker", "Monster Slayer"],
311
+ "Rogue": ["Thief", "Assassin", "Arcane Trickster", "Mastermind", "Swashbuckler", "Inquisitive", "Scout"],
312
+ "Sorcerer": ["Draconic Bloodline", "Wild Magic", "Storm Sorcery", "Shadow Magic", "Divine Soul"],
313
+ "Warlock": ["The Archfey", "The Fiend", "The Great Old One", "The Celestial", "The Hexblade"],
314
+ "Wizard": ["School of Abjuration", "School of Conjuration", "School of Divination", "School of Enchantment", "School of Evocation", "School of Illusion", "School of Necromancy", "School of Transmutation", "War Magic"]
315
+ };
316
+
317
+ const backgrounds = [
318
+ "Acolyte", "Charlatan", "Criminal", "Entertainer", "Folk Hero",
319
+ "Guild Artisan", "Hermit", "Noble", "Outlander", "Sage",
320
+ "Sailor", "Soldier", "Urchin"
321
+ ];
322
+
323
+ const alignments = [
324
+ "Lawful Good", "Neutral Good", "Chaotic Good",
325
+ "Lawful Neutral", "True Neutral", "Chaotic Neutral",
326
+ "Lawful Evil", "Neutral Evil", "Chaotic Evil"
327
+ ];
328
+
329
+ // Enhanced name generation system
330
+ const namePrefixes = {
331
+ "male": ["Al", "Bal", "Cor", "Dain", "Ed", "Fal", "Gar", "Hal", "Ian", "Jor", "Kal", "Lor", "Mal", "Nor", "Oth", "Pal", "Quin", "Ral", "Sor", "Tal", "Ul", "Val", "Wil", "Xan", "Yor", "Zan"],
332
+ "female": ["Ael", "Bri", "Cer", "Dae", "Eli", "Fae", "Gwy", "Hel", "Iri", "Jas", "Kyl", "Lil", "Mae", "Nym", "Ori", "Pha", "Quel", "Rae", "Syl", "Tae", "Una", "Vyl", "Wyn", "Xyl", "Yll", "Zyl"],
333
+ "neutral": ["Aer", "Ber", "Cyr", "Dru", "Ere", "Fyr", "Gry", "Hyr", "Ith", "Jyr", "Kyr", "Lyr", "Myr", "Nyr", "Ory", "Pyr", "Qyr", "Ryr", "Syr", "Tyr", "Ury", "Vyr", "Wyr", "Xyr", "Yyr", "Zyr"]
334
+ };
335
+
336
+ const nameSuffixes = {
337
+ "male": ["dor", "fin", "gar", "horn", "ian", "jar", "kor", "lin", "mar", "nor", "or", "par", "quin", "rik", "sar", "tor", "ur", "var", "win", "xor", "yor", "zar"],
338
+ "female": ["ara", "belle", "cyn", "delle", "elle", "fina", "gwen", "halla", "ira", "jara", "kala", "lyra", "mira", "nara", "ora", "pia", "quira", "ria", "sira", "tira", "ura", "vira", "wina", "xira", "yra", "zira"],
339
+ "neutral": ["an", "ban", "can", "dan", "en", "fan", "gan", "han", "ian", "jan", "kan", "lan", "man", "nan", "on", "pan", "qan", "ran", "san", "tan", "uan", "van", "wan", "xan", "yan", "zan"]
340
+ };
341
+
342
+ const surnamePrefixes = ["Black", "Bright", "Copper", "Dark", "Ember", "Frost", "Gold", "Hollow", "Iron", "Jade", "King", "Long", "Moon", "Night", "Oak", "Proud"];
343
+ const surnameSuffixes = ["wood", "shield", "water", "hold", "mane", "way", "root", "helm", "ford", "shadow", "shade", "breeze", "leaf", "more"];
344
+
345
+ const titlePrefixes = ["The", "Sir", "Lady", "Master", "Dame", "Lord", "Captain", "Baron", "Count", "Duke"];
346
+ const titleSuffixes = ["Brave", "Wise", "Strong", "Swift", "Clever", "Mighty", "Noble", "Fair", "Just", "Valiant"];
347
+
348
+ const namePatterns = [
349
+ // Single name patterns
350
+ () => getRandomItem(["The ", ""]) + generateNamePart("neutral"),
351
+ () => generateNamePart("male") + getRandomItem([" the ", " of ", " from "]) + getRandomItem([generatePlaceName(), generateTitle()]),
352
+ () => generateNamePart("female") + getRandomItem([" the ", " of ", " from "]) + getRandomItem([generatePlaceName(), generateTitle()]),
353
+
354
+ // First + last name patterns
355
+ () => generateNamePart("male") + " " + generateSurname(),
356
+ () => generateNamePart("female") + " " + generateSurname(),
357
+ () => generateNamePart("neutral") + " " + generateSurname(),
358
+
359
+ // Compound names
360
+ () => generateNamePart("male") + getRandomItem(["", "-"]) + generateNamePart("male"),
361
+ () => generateNamePart("female") + getRandomItem(["", "-"]) + generateNamePart("female"),
362
+
363
+ // Title + name patterns
364
+ () => getRandomItem(titlePrefixes) + " " + generateNamePart("male"),
365
+ () => getRandomItem(titlePrefixes) + " " + generateNamePart("female"),
366
+ () => generateNamePart("male") + " " + getRandomItem(titleSuffixes),
367
+ () => generateNamePart("female") + " " + getRandomItem(titleSuffixes)
368
+ ];
369
+
370
+ function generateNamePart(gender) {
371
+ const prefix = getRandomItem(namePrefixes[gender]);
372
+ const suffix = getRandomItem(nameSuffixes[gender]);
373
+
374
+ // Sometimes add an extra syllable or modify the name
375
+ if (Math.random() > 0.7) {
376
+ const extra = getRandomItem(["a", "e", "i", "o", "u", "ar", "el", "in", "or", "yn"]);
377
+ return prefix + extra + suffix;
378
+ }
379
+
380
+ return prefix + suffix;
381
+ }
382
+
383
+ function generateSurname() {
384
+ const prefix = getRandomItem(surnamePrefixes);
385
+ const suffix = getRandomItem(surnameSuffixes);
386
+
387
+ // Sometimes combine two prefixes or suffixes
388
+ if (Math.random() > 0.6) {
389
+ const extraPrefix = getRandomItem(surnamePrefixes);
390
+ return prefix + extraPrefix + suffix;
391
+ }
392
+
393
+ return prefix + suffix;
394
+ }
395
+
396
+ function generatePlaceName() {
397
+ const places = ["the Mountains", "the Forest", "the Vale", "the Hills", "the River", "the Sea", "the North", "the South", "the East", "the West"];
398
+ return getRandomItem(places);
399
+ }
400
+
401
+ function generateTitle() {
402
+ return getRandomItem(titleSuffixes);
403
+ }
404
+
405
+ function generateCharacterName(gender) {
406
+ // Choose a random naming pattern
407
+ const pattern = getRandomItem(namePatterns);
408
+ return pattern();
409
+ }
410
+
411
+ const personalityTraits = [
412
+ "I idolize a particular hero of my faith and constantly refer to that person's deeds and example.",
413
+ "I can find common ground between the fiercest enemies, empathizing with them and always working toward peace.",
414
+ "I see omens in every event and action. The gods try to speak to us, we just need to listen.",
415
+ "Nothing can shake my optimistic attitude.",
416
+ "I quote (or misquote) sacred texts and proverbs in almost every situation.",
417
+ "I am tolerant (or intolerant) of other faiths and respect (or condemn) the worship of other gods.",
418
+ "I've enjoyed fine food, drink, and high society among my temple's elite. Rough living grates on me.",
419
+ "I've spent so long in the temple that I have little practical experience dealing with people in the outside world."
420
+ ];
421
+
422
+ const ideals = [
423
+ "Tradition. The ancient traditions of worship and sacrifice must be preserved and upheld. (Lawful)",
424
+ "Charity. I always try to help those in need, no matter what the personal cost. (Good)",
425
+ "Change. We must help bring about the changes the gods are constantly working in the world. (Chaotic)",
426
+ "Power. I hope to one day rise to the top of my faith's religious hierarchy. (Lawful)",
427
+ "Faith. I trust that my deity will guide my actions. I have faith that if I work hard, things will go well. (Lawful)",
428
+ "Aspiration. I seek to prove myself worthy of my god's favor by matching my actions against his or her teachings. (Any)"
429
+ ];
430
+
431
+ const bonds = [
432
+ "I would die to recover an ancient relic of my faith that was lost long ago.",
433
+ "I will someday get revenge on the corrupt temple hierarchy who branded me a heretic.",
434
+ "I owe my life to the priest who took me in when my parents died.",
435
+ "Everything I do is for the common people.",
436
+ "I will do anything to protect the temple where I served.",
437
+ "I seek to preserve a sacred text that my enemies consider heretical and seek to destroy."
438
+ ];
439
+
440
+ const flaws = [
441
+ "I judge others harshly, and myself even more severely.",
442
+ "I put too much trust in those who wield power within my temple's hierarchy.",
443
+ "My piety sometimes leads me to blindly trust those that profess faith in my god.",
444
+ "I am inflexible in my thinking.",
445
+ "I am suspicious of strangers and expect the worst of them.",
446
+ "Once I pick a goal, I become obsessed with it to the detriment of everything else in my life."
447
+ ];
448
+
449
+ const eyeColors = ["Amber", "Blue", "Brown", "Gray", "Green", "Hazel", "Red", "Violet", "Yellow"];
450
+ const skinColors = ["Pale", "Fair", "Light", "Medium", "Olive", "Tan", "Brown", "Dark", "Ebony", "Gray", "Blue", "Green"];
451
+ const hairColors = ["Black", "Brown", "Blonde", "Red", "White", "Gray", "Auburn", "Chestnut", "Silver", "Blue", "Green"];
452
+ const hairStyles = ["Short", "Long", "Curly", "Straight", "Wavy", "Bald", "Braided", "Ponytail", "Mohawk", "Dreadlocks"];
453
+
454
+ const distinctiveFeatures = [
455
+ "Scar across the face", "Missing finger", "Tattoos covering arms", "Piercings", "Unusual birthmark",
456
+ "Heterochromia (different colored eyes)", "Limp", "Crooked nose", "Unusually tall/short", "Distinctive voice",
457
+ "Always wears a specific color", "Always carries a particular item", "Unusual jewelry", "Memorable laugh"
458
+ ];
459
+
460
+ // Equipment lists
461
+ const weapons = {
462
+ "Simple Melee": ["Club", "Dagger", "Greatclub", "Handaxe", "Javelin", "Light hammer", "Mace", "Quarterstaff", "Sickle", "Spear"],
463
+ "Simple Ranged": ["Light crossbow", "Dart", "Shortbow", "Sling"],
464
+ "Martial Melee": ["Battleaxe", "Flail", "Glaive", "Greataxe", "Greatsword", "Halberd", "Lance", "Longsword", "Maul", "Morningstar", "Pike", "Rapier", "Scimitar", "Shortsword", "Trident", "War pick", "Warhammer", "Whip"],
465
+ "Martial Ranged": ["Blowgun", "Hand crossbow", "Heavy crossbow", "Longbow", "Net"]
466
+ };
467
+
468
+ const armor = {
469
+ "Light": ["Padded", "Leather", "Studded leather"],
470
+ "Medium": ["Hide", "Chain shirt", "Scale mail", "Breastplate", "Half plate"],
471
+ "Heavy": ["Ring mail", "Chain mail", "Splint", "Plate"],
472
+ "Shields": ["Shield"]
473
+ };
474
+
475
+ const adventuringGear = [
476
+ "Backpack", "Bedroll", "Bell", "Blanket", "Block and tackle", "Book", "Candle", "Case (map/scroll)", "Chain (10 feet)", "Chalk", "Chest", "Climber's kit",
477
+ "Clothes (common)", "Clothes (costume)", "Clothes (fine)", "Clothes (traveler's)", "Component pouch", "Crowbar", "Fishing tackle", "Flask", "Grappling hook",
478
+ "Hammer", "Healer's kit", "Holy symbol", "Hourglass", "Ink (1 oz. bottle)", "Ink pen", "Ladder (10-foot)", "Lantern", "Lock", "Magnifying glass", "Manacles",
479
+ "Mess kit", "Mirror (steel)", "Oil (flask)", "Paper (one sheet)", "Parchment (one sheet)", "Perfume (vial)", "Pick (miner's)", "Piton", "Pole (10-foot)",
480
+ "Pot (iron)", "Potion of healing", "Pouch", "Quiver", "Ram (portable)", "Rations (1 day)", "Robes", "Rope (hempen, 50 feet)", "Rope (silk, 50 feet)",
481
+ "Sack", "Scale (merchant's)", "Sealing wax", "Shovel", "Signal whistle", "Signet ring", "Soap", "Spellbook", "Spikes (iron)", "Spyglass", "Tent (two-person)",
482
+ "Tinderbox", "Torch", "Vial", "Waterskin", "Whetstone"
483
+ ];
484
+
485
+ // Utility functions
486
+ function getRandomInt(min, max) {
487
+ return Math.floor(Math.random() * (max - min + 1)) + min;
488
+ }
489
+
490
+ function getRandomItem(array) {
491
+ return array[Math.floor(Math.random() * array.length)];
492
+ }
493
+
494
+ function getRandomItems(array, count) {
495
+ const shuffled = [...array].sort(() => 0.5 - Math.random());
496
+ return shuffled.slice(0, count);
497
+ }
498
+
499
+ function calculateModifier(score) {
500
+ return Math.floor((score - 10) / 2);
501
+ }
502
+
503
+ function rollStats() {
504
+ // Roll 4d6, drop lowest, sum remaining
505
+ const stats = [];
506
+ for (let i = 0; i < 6; i++) {
507
+ const rolls = [
508
+ getRandomInt(1, 6),
509
+ getRandomInt(1, 6),
510
+ getRandomInt(1, 6),
511
+ getRandomInt(1, 6)
512
+ ];
513
+ rolls.sort((a, b) => a - b);
514
+ const sum = rolls[1] + rolls[2] + rolls[3];
515
+ stats.push(sum);
516
+ }
517
+ return stats;
518
+ }
519
+
520
+ function generateCharacter() {
521
+ // Add loading animation to generate button
522
+ const generateBtn = document.getElementById('generateAll');
523
+ generateBtn.innerHTML = '<span class="material-icons animate-spin">autorenew</span> Generating...';
524
+ generateBtn.classList.add('cursor-not-allowed');
525
+
526
+ // Simulate loading with timeout
527
+ setTimeout(() => {
528
+ // Basic info
529
+ const race = getRandomItem(races);
530
+ const subrace = getRandomItem(subraces[race]);
531
+ const charClass = getRandomItem(classes);
532
+ const subclass = getRandomItem(subclasses[charClass]);
533
+ const background = getRandomItem(backgrounds);
534
+ const alignment = getRandomItem(alignments);
535
+
536
+ // Generate unique name
537
+ const gender = Math.random() > 0.5 ? "male" : "female";
538
+ const name = generateCharacterName(gender);
539
+
540
+ // Stats
541
+ const stats = rollStats();
542
+ const str = stats[0];
543
+ const dex = stats[1];
544
+ const con = stats[2];
545
+ const int = stats[3];
546
+ const wis = stats[4];
547
+ const cha = stats[5];
548
+
549
+ // Modifiers
550
+ const strMod = calculateModifier(str);
551
+ const dexMod = calculateModifier(dex);
552
+ const conMod = calculateModifier(con);
553
+ const intMod = calculateModifier(int);
554
+ const wisMod = calculateModifier(wis);
555
+ const chaMod = calculateModifier(cha);
556
+
557
+ // Background details
558
+ const personality = getRandomItem(personalityTraits);
559
+ const ideal = getRandomItem(ideals);
560
+ const bond = getRandomItem(bonds);
561
+ const flaw = getRandomItem(flaws);
562
+
563
+ // Physical traits
564
+ const age = getRandomInt(16, 80);
565
+ const height = getRandomInt(48, 96); // in inches
566
+ const weight = getRandomInt(90, 300); // in pounds
567
+ const eyes = getRandomItem(eyeColors);
568
+ const skin = getRandomItem(skinColors);
569
+ const hair = `${getRandomItem(hairColors)}, ${getRandomItem(hairStyles)}`;
570
+ const distinctive = getRandomItem(distinctiveFeatures);
571
+
572
+ // Generate backstory
573
+ const backstory = generateBackstory(name, race, subrace, charClass, background);
574
+
575
+ // Generate equipment
576
+ const equipment = generateEquipment(charClass, background);
577
+
578
+ // Generate proficiencies and features
579
+ const proficiencies = generateProficiencies(charClass, race, background);
580
+ const features = generateFeatures(charClass, race, background);
581
+
582
+ // Generate spells if applicable
583
+ const spells = generateSpells(charClass);
584
+
585
+ // Update the UI
586
+ updateCharacterSheet({
587
+ name, race, subrace, charClass, subclass, background, alignment,
588
+ str, dex, con, int, wis, cha,
589
+ strMod, dexMod, conMod, intMod, wisMod, chaMod,
590
+ personality, ideal, bond, flaw,
591
+ age, height, weight, eyes, skin, hair, distinctive,
592
+ backstory, equipment, proficiencies, features, spells
593
+ });
594
+
595
+ // Reset generate button
596
+ generateBtn.innerHTML = '<span class="material-icons">casino</span> Generate Full Character';
597
+ generateBtn.classList.remove('cursor-not-allowed');
598
+
599
+ // Add pulse animation to card
600
+ document.querySelector('.card').classList.add('animate-pulse');
601
+ setTimeout(() => {
602
+ document.querySelector('.card').classList.remove('animate-pulse');
603
+ }, 500);
604
+
605
+ }, 800); // Simulated loading time
606
+ }
607
+
608
+ function generateBackstory(name, race, subrace, charClass, background) {
609
+ const locations = [
610
+ "a small village", "a bustling city", "a remote monastery", "a nomadic tribe",
611
+ "a coastal town", "a mountain fortress", "a forest settlement", "an underground city"
612
+ ];
613
+
614
+ const events = [
615
+ "a terrible plague", "a devastating war", "a natural disaster", "a political upheaval",
616
+ "a magical catastrophe", "an economic collapse", "a religious schism", "a monster invasion"
617
+ ];
618
+
619
+ const motivations = [
620
+ "seek revenge", "find redemption", "discover the truth", "protect the innocent",
621
+ "gain power", "explore the world", "fulfill a prophecy", "escape their past"
622
+ ];
623
+
624
+ const location = getRandomItem(locations);
625
+ const event = getRandomItem(events);
626
+ const motivation = getRandomItem(motivations);
627
+
628
+ return `${name} is a ${race} ${charClass.toLowerCase()} from ${location}. Growing up as ${subrace.toLowerCase()}, they witnessed ${event} which shaped their worldview. Now they adventure to ${motivation}.`;
629
+ }
630
+
631
+ function generateEquipment(charClass, background) {
632
+ let equipment = [];
633
+
634
+ // Add weapons based on class
635
+ if (["Fighter", "Paladin", "Ranger"].includes(charClass)) {
636
+ equipment.push(getRandomItem(weapons["Martial Melee"]));
637
+ equipment.push(getRandomItem(weapons["Martial Ranged"]));
638
+ } else if (["Barbarian", "Monk", "Rogue"].includes(charClass)) {
639
+ equipment.push(getRandomItem(weapons["Simple Melee"]));
640
+ equipment.push(getRandomItem(weapons["Simple Ranged"]));
641
+ } else if (["Wizard", "Sorcerer"].includes(charClass)) {
642
+ equipment.push(getRandomItem(weapons["Simple Melee"]));
643
+ } else {
644
+ // Bard, Cleric, Druid, Warlock
645
+ equipment.push(getRandomItem([...weapons["Simple Melee"], ...weapons["Simple Ranged"]]));
646
+ }
647
+
648
+ // Add armor based on class
649
+ if (["Fighter", "Paladin"].includes(charClass)) {
650
+ equipment.push(getRandomItem(armor["Heavy"]));
651
+ equipment.push(getRandomItem(armor["Shields"]));
652
+ } else if (["Cleric", "Ranger"].includes(charClass)) {
653
+ equipment.push(getRandomItem(armor["Medium"]));
654
+ } else if (["Rogue", "Bard"].includes(charClass)) {
655
+ equipment.push(getRandomItem(armor["Light"]));
656
+ }
657
+
658
+ // Add background equipment
659
+ if (background === "Acolyte") {
660
+ equipment.push("Holy symbol", "Prayer book", "Incense");
661
+ } else if (background === "Criminal") {
662
+ equipment.push("Crowbar", "Dark common clothes with hood");
663
+ } else if (background === "Folk Hero") {
664
+ equipment.push("Artisan's tools", "Shovel");
665
+ } else if (background === "Noble") {
666
+ equipment.push("Fine clothes", "Signet ring");
667
+ } else if (background === "Soldier") {
668
+ equipment.push("Insignia of rank", "Trophy from a fallen enemy");
669
+ }
670
+
671
+ // Add some random adventuring gear
672
+ equipment = [...equipment, ...getRandomItems(adventuringGear, 3)];
673
+
674
+ return equipment;
675
+ }
676
+
677
+ function generateProficiencies(charClass, race, background) {
678
+ let proficiencies = [];
679
+
680
+ // Class proficiencies
681
+ if (["Fighter", "Paladin", "Ranger"].includes(charClass)) {
682
+ proficiencies.push("All armor", "Shields", "Simple weapons", "Martial weapons");
683
+ } else if (charClass === "Barbarian") {
684
+ proficiencies.push("Light armor", "Medium armor", "Shields", "Simple weapons", "Martial weapons");
685
+ } else if (charClass === "Bard") {
686
+ proficiencies.push("Light armor", "Simple weapons", "Hand crossbows", "Longswords", "Rapiers", "Shortswords");
687
+ } else if (charClass === "Cleric") {
688
+ proficiencies.push("Light armor", "Medium armor", "Shields", "Simple weapons");
689
+ } else if (charClass === "Druid") {
690
+ proficiencies.push("Light armor", "Medium armor", "Shields", "Clubs", "Daggers", "Darts", "Javelins", "Maces", "Quarterstaffs", "Scimitars", "Sickles", "Slings", "Spears");
691
+ } else if (charClass === "Monk") {
692
+ proficiencies.push("Simple weapons", "Shortswords");
693
+ } else if (charClass === "Rogue") {
694
+ proficiencies.push("Light armor", "Simple weapons", "Hand crossbows", "Longswords", "Rapiers", "Shortswords");
695
+ } else if (["Sorcerer", "Wizard"].includes(charClass)) {
696
+ proficiencies.push("Daggers", "Darts", "Slings", "Quarterstaffs", "Light crossbows");
697
+ } else if (charClass === "Warlock") {
698
+ proficiencies.push("Light armor", "Simple weapons");
699
+ }
700
+
701
+ // Race proficiencies
702
+ if (race === "Dwarf") {
703
+ proficiencies.push("Battleaxe", "Handaxe", "Light hammer", "Warhammer");
704
+ } else if (race === "Elf") {
705
+ proficiencies.push("Longsword", "Shortsword", "Longbow", "Shortbow");
706
+ } else if (race === "Halfling") {
707
+ proficiencies.push("Lucky (reroll 1s on attack rolls, ability checks, saving throws)");
708
+ }
709
+
710
+ // Background proficiencies
711
+ if (["Acolyte", "Sage"].includes(background)) {
712
+ proficiencies.push("Arcana", "Religion");
713
+ } else if (["Criminal", "Urchin"].includes(background)) {
714
+ proficiencies.push("Deception", "Stealth");
715
+ } else if (background === "Folk Hero") {
716
+ proficiencies.push("Animal Handling", "Survival");
717
+ } else if (background === "Noble") {
718
+ proficiencies.push("History", "Persuasion");
719
+ } else if (background === "Soldier") {
720
+ proficiencies.push("Athletics", "Intimidation");
721
+ }
722
+
723
+ // Add 2 random skills based on class
724
+ const classSkills = {
725
+ "Barbarian": ["Animal Handling", "Athletics", "Intimidation", "Nature", "Perception", "Survival"],
726
+ "Bard": ["Acrobatics", "Animal Handling", "Arcana", "Athletics", "Deception", "History", "Insight", "Intimidation", "Investigation", "Medicine", "Nature", "Perception", "Performance", "Persuasion", "Religion", "Sleight of Hand", "Stealth"],
727
+ "Cleric": ["History", "Insight", "Medicine", "Persuasion", "Religion"],
728
+ "Druid": ["Arcana", "Animal Handling", "Insight", "Medicine", "Nature", "Perception", "Religion", "Survival"],
729
+ "Fighter": ["Acrobatics", "Animal Handling", "Athletics", "History", "Insight", "Intimidation", "Perception", "Survival"],
730
+ "Monk": ["Acrobatics", "Athletics", "History", "Insight", "Religion", "Stealth"],
731
+ "Paladin": ["Athletics", "Insight", "Intimidation", "Medicine", "Persuasion", "Religion"],
732
+ "Ranger": ["Animal Handling", "Athletics", "Insight", "Investigation", "Nature", "Perception", "Stealth", "Survival"],
733
+ "Rogue": ["Acrobatics", "Athletics", "Deception", "Insight", "Intimidation", "Investigation", "Perception", "Performance", "Persuasion", "Sleight of Hand", "Stealth"],
734
+ "Sorcerer": ["Arcana", "Deception", "Insight", "Intimidation", "Persuasion", "Religion"],
735
+ "Warlock": ["Arcana", "Deception", "History", "Intimidation", "Investigation", "Nature", "Religion"],
736
+ "Wizard": ["Arcana", "History", "Insight", "Investigation", "Medicine", "Religion"]
737
+ };
738
+
739
+ if (classSkills[charClass]) {
740
+ proficiencies = [...proficiencies, ...getRandomItems(classSkills[charClass], 2)];
741
+ }
742
+
743
+ return proficiencies;
744
+ }
745
+
746
+ function generateFeatures(charClass, race, background) {
747
+ let features = [];
748
+
749
+ // Race features
750
+ if (race === "Dragonborn") {
751
+ features.push("Draconic Ancestry", "Breath Weapon");
752
+ } else if (race === "Dwarf") {
753
+ features.push("Darkvision", "Dwarven Resilience", "Stonecunning");
754
+ } else if (race === "Elf") {
755
+ features.push("Darkvision", "Keen Senses", "Fey Ancestry", "Trance");
756
+ } else if (race === "Gnome") {
757
+ features.push("Darkvision", "Gnome Cunning");
758
+ } else if (race === "Half-Elf") {
759
+ features.push("Darkvision", "Fey Ancestry", "Skill Versatility");
760
+ } else if (race === "Halfling") {
761
+ features.push("Lucky", "Brave", "Halfling Nimbleness");
762
+ } else if (race === "Half-Orc") {
763
+ features.push("Darkvision", "Relentless Endurance", "Savage Attacks");
764
+ } else if (race === "Tiefling") {
765
+ features.push("Darkvision", "Hellish Resistance", "Infernal Legacy");
766
+ }
767
+
768
+ // Background features
769
+ if (background === "Acolyte") {
770
+ features.push("Shelter of the Faithful");
771
+ } else if (background === "Charlatan") {
772
+ features.push("False Identity");
773
+ } else if (background === "Criminal") {
774
+ features.push("Criminal Contact");
775
+ } else if (background === "Folk Hero") {
776
+ features.push("Rustic Hospitality");
777
+ } else if (background === "Noble") {
778
+ features.push("Position of Privilege");
779
+ } else if (background === "Soldier") {
780
+ features.push("Military Rank");
781
+ }
782
+
783
+ return features;
784
+ }
785
+
786
+ function generateSpells(charClass) {
787
+ if (!["Bard", "Cleric", "Druid", "Paladin", "Ranger", "Sorcerer", "Warlock", "Wizard"].includes(charClass)) {
788
+ return [];
789
+ }
790
+
791
+ const cantrips = [
792
+ "Acid Splash", "Blade Ward", "Booming Blade", "Chill Touch", "Control Flames", "Create Bonfire",
793
+ "Dancing Lights", "Druidcraft", "Eldritch Blast", "Fire Bolt", "Friends", "Frostbite",
794
+ "Green-Flame Blade", "Guidance", "Gust", "Infestation", "Light", "Lightning Lure",
795
+ "Mage Hand", "Magic Stone", "Mending", "Message", "Mind Sliver", "Minor Illusion",
796
+ "Mold Earth", "Poison Spray", "Prestidigitation", "Primal Savagery", "Produce Flame",
797
+ "Ray of Frost", "Resistance", "Sacred Flame", "Shape Water", "Shillelagh", "Shocking Grasp",
798
+ "Spare the Dying", "Sword Burst", "Thaumaturgy", "Thorn Whip", "Thunderclap", "Toll the Dead",
799
+ "True Strike", "Vicious Mockery", "Word of Radiance"
800
+ ];
801
+
802
+ const level1Spells = [
803
+ "Absorb Elements", "Alarm", "Animal Friendship", "Armor of Agathys", "Bane", "Bless",
804
+ "Burning Hands", "Catapult", "Cause Fear", "Ceremony", "Charm Person", "Chromatic Orb",
805
+ "Color Spray", "Command", "Compelled Duel", "Comprehend Languages", "Create or Destroy Water",
806
+ "Cure Wounds", "Detect Evil and Good", "Detect Magic", "Detect Poison and Disease",
807
+ "Disguise Self", "Dissonant Whispers", "Divine Favor", "Earth Tremor", "Ensnaring Strike",
808
+ "Entangle", "Expeditious Retreat", "Faerie Fire", "False Life", "Feather Fall",
809
+ "Find Familiar", "Fog Cloud", "Goodberry", "Grease", "Guiding Bolt", "Hail of Thorns",
810
+ "Healing Word", "Hellish Rebuke", "Heroism", "Hex", "Hunter's Mark", "Identify",
811
+ "Illusory Script", "Inflict Wounds", "Jump", "Longstrider", "Mage Armor", "Magic Missile",
812
+ "Protection from Evil and Good", "Purify Food and Drink", "Ray of Sickness", "Sanctuary",
813
+ "Searing Smite", "Shield", "Shield of Faith", "Silent Image", "Sleep", "Snare",
814
+ "Speak with Animals", "Tasha's Hideous Laughter", "Tenser's Floating Disk", "Thunderous Smite",
815
+ "Thunderwave", "Unseen Servant", "Witch Bolt", "Wrathful Smite", "Zephyr Strike"
816
+ ];
817
+
818
+ let spells = [];
819
+
820
+ // Add cantrips
821
+ if (["Bard", "Cleric", "Druid", "Sorcerer", "Warlock", "Wizard"].includes(charClass)) {
822
+ spells = [...spells, ...getRandomItems(cantrips, 2)];
823
+ }
824
+
825
+ // Add level 1 spells
826
+ spells = [...spells, ...getRandomItems(level1Spells, 3)];
827
+
828
+ return spells;
829
+ }
830
+
831
+ function updateCharacterSheet(character) {
832
+ // Basic info
833
+ document.getElementById('charName').textContent = character.name;
834
+ document.getElementById('race').textContent = character.race;
835
+ document.getElementById('subrace').textContent = character.subrace;
836
+ document.getElementById('class').textContent = character.charClass;
837
+ document.getElementById('subclass').textContent = character.subclass;
838
+
839
+ // Background
840
+ document.getElementById('background').textContent = character.background;
841
+ document.getElementById('alignment').textContent = character.alignment;
842
+ document.getElementById('personality').textContent = character.personality;
843
+ document.getElementById('ideal').textContent = character.ideal;
844
+ document.getElementById('bond').textContent = character.bond;
845
+ document.getElementById('flaw').textContent = character.flaw;
846
+
847
+ // Stats
848
+ document.getElementById('str').textContent = character.str;
849
+ document.getElementById('dex').textContent = character.dex;
850
+ document.getElementById('con').textContent = character.con;
851
+ document.getElementById('int').textContent = character.int;
852
+ document.getElementById('wis').textContent = character.wis;
853
+ document.getElementById('cha').textContent = character.cha;
854
+
855
+ // Modifiers
856
+ document.getElementById('strMod').textContent = character.strMod >= 0 ? `+${character.strMod}` : character.strMod;
857
+ document.getElementById('dexMod').textContent = character.dexMod >= 0 ? `+${character.dexMod}` : character.dexMod;
858
+ document.getElementById('conMod').textContent = character.conMod >= 0 ? `+${character.conMod}` : character.conMod;
859
+ document.getElementById('intMod').textContent = character.intMod >= 0 ? `+${character.intMod}` : character.intMod;
860
+ document.getElementById('wisMod').textContent = character.wisMod >= 0 ? `+${character.wisMod}` : character.wisMod;
861
+ document.getElementById('chaMod').textContent = character.chaMod >= 0 ? `+${character.chaMod}` : character.chaMod;
862
+
863
+ // Physical traits
864
+ document.getElementById('age').textContent = character.age;
865
+ document.getElementById('height').textContent = `${Math.floor(character.height / 12)}'${character.height % 12}"`;
866
+ document.getElementById('weight').textContent = `${character.weight} lbs`;
867
+ document.getElementById('eyes').textContent = character.eyes;
868
+ document.getElementById('skin').textContent = character.skin;
869
+ document.getElementById('hair').textContent = character.hair;
870
+ document.getElementById('distinctive').textContent = character.distinctive;
871
+
872
+ // Backstory
873
+ document.getElementById('backstory').textContent = character.backstory;
874
+
875
+ // Proficiencies
876
+ const proficienciesList = document.getElementById('proficiencies');
877
+ proficienciesList.innerHTML = '';
878
+ character.proficiencies.forEach(prof => {
879
+ const li = document.createElement('li');
880
+ li.textContent = prof;
881
+ li.classList.add('animate-fade-in');
882
+ proficienciesList.appendChild(li);
883
+ });
884
+
885
+ // Features
886
+ const featuresList = document.getElementById('features');
887
+ featuresList.innerHTML = '';
888
+ character.features.forEach(feat => {
889
+ const li = document.createElement('li');
890
+ li.textContent = feat;
891
+ li.classList.add('animate-fade-in');
892
+ featuresList.appendChild(li);
893
+ });
894
+
895
+ // Equipment
896
+ const equipmentList = document.getElementById('equipmentList');
897
+ equipmentList.innerHTML = '';
898
+ character.equipment.forEach(item => {
899
+ const li = document.createElement('li');
900
+ li.textContent = item;
901
+ li.classList.add('animate-fade-in');
902
+ equipmentList.appendChild(li);
903
+ });
904
+
905
+ // Spells
906
+ const spellsList = document.getElementById('spellsList');
907
+ spellsList.innerHTML = '';
908
+ if (character.spells.length > 0) {
909
+ character.spells.forEach(spell => {
910
+ const li = document.createElement('li');
911
+ li.textContent = spell;
912
+ li.classList.add('animate-fade-in');
913
+ spellsList.appendChild(li);
914
+ });
915
+ } else {
916
+ const li = document.createElement('li');
917
+ li.textContent = "No spells for this character";
918
+ li.classList.add('animate-fade-in');
919
+ spellsList.appendChild(li);
920
+ }
921
+
922
+ // Add animation to updated elements
923
+ const elementsToAnimate = document.querySelectorAll('#charName, #race, #class, #background, #str, #dex, #con, #int, #wis, #cha');
924
+ elementsToAnimate.forEach(el => {
925
+ el.classList.add('animate-fade-in');
926
+ setTimeout(() => el.classList.remove('animate-fade-in'), 500);
927
+ });
928
+ }
929
+
930
+ function generateVisuals() {
931
+ // Add loading animation to button
932
+ const btn = document.getElementById('generateVisuals');
933
+ btn.innerHTML = '<span class="material-icons animate-spin">autorenew</span> Generating...';
934
+ btn.classList.add('cursor-not-allowed');
935
+
936
+ setTimeout(() => {
937
+ const gender = Math.random() > 0.5 ? "male" : "female";
938
+ const race = document.getElementById('race').textContent;
939
+
940
+ // Physical traits
941
+ const age = getRandomInt(16, 80);
942
+ const height = getRandomInt(48, 96); // in inches
943
+ const weight = getRandomInt(90, 300); // in pounds
944
+ const eyes = getRandomItem(eyeColors);
945
+ const skin = getRandomItem(skinColors);
946
+ const hair = `${getRandomItem(hairColors)}, ${getRandomItem(hairStyles)}`;
947
+ const distinctive = getRandomItem(distinctiveFeatures);
948
+
949
+ // Update the UI
950
+ document.getElementById('age').textContent = age;
951
+ document.getElementById('height').textContent = `${Math.floor(height / 12)}'${height % 12}"`;
952
+ document.getElementById('weight').textContent = `${weight} lbs`;
953
+ document.getElementById('eyes').textContent = eyes;
954
+ document.getElementById('skin').textContent = skin;
955
+ document.getElementById('hair').textContent = hair;
956
+ document.getElementById('distinctive').textContent = distinctive;
957
+
958
+ // Reset button
959
+ btn.innerHTML = '<span class="material-icons">palette</span> Reroll Appearance';
960
+ btn.classList.remove('cursor-not-allowed');
961
+
962
+ // Add animation to updated elements
963
+ const elementsToAnimate = document.querySelectorAll('#age, #height, #weight, #eyes, #skin, #hair, #distinctive');
964
+ elementsToAnimate.forEach(el => {
965
+ el.classList.add('animate-fade-in');
966
+ setTimeout(() => el.classList.remove('animate-fade-in'), 500);
967
+ });
968
+
969
+ }, 500);
970
+ }
971
+
972
+ function generateStats() {
973
+ // Add loading animation to button
974
+ const btn = document.getElementById('generateStats');
975
+ btn.innerHTML = '<span class="material-icons animate-spin">autorenew</span> Rolling...';
976
+ btn.classList.add('cursor-not-allowed');
977
+
978
+ setTimeout(() => {
979
+ const stats = rollStats();
980
+ const str = stats[0];
981
+ const dex = stats[1];
982
+ const con = stats[2];
983
+ const int = stats[3];
984
+ const wis = stats[4];
985
+ const cha = stats[5];
986
+
987
+ // Modifiers
988
+ const strMod = calculateModifier(str);
989
+ const dexMod = calculateModifier(dex);
990
+ const conMod = calculateModifier(con);
991
+ const intMod = calculateModifier(int);
992
+ const wisMod = calculateModifier(wis);
993
+ const chaMod = calculateModifier(cha);
994
+
995
+ // Update the UI
996
+ document.getElementById('str').textContent = str;
997
+ document.getElementById('dex').textContent = dex;
998
+ document.getElementById('con').textContent = con;
999
+ document.getElementById('int').textContent = int;
1000
+ document.getElementById('wis').textContent = wis;
1001
+ document.getElementById('cha').textContent = cha;
1002
+
1003
+ document.getElementById('strMod').textContent = strMod >= 0 ? `+${strMod}` : strMod;
1004
+ document.getElementById('dexMod').textContent = dexMod >= 0 ? `+${dexMod}` : dexMod;
1005
+ document.getElementById('conMod').textContent = conMod >= 0 ? `+${conMod}` : conMod;
1006
+ document.getElementById('intMod').textContent = intMod >= 0 ? `+${intMod}` : intMod;
1007
+ document.getElementById('wisMod').textContent = wisMod >= 0 ? `+${wisMod}` : wisMod;
1008
+ document.getElementById('chaMod').textContent = chaMod >= 0 ? `+${chaMod}` : chaMod;
1009
+
1010
+ // Reset button
1011
+ btn.innerHTML = '<span class="material-icons">swap_vert</span> Reroll Stats';
1012
+ btn.classList.remove('cursor-not-allowed');
1013
+
1014
+ // Add animation to updated elements
1015
+ const elementsToAnimate = document.querySelectorAll('#str, #dex, #con, #int, #wis, #cha, #strMod, #dexMod, #conMod, #intMod, #wisMod, #chaMod');
1016
+ elementsToAnimate.forEach(el => {
1017
+ el.classList.add('animate-fade-in');
1018
+ setTimeout(() => el.classList.remove('animate-fade-in'), 500);
1019
+ });
1020
+
1021
+ }, 500);
1022
+ }
1023
+
1024
+ function saveCharacter() {
1025
+ const btn = document.getElementById('saveCharacter');
1026
+ btn.innerHTML = '<span class="material-icons">check</span> Saved!';
1027
+
1028
+ setTimeout(() => {
1029
+ btn.innerHTML = '<span class="material-icons">save</span> Save Character';
1030
+ }, 2000);
1031
+
1032
+ // In a real app, this would save to a database or local storage
1033
+ console.log("Character saved!");
1034
+ }
1035
+
1036
+ // Tab switching
1037
+ function setupTabs() {
1038
+ const tabs = document.querySelectorAll('.tab');
1039
+ const tabContents = document.querySelectorAll('.tab-content');
1040
+
1041
+ tabs.forEach(tab => {
1042
+ tab.addEventListener('click', () => {
1043
+ // Remove active class from all tabs
1044
+ tabs.forEach(t => t.classList.remove('tab-active'));
1045
+ // Add active class to clicked tab
1046
+ tab.classList.add('tab-active');
1047
+
1048
+ // Hide all tab contents
1049
+ tabContents.forEach(content => content.classList.add('hidden'));
1050
+ // Show the selected tab content
1051
+ const tabId = tab.getAttribute('data-tab');
1052
+ document.getElementById(`${tabId}Tab`).classList.remove('hidden');
1053
+ });
1054
+ });
1055
+ }
1056
+
1057
+ // Event listeners
1058
+ document.getElementById('generateAll').addEventListener('click', generateCharacter);
1059
+ document.getElementById('generateVisuals').addEventListener('click', generateVisuals);
1060
+ document.getElementById('generateStats').addEventListener('click', generateStats);
1061
+ document.getElementById('saveCharacter').addEventListener('click', saveCharacter);
1062
+
1063
+ // Initialize
1064
+ setupTabs();
1065
+
1066
+ // Generate a character on first load
1067
+ generateCharacter();
1068
+ </script>
1069
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=IsaiahSouf/dnd-5e-character-creator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1070
+ </html>
prompts.txt ADDED
File without changes