Fraser commited on
Commit
13cae40
·
1 Parent(s): d9c705e
src/lib/components/MonsterGenerator/MonsterGenerator.svelte CHANGED
@@ -66,16 +66,16 @@ Here is the output schema:
66
  "properties": {
67
  "name": {"type": "string", "description": "The monster's name"},
68
  "description": {"type": "string", "description": "A brief description of the monster"},
69
- "rarity": {"type": "string", "enum": ["very-low", "low", "medium", "high", "very-high"], "description": "How rare/unique the monster is"},
70
- "HP": {"type": "string", "enum": ["very-low", "low", "medium", "high", "very-high"], "description": "Health points"},
71
- "defence": {"type": "string", "enum": ["very-low", "low", "medium", "high", "very-high"], "description": "Defensive capability"},
72
- "attack": {"type": "string", "enum": ["very-low", "low", "medium", "high", "very-high"], "description": "Attack power"},
73
- "speed": {"type": "string", "enum": ["very-low", "low", "medium", "high", "very-high"], "description": "Movement speed"},
74
- "specialAbility": {"type": "string", "description": "Passive trait that gives the monster a unique advantage in battle"},
75
- "attackActionDescription": {"type": "string", "description": "Primary attack that deals damage"},
76
- "boostActionDescription": {"type": "string", "description": "Action that buffs the monster's own stats/status"},
77
- "disparageActionDescription": {"type": "string", "description": "Action that lowers enemy stats/status"},
78
- "specialActionDescription": {"type": "string", "description": "Powerful action with single use per battle"}
79
  },
80
  "required": ["name", "description", "rarity", "HP", "defence", "attack", "speed", "specialAbility", "attackActionDescription", "boostActionDescription", "disparageActionDescription", "specialActionDescription"]
81
  }
@@ -338,11 +338,29 @@ Assistant: \`\`\`json`;
338
  const matches = jsonString.match(/```(?:json)?\s*([\s\S]*?)```/);
339
  if (matches) {
340
  cleanJson = matches[1];
 
 
 
341
  }
342
  }
343
 
344
  try {
345
- const stats: MonsterStats = JSON.parse(cleanJson.trim());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  state.monsterStats = stats;
347
  console.log('Monster stats generated:', stats);
348
  } catch (parseError) {
 
66
  "properties": {
67
  "name": {"type": "string", "description": "The monster's name"},
68
  "description": {"type": "string", "description": "A brief description of the monster"},
69
+ "rarity": {"type": "integer", "minimum": 0, "maximum": 100, "description": "How rare/unique the monster is (0=very common, 100=legendary)"},
70
+ "HP": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Health points (0=fragile, 100=tank)"},
71
+ "defence": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Defensive capability (0=paper thin, 100=impenetrable)"},
72
+ "attack": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Attack power (0=harmless, 100=devastating)"},
73
+ "speed": {"type": "integer", "minimum": 0, "maximum": 100, "description": "Movement speed (0=immobile, 100=lightning fast)"},
74
+ "specialAbility": {"type": "string", "description": "Description of a passive trait that gives the monster a unique advantage in battle"},
75
+ "attackActionDescription": {"type": "string", "description": "Description of a primary attack that deals damage"},
76
+ "boostActionDescription": {"type": "string", "description": "Description of an action that buffs the monster's own stats/status"},
77
+ "disparageActionDescription": {"type": "string", "description": "Description of an action that lowers enemy stats/status"},
78
+ "specialActionDescription": {"type": "string", "description": "Description of a powerful action with single use per battle"}
79
  },
80
  "required": ["name", "description", "rarity", "HP", "defence", "attack", "speed", "specialAbility", "attackActionDescription", "boostActionDescription", "disparageActionDescription", "specialActionDescription"]
81
  }
 
338
  const matches = jsonString.match(/```(?:json)?\s*([\s\S]*?)```/);
339
  if (matches) {
340
  cleanJson = matches[1];
341
+ } else {
342
+ // If no closing ```, just remove the opening ```json
343
+ cleanJson = jsonString.replace(/^```(?:json)?\s*/, '').replace(/```\s*$/, '');
344
  }
345
  }
346
 
347
  try {
348
+ const parsedStats = JSON.parse(cleanJson.trim());
349
+
350
+ // Ensure numeric fields are actually numbers
351
+ const numericFields = ['rarity', 'HP', 'defence', 'attack', 'speed'];
352
+
353
+ for (const field of numericFields) {
354
+ if (parsedStats[field] !== undefined) {
355
+ // Convert string numbers to actual numbers
356
+ parsedStats[field] = parseInt(parsedStats[field]);
357
+
358
+ // Clamp to 0-100 range
359
+ parsedStats[field] = Math.max(0, Math.min(100, parsedStats[field]));
360
+ }
361
+ }
362
+
363
+ const stats: MonsterStats = parsedStats;
364
  state.monsterStats = stats;
365
  console.log('Monster stats generated:', stats);
366
  } catch (parseError) {
src/lib/components/MonsterGenerator/MonsterResult.svelte CHANGED
@@ -28,6 +28,14 @@
28
  alert('Prompt copied to clipboard!');
29
  }
30
 
 
 
 
 
 
 
 
 
31
  async function saveToCollection() {
32
  if (!workflowState.monsterImage || !workflowState.imageCaption || !workflowState.monsterConcept || !workflowState.imagePrompt) {
33
  saveError = 'Missing monster data';
@@ -78,7 +86,7 @@
78
  </script>
79
 
80
  <div class="result-container">
81
- <h3>Your Monster Has Been Created!</h3>
82
 
83
  {#if workflowState.monsterImage}
84
  <div class="monster-image-container">
@@ -90,59 +98,35 @@
90
  </div>
91
  {/if}
92
 
93
- <div class="results-grid">
94
- <div class="result-section">
95
- <h4>Original Description</h4>
96
- <div class="result-content">
97
- <p>{workflowState.imageCaption || 'No caption available'}</p>
98
- </div>
99
- </div>
100
-
101
- <div class="result-section">
102
- <h4>Monster Concept</h4>
103
- <div class="result-content">
104
- <p>{workflowState.monsterConcept || 'No concept available'}</p>
105
- </div>
106
- </div>
107
-
108
- <div class="result-section">
109
- <h4>Generation Prompt</h4>
110
- <div class="result-content">
111
- <p>{workflowState.imagePrompt || 'No prompt available'}</p>
112
- {#if workflowState.imagePrompt}
113
- <button class="copy-button" onclick={copyPrompt}>
114
- <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
115
- <path d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2zm2 0v8h8V2H6zM2 6a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-2h-2v2H2V8h2V6H2z"/>
116
- </svg>
117
- Copy
118
- </button>
119
- {/if}
120
- </div>
121
- </div>
122
 
123
  {#if workflowState.monsterStats}
124
  <div class="result-section">
125
  <h4>Battle Stats</h4>
126
  <div class="stats-grid">
127
  <div class="stat-item">
128
- <span class="stat-label">Rarity:</span>
129
- <span class="stat-value stat-{workflowState.monsterStats.rarity}">{workflowState.monsterStats.rarity}</span>
 
130
  </div>
131
  <div class="stat-item">
132
- <span class="stat-label">HP:</span>
133
- <span class="stat-value stat-{workflowState.monsterStats.HP}">{workflowState.monsterStats.HP}</span>
 
134
  </div>
135
  <div class="stat-item">
136
- <span class="stat-label">Attack:</span>
137
- <span class="stat-value stat-{workflowState.monsterStats.attack}">{workflowState.monsterStats.attack}</span>
 
138
  </div>
139
  <div class="stat-item">
140
- <span class="stat-label">Defence:</span>
141
- <span class="stat-value stat-{workflowState.monsterStats.defence}">{workflowState.monsterStats.defence}</span>
 
142
  </div>
143
  <div class="stat-item">
144
- <span class="stat-label">Speed:</span>
145
- <span class="stat-value stat-{workflowState.monsterStats.speed}">{workflowState.monsterStats.speed}</span>
 
146
  </div>
147
  </div>
148
  <div class="abilities-section">
@@ -236,11 +220,6 @@
236
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
237
  }
238
 
239
- .results-grid {
240
- display: grid;
241
- gap: 1.5rem;
242
- margin-bottom: 3rem;
243
- }
244
 
245
  .result-section {
246
  background: #f8f9fa;
@@ -370,31 +349,38 @@
370
  .stat-item {
371
  display: flex;
372
  flex-direction: column;
373
- align-items: center;
374
- padding: 0.5rem;
375
  background: white;
376
  border-radius: 6px;
377
  border: 1px solid #dee2e6;
 
 
 
 
 
 
 
 
 
 
 
378
  }
379
 
380
  .stat-label {
381
  font-size: 0.85rem;
382
  color: #6c757d;
383
  margin-bottom: 0.25rem;
 
 
384
  }
385
 
386
  .stat-value {
387
  font-weight: 600;
388
- text-transform: uppercase;
389
- font-size: 0.9rem;
 
390
  }
391
 
392
- .stat-very-low { color: #dc3545; }
393
- .stat-low { color: #fd7e14; }
394
- .stat-medium { color: #ffc107; }
395
- .stat-high { color: #28a745; }
396
- .stat-very-high { color: #007bff; }
397
-
398
  .abilities-section {
399
  display: grid;
400
  gap: 1rem;
 
28
  alert('Prompt copied to clipboard!');
29
  }
30
 
31
+ function getStatColor(value: number): string {
32
+ if (value >= 80) return '#007bff'; // very high - blue
33
+ if (value >= 60) return '#28a745'; // high - green
34
+ if (value >= 40) return '#ffc107'; // medium - yellow
35
+ if (value >= 20) return '#fd7e14'; // low - orange
36
+ return '#dc3545'; // very low - red
37
+ }
38
+
39
  async function saveToCollection() {
40
  if (!workflowState.monsterImage || !workflowState.imageCaption || !workflowState.monsterConcept || !workflowState.imagePrompt) {
41
  saveError = 'Missing monster data';
 
86
  </script>
87
 
88
  <div class="result-container">
89
+ <h3>{workflowState.monsterStats?.name || 'Your Monster Has Been Created!'}</h3>
90
 
91
  {#if workflowState.monsterImage}
92
  <div class="monster-image-container">
 
98
  </div>
99
  {/if}
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  {#if workflowState.monsterStats}
103
  <div class="result-section">
104
  <h4>Battle Stats</h4>
105
  <div class="stats-grid">
106
  <div class="stat-item">
107
+ <div class="stat-bar" style="width: {workflowState.monsterStats.rarity}%; background-color: {getStatColor(workflowState.monsterStats.rarity)}20"></div>
108
+ <span class="stat-label">Rarity</span>
109
+ <span class="stat-value" style="color: {getStatColor(workflowState.monsterStats.rarity)}">{workflowState.monsterStats.rarity}</span>
110
  </div>
111
  <div class="stat-item">
112
+ <div class="stat-bar" style="width: {workflowState.monsterStats.HP}%; background-color: {getStatColor(workflowState.monsterStats.HP)}20"></div>
113
+ <span class="stat-label">HP</span>
114
+ <span class="stat-value" style="color: {getStatColor(workflowState.monsterStats.HP)}">{workflowState.monsterStats.HP}</span>
115
  </div>
116
  <div class="stat-item">
117
+ <div class="stat-bar" style="width: {workflowState.monsterStats.attack}%; background-color: {getStatColor(workflowState.monsterStats.attack)}20"></div>
118
+ <span class="stat-label">Attack</span>
119
+ <span class="stat-value" style="color: {getStatColor(workflowState.monsterStats.attack)}">{workflowState.monsterStats.attack}</span>
120
  </div>
121
  <div class="stat-item">
122
+ <div class="stat-bar" style="width: {workflowState.monsterStats.defence}%; background-color: {getStatColor(workflowState.monsterStats.defence)}20"></div>
123
+ <span class="stat-label">Defence</span>
124
+ <span class="stat-value" style="color: {getStatColor(workflowState.monsterStats.defence)}">{workflowState.monsterStats.defence}</span>
125
  </div>
126
  <div class="stat-item">
127
+ <div class="stat-bar" style="width: {workflowState.monsterStats.speed}%; background-color: {getStatColor(workflowState.monsterStats.speed)}20"></div>
128
+ <span class="stat-label">Speed</span>
129
+ <span class="stat-value" style="color: {getStatColor(workflowState.monsterStats.speed)}">{workflowState.monsterStats.speed}</span>
130
  </div>
131
  </div>
132
  <div class="abilities-section">
 
220
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
221
  }
222
 
 
 
 
 
 
223
 
224
  .result-section {
225
  background: #f8f9fa;
 
349
  .stat-item {
350
  display: flex;
351
  flex-direction: column;
352
+ padding: 0.75rem;
 
353
  background: white;
354
  border-radius: 6px;
355
  border: 1px solid #dee2e6;
356
+ position: relative;
357
+ overflow: hidden;
358
+ }
359
+
360
+ .stat-bar {
361
+ position: absolute;
362
+ top: 0;
363
+ left: 0;
364
+ height: 100%;
365
+ transition: width 0.3s ease;
366
+ z-index: 0;
367
  }
368
 
369
  .stat-label {
370
  font-size: 0.85rem;
371
  color: #6c757d;
372
  margin-bottom: 0.25rem;
373
+ position: relative;
374
+ z-index: 1;
375
  }
376
 
377
  .stat-value {
378
  font-weight: 600;
379
+ font-size: 1.1rem;
380
+ position: relative;
381
+ z-index: 1;
382
  }
383
 
 
 
 
 
 
 
384
  .abilities-section {
385
  display: grid;
386
  gap: 1rem;
src/lib/types/index.ts CHANGED
@@ -103,16 +103,14 @@ export interface MonsterGeneratorProps {
103
  }
104
 
105
  // Monster Stats Types
106
- export type LikertScale = 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
107
-
108
  export interface MonsterStats {
109
  name: string;
110
  description: string;
111
- rarity: LikertScale;
112
- HP: LikertScale;
113
- defence: LikertScale;
114
- attack: LikertScale;
115
- speed: LikertScale;
116
  specialAbility: string;
117
  attackActionDescription: string;
118
  boostActionDescription: string;
 
103
  }
104
 
105
  // Monster Stats Types
 
 
106
  export interface MonsterStats {
107
  name: string;
108
  description: string;
109
+ rarity: number; // 0-100
110
+ HP: number; // 0-100
111
+ defence: number; // 0-100
112
+ attack: number; // 0-100
113
+ speed: number; // 0-100
114
  specialAbility: string;
115
  attackActionDescription: string;
116
  boostActionDescription: string;