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;
|