prompt
Browse files
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": "
|
| 70 |
-
"HP": {"type": "
|
| 71 |
-
"defence": {"type": "
|
| 72 |
-
"attack": {"type": "
|
| 73 |
-
"speed": {"type": "
|
| 74 |
-
"specialAbility": {"type": "string", "description": "
|
| 75 |
-
"attackActionDescription": {"type": "string", "description": "
|
| 76 |
-
"boostActionDescription": {"type": "string", "description": "
|
| 77 |
-
"disparageActionDescription": {"type": "string", "description": "
|
| 78 |
-
"specialActionDescription": {"type": "string", "description": "
|
| 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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 |
-
<
|
| 129 |
-
<span class="stat-
|
|
|
|
| 130 |
</div>
|
| 131 |
<div class="stat-item">
|
| 132 |
-
<
|
| 133 |
-
<span class="stat-
|
|
|
|
| 134 |
</div>
|
| 135 |
<div class="stat-item">
|
| 136 |
-
<
|
| 137 |
-
<span class="stat-
|
|
|
|
| 138 |
</div>
|
| 139 |
<div class="stat-item">
|
| 140 |
-
<
|
| 141 |
-
<span class="stat-
|
|
|
|
| 142 |
</div>
|
| 143 |
<div class="stat-item">
|
| 144 |
-
<
|
| 145 |
-
<span class="stat-
|
|
|
|
| 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 |
-
|
| 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 |
-
|
| 389 |
-
|
|
|
|
| 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:
|
| 112 |
-
HP:
|
| 113 |
-
defence:
|
| 114 |
-
attack:
|
| 115 |
-
speed:
|
| 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;
|