From 1960adb449df3ca4638c0eeff0a93e7cd0382cc8 Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:13:40 +0000 Subject: [PATCH 01/26] Add prompt guessing game initial structure Created a new React app for the prompt guessing game that will: - Generate creative prompts using text.pollinations.ai - Create images from prompts using image.pollinations.ai - Let users guess the prompts and provide feedback Next steps: 1. Integrate with text.pollinations.ai for prompt generation 2. Integrate with image.pollinations.ai for image generation 3. Implement prompt similarity checking for guess evaluation Closes # 140 Mentat precommits passed. Log: https://mentat.ai/log/da1bbadf-deed-4d43-b60e-4fdf03101e21 --- index.html | 12 +++++++ package.json | 8 ++++- prompt-guessing-game/package.json | 19 ++++++++++ src/App.css | 60 +++++++++++++++++++++++++++++++ src/App.jsx | 59 ++++++++++++++++++++++++++++++ src/index.css | 32 +++++++++++++++++ src/main.jsx | 10 ++++++ vite.config.js | 6 ++++ 8 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 index.html create mode 100644 prompt-guessing-game/package.json create mode 100644 src/App.css create mode 100644 src/App.jsx create mode 100644 src/index.css create mode 100644 src/main.jsx create mode 100644 vite.config.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..97a49e3 --- /dev/null +++ b/index.html @@ -0,0 +1,12 @@ + + + + + + Prompt Guessing Game + + +
+ + + \ No newline at end of file diff --git a/package.json b/package.json index 734c4d4..df58344 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,11 @@ "homepage": "https://github.com/pollinations/hive#readme", "devDependencies": { "@playwright/test": "^1.41.1" + }, + "dependencies": { + "@vitejs/plugin-react": "^4.3.4", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "vite": "^6.0.7" } -} \ No newline at end of file +} diff --git a/prompt-guessing-game/package.json b/prompt-guessing-game/package.json new file mode 100644 index 0000000..e5fc11d --- /dev/null +++ b/prompt-guessing-game/package.json @@ -0,0 +1,19 @@ +{ + "name": "prompt-guessing-game", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.2.0", + "vite": "^5.0.0" + } +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..04e064e --- /dev/null +++ b/src/App.css @@ -0,0 +1,60 @@ +.app { + max-width: 800px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.game-container { + margin-top: 2rem; +} + +.image-container { + margin: 2rem 0; +} + +.image-container img { + max-width: 100%; + max-height: 400px; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +form { + display: flex; + gap: 1rem; + justify-content: center; + margin: 2rem 0; +} + +input { + padding: 0.5rem 1rem; + font-size: 1rem; + border: 1px solid #ccc; + border-radius: 4px; + width: 300px; +} + +button { + padding: 0.5rem 1rem; + font-size: 1rem; + background-color: #4CAF50; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s; +} + +button:hover { + background-color: #45a049; +} + +.game-info { + margin-top: 2rem; +} + +.feedback { + margin-top: 1rem; + font-weight: bold; +} \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx new file mode 100644 index 0000000..0bed1a4 --- /dev/null +++ b/src/App.jsx @@ -0,0 +1,59 @@ +import { useState } from 'react' +import './App.css' + +function App() { + const [currentImage, setCurrentImage] = useState(null) + const [userGuess, setUserGuess] = useState('') + const [feedback, setFeedback] = useState('') + const [attempts, setAttempts] = useState(0) + const [actualPrompt, setActualPrompt] = useState('') + + const handleGuess = async (e) => { + e.preventDefault() + // TODO: Implement guess evaluation logic using text.pollinations.ai + setAttempts(prev => prev + 1) + } + + const startNewGame = async () => { + // TODO: Generate new prompt using text.pollinations.ai + // TODO: Generate image using image.pollinations.ai + setAttempts(0) + setFeedback('') + setUserGuess('') + } + + return ( +
+

Prompt Guessing Game

+ +
+ {currentImage ? ( + <> +
+ AI generated +
+ +
+ setUserGuess(e.target.value)} + placeholder="What's the prompt for this image?" + /> + +
+ +
+

Attempts: {attempts}

+ {feedback &&

{feedback}

} +
+ + ) : ( + + )} +
+
+ ) +} + +export default App \ No newline at end of file diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..c1776bb --- /dev/null +++ b/src/index.css @@ -0,0 +1,32 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 2.2em; + line-height: 1.1; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } +} \ No newline at end of file diff --git a/src/main.jsx b/src/main.jsx new file mode 100644 index 0000000..54ebda4 --- /dev/null +++ b/src/main.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' +import './index.css' + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +) \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..3e34260 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], +}) \ No newline at end of file From 8e9cb95a53458f5cade06048a73d5bc601561dcd Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:19:20 +0000 Subject: [PATCH 02/26] Implement prompt guessing game functionality - Added utility functions for: - Generating creative prompts using text.pollinations.ai - Creating images from prompts using image.pollinations.ai - Evaluating guess similarity - Enhanced UI with loading and error states - Added disabled states for inputs during loading - Improved feedback system for user guesses - Added loading animation and error styling Closes # 140 Mentat precommits passed. Log: https://mentat.ai/log/81a96ae5-98dc-4628-985c-a96846c045de --- prompt-guessing-game/src/utils.js | 78 +++++++++++++++++++++++++++++++ src/App.css | 38 ++++++++++++++- src/App.jsx | 69 ++++++++++++++++++++++----- src/utils.js | 78 +++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 13 deletions(-) create mode 100644 prompt-guessing-game/src/utils.js create mode 100644 src/utils.js diff --git a/prompt-guessing-game/src/utils.js b/prompt-guessing-game/src/utils.js new file mode 100644 index 0000000..b22be77 --- /dev/null +++ b/prompt-guessing-game/src/utils.js @@ -0,0 +1,78 @@ +// Function to generate a creative prompt using text.pollinations.ai +export async function generatePrompt() { + try { + const response = await fetch('https://text.pollinations.ai/v1/generate', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + prompt: 'Generate a creative and descriptive image prompt that would be interesting to visualize.', + max_tokens: 50, + }), + }); + + if (!response.ok) { + throw new Error('Failed to generate prompt'); + } + + const data = await response.json(); + return data.choices[0].text.trim(); + } catch (error) { + console.error('Error generating prompt:', error); + throw error; + } +} + +// Function to generate an image from a prompt using image.pollinations.ai +export async function generateImage(prompt) { + try { + const response = await fetch('https://image.pollinations.ai/prompt/' + encodeURIComponent(prompt)); + + if (!response.ok) { + throw new Error('Failed to generate image'); + } + + return response.url; + } catch (error) { + console.error('Error generating image:', error); + throw error; + } +} + +// Function to evaluate similarity between guess and actual prompt +export async function evaluateGuess(guess, actualPrompt) { + try { + const response = await fetch('https://text.pollinations.ai/v1/similarity', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + text1: guess, + text2: actualPrompt, + }), + }); + + if (!response.ok) { + throw new Error('Failed to evaluate guess'); + } + + const data = await response.json(); + const similarity = data.similarity; + + // Return feedback based on similarity score + if (similarity > 0.9) { + return { message: "Perfect! You got it!", isCorrect: true, similarity }; + } else if (similarity > 0.7) { + return { message: "Very close! Try being more specific.", isCorrect: false, similarity }; + } else if (similarity > 0.5) { + return { message: "You're on the right track!", isCorrect: false, similarity }; + } else { + return { message: "Not quite. Try a different approach.", isCorrect: false, similarity }; + } + } catch (error) { + console.error('Error evaluating guess:', error); + throw error; + } +} \ No newline at end of file diff --git a/src/App.css b/src/App.css index 04e064e..289df7a 100644 --- a/src/App.css +++ b/src/App.css @@ -35,6 +35,11 @@ input { width: 300px; } +input:disabled { + background-color: #f5f5f5; + cursor: not-allowed; +} + button { padding: 0.5rem 1rem; font-size: 1rem; @@ -46,10 +51,15 @@ button { transition: background-color 0.2s; } -button:hover { +button:hover:not(:disabled) { background-color: #45a049; } +button:disabled { + background-color: #cccccc; + cursor: not-allowed; +} + .game-info { margin-top: 2rem; } @@ -57,4 +67,28 @@ button:hover { .feedback { margin-top: 1rem; font-weight: bold; -} \ No newline at end of file +} + +.error { + color: #dc3545; + margin: 1rem 0; + padding: 0.5rem; + border-radius: 4px; + background-color: #f8d7da; +} + +.loading { + margin: 2rem 0; + font-size: 1.2rem; + color: #666; +} + +@keyframes pulse { + 0% { opacity: 1; } + 50% { opacity: 0.5; } + 100% { opacity: 1; } +} + +.loading { + animation: pulse 1.5s infinite; +} diff --git a/src/App.jsx b/src/App.jsx index 0bed1a4..fec64f7 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,5 @@ import { useState } from 'react' +import { generatePrompt, generateImage, evaluateGuess } from './utils' import './App.css' function App() { @@ -7,19 +8,56 @@ function App() { const [feedback, setFeedback] = useState('') const [attempts, setAttempts] = useState(0) const [actualPrompt, setActualPrompt] = useState('') + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) const handleGuess = async (e) => { e.preventDefault() - // TODO: Implement guess evaluation logic using text.pollinations.ai - setAttempts(prev => prev + 1) + if (!userGuess.trim()) return + + try { + setLoading(true) + const result = await evaluateGuess(userGuess, actualPrompt) + setFeedback(result.message) + setAttempts(prev => prev + 1) + + if (result.isCorrect) { + setTimeout(() => { + alert('Congratulations! You guessed the prompt correctly!') + startNewGame() + }, 1500) + } + } catch (err) { + setError('Failed to evaluate guess. Please try again.') + console.error(err) + } finally { + setLoading(false) + } } const startNewGame = async () => { - // TODO: Generate new prompt using text.pollinations.ai - // TODO: Generate image using image.pollinations.ai - setAttempts(0) - setFeedback('') - setUserGuess('') + try { + setLoading(true) + setError(null) + + // Generate new prompt + const prompt = await generatePrompt() + setActualPrompt(prompt) + + // Generate image from prompt + const imageUrl = await generateImage(prompt) + setCurrentImage(imageUrl) + + // Reset game state + setAttempts(0) + setFeedback('') + setUserGuess('') + } catch (err) { + setError('Failed to start new game. Please try again.') + console.error(err) + } finally { + setLoading(false) + } } return ( @@ -27,7 +65,11 @@ function App() {

Prompt Guessing Game

- {currentImage ? ( + {error &&

{error}

} + + {loading ? ( +
Loading...
+ ) : currentImage ? ( <>
AI generated @@ -39,8 +81,11 @@ function App() { value={userGuess} onChange={(e) => setUserGuess(e.target.value)} placeholder="What's the prompt for this image?" + disabled={loading} /> - +
@@ -49,11 +94,13 @@ function App() {
) : ( - + )}
) } -export default App \ No newline at end of file +export default App diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..b22be77 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,78 @@ +// Function to generate a creative prompt using text.pollinations.ai +export async function generatePrompt() { + try { + const response = await fetch('https://text.pollinations.ai/v1/generate', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + prompt: 'Generate a creative and descriptive image prompt that would be interesting to visualize.', + max_tokens: 50, + }), + }); + + if (!response.ok) { + throw new Error('Failed to generate prompt'); + } + + const data = await response.json(); + return data.choices[0].text.trim(); + } catch (error) { + console.error('Error generating prompt:', error); + throw error; + } +} + +// Function to generate an image from a prompt using image.pollinations.ai +export async function generateImage(prompt) { + try { + const response = await fetch('https://image.pollinations.ai/prompt/' + encodeURIComponent(prompt)); + + if (!response.ok) { + throw new Error('Failed to generate image'); + } + + return response.url; + } catch (error) { + console.error('Error generating image:', error); + throw error; + } +} + +// Function to evaluate similarity between guess and actual prompt +export async function evaluateGuess(guess, actualPrompt) { + try { + const response = await fetch('https://text.pollinations.ai/v1/similarity', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + text1: guess, + text2: actualPrompt, + }), + }); + + if (!response.ok) { + throw new Error('Failed to evaluate guess'); + } + + const data = await response.json(); + const similarity = data.similarity; + + // Return feedback based on similarity score + if (similarity > 0.9) { + return { message: "Perfect! You got it!", isCorrect: true, similarity }; + } else if (similarity > 0.7) { + return { message: "Very close! Try being more specific.", isCorrect: false, similarity }; + } else if (similarity > 0.5) { + return { message: "You're on the right track!", isCorrect: false, similarity }; + } else { + return { message: "Not quite. Try a different approach.", isCorrect: false, similarity }; + } + } catch (error) { + console.error('Error evaluating guess:', error); + throw error; + } +} \ No newline at end of file From d7f7765cc27b28e02509a74dcf20a68e447f8a32 Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:22:49 +0000 Subject: [PATCH 03/26] Add game instructions and hint system - Added clear instructions for players - Implemented hint system after 5 attempts - Show actual prompt after successful guess - Added game won state to prevent further guesses - Improved UI feedback and styling - Added loading and disabled states for better UX Closes # 140 Mentat precommits passed. Log: https://mentat.ai/log/10c53bb0-aa10-4fdf-9153-ba6aff1b73bc --- src/App.css | 21 +++++++++++++++++++++ src/App.jsx | 34 +++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/App.css b/src/App.css index 289df7a..6dea7d8 100644 --- a/src/App.css +++ b/src/App.css @@ -5,6 +5,18 @@ text-align: center; } +.instructions { + margin: 1rem 0 2rem; + padding: 1rem; + background-color: #f8f9fa; + border-radius: 8px; + color: #666; +} + +.instructions p { + margin: 0.5rem 0; +} + .game-container { margin-top: 2rem; } @@ -69,6 +81,15 @@ button:disabled { font-weight: bold; } +.hint { + margin-top: 1rem; + color: #856404; + background-color: #fff3cd; + padding: 0.5rem; + border-radius: 4px; + font-style: italic; +} + .error { color: #dc3545; margin: 1rem 0; diff --git a/src/App.jsx b/src/App.jsx index fec64f7..8156f7d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -10,6 +10,8 @@ function App() { const [actualPrompt, setActualPrompt] = useState('') const [loading, setLoading] = useState(false) const [error, setError] = useState(null) + const [showHint, setShowHint] = useState(false) + const [gameWon, setGameWon] = useState(false) const handleGuess = async (e) => { e.preventDefault() @@ -22,10 +24,15 @@ function App() { setAttempts(prev => prev + 1) if (result.isCorrect) { + setGameWon(true) + setFeedback(`Perfect! The prompt was: "${actualPrompt}"`) setTimeout(() => { - alert('Congratulations! You guessed the prompt correctly!') - startNewGame() - }, 1500) + if (confirm('Congratulations! Would you like to play again?')) { + startNewGame() + } + }, 2000) + } else if (attempts >= 4 && !showHint) { + setShowHint(true) } } catch (err) { setError('Failed to evaluate guess. Please try again.') @@ -39,6 +46,8 @@ function App() { try { setLoading(true) setError(null) + setShowHint(false) + setGameWon(false) // Generate new prompt const prompt = await generatePrompt() @@ -60,10 +69,20 @@ function App() { } } + const getHint = () => { + const words = actualPrompt.split(' ') + return words.map(word => word[0] + '...').join(' ') + } + return (

Prompt Guessing Game

+
+

Try to guess the AI-generated prompt that was used to create this image!

+

The more accurate your guess, the higher your score.

+
+
{error &&

{error}

} @@ -81,9 +100,9 @@ function App() { value={userGuess} onChange={(e) => setUserGuess(e.target.value)} placeholder="What's the prompt for this image?" - disabled={loading} + disabled={loading || gameWon} /> - @@ -91,6 +110,11 @@ function App() {

Attempts: {attempts}

{feedback &&

{feedback}

} + {showHint && !gameWon && ( +

+ Hint: The prompt starts with: {getHint()} +

+ )}
) : ( From 18a094caeee46c3ae299db40cfa8f542409ba22b Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:24:16 +0000 Subject: [PATCH 04/26] Fix build configuration and directory structure - Added proper Vite configuration - Fixed directory structure to match Vite requirements - Added missing index.css file - Updated build settings - Successfully building to dist directory The build is now working correctly and generating the necessary files. Mentat precommits passed. Log: https://mentat.ai/log/549d3bf4-9953-43bc-8d8a-e879e2a81697 --- index.html => prompt-guessing-game/index.html | 0 {src => prompt-guessing-game/src}/App.css | 0 {src => prompt-guessing-game/src}/App.jsx | 0 prompt-guessing-game/src/index.css | 32 ++++++++ {src => prompt-guessing-game/src}/main.jsx | 0 prompt-guessing-game/vite.config.js | 13 ++++ src/utils.js | 78 ------------------- 7 files changed, 45 insertions(+), 78 deletions(-) rename index.html => prompt-guessing-game/index.html (100%) rename {src => prompt-guessing-game/src}/App.css (100%) rename {src => prompt-guessing-game/src}/App.jsx (100%) create mode 100644 prompt-guessing-game/src/index.css rename {src => prompt-guessing-game/src}/main.jsx (100%) create mode 100644 prompt-guessing-game/vite.config.js delete mode 100644 src/utils.js diff --git a/index.html b/prompt-guessing-game/index.html similarity index 100% rename from index.html rename to prompt-guessing-game/index.html diff --git a/src/App.css b/prompt-guessing-game/src/App.css similarity index 100% rename from src/App.css rename to prompt-guessing-game/src/App.css diff --git a/src/App.jsx b/prompt-guessing-game/src/App.jsx similarity index 100% rename from src/App.jsx rename to prompt-guessing-game/src/App.jsx diff --git a/prompt-guessing-game/src/index.css b/prompt-guessing-game/src/index.css new file mode 100644 index 0000000..c1776bb --- /dev/null +++ b/prompt-guessing-game/src/index.css @@ -0,0 +1,32 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + margin: 0; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 2.2em; + line-height: 1.1; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } +} \ No newline at end of file diff --git a/src/main.jsx b/prompt-guessing-game/src/main.jsx similarity index 100% rename from src/main.jsx rename to prompt-guessing-game/src/main.jsx diff --git a/prompt-guessing-game/vite.config.js b/prompt-guessing-game/vite.config.js new file mode 100644 index 0000000..fdafbd4 --- /dev/null +++ b/prompt-guessing-game/vite.config.js @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + build: { + outDir: 'dist', + assetsDir: 'assets', + }, + server: { + port: 3000, + }, +}) \ No newline at end of file diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index b22be77..0000000 --- a/src/utils.js +++ /dev/null @@ -1,78 +0,0 @@ -// Function to generate a creative prompt using text.pollinations.ai -export async function generatePrompt() { - try { - const response = await fetch('https://text.pollinations.ai/v1/generate', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - prompt: 'Generate a creative and descriptive image prompt that would be interesting to visualize.', - max_tokens: 50, - }), - }); - - if (!response.ok) { - throw new Error('Failed to generate prompt'); - } - - const data = await response.json(); - return data.choices[0].text.trim(); - } catch (error) { - console.error('Error generating prompt:', error); - throw error; - } -} - -// Function to generate an image from a prompt using image.pollinations.ai -export async function generateImage(prompt) { - try { - const response = await fetch('https://image.pollinations.ai/prompt/' + encodeURIComponent(prompt)); - - if (!response.ok) { - throw new Error('Failed to generate image'); - } - - return response.url; - } catch (error) { - console.error('Error generating image:', error); - throw error; - } -} - -// Function to evaluate similarity between guess and actual prompt -export async function evaluateGuess(guess, actualPrompt) { - try { - const response = await fetch('https://text.pollinations.ai/v1/similarity', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - text1: guess, - text2: actualPrompt, - }), - }); - - if (!response.ok) { - throw new Error('Failed to evaluate guess'); - } - - const data = await response.json(); - const similarity = data.similarity; - - // Return feedback based on similarity score - if (similarity > 0.9) { - return { message: "Perfect! You got it!", isCorrect: true, similarity }; - } else if (similarity > 0.7) { - return { message: "Very close! Try being more specific.", isCorrect: false, similarity }; - } else if (similarity > 0.5) { - return { message: "You're on the right track!", isCorrect: false, similarity }; - } else { - return { message: "Not quite. Try a different approach.", isCorrect: false, similarity }; - } - } catch (error) { - console.error('Error evaluating guess:', error); - throw error; - } -} \ No newline at end of file From 68be43a5f1af0fbc17087e92e70442f1e50d7116 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:07:17 +0100 Subject: [PATCH 05/26] Update deploy-apps.yml --- .github/workflows/deploy-apps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apps.yml b/.github/workflows/deploy-apps.yml index 476621b..ff648a7 100644 --- a/.github/workflows/deploy-apps.yml +++ b/.github/workflows/deploy-apps.yml @@ -55,7 +55,7 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ${{ github.event_name == 'pull_request' && './pr-preview' || './dist' }} + publish_dir: ${{ github.event_name == 'pull_request' && './dist' || './pr-preview' }} destination_dir: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'main' }} keep_files: true enable_jekyll: false From 38eaf60135a1570505529189c7690c67c006a7af Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:21:13 +0100 Subject: [PATCH 06/26] Update utils.js --- prompt-guessing-game/src/utils.js | 73 +++++++++++++++++-------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/prompt-guessing-game/src/utils.js b/prompt-guessing-game/src/utils.js index b22be77..5b65b16 100644 --- a/prompt-guessing-game/src/utils.js +++ b/prompt-guessing-game/src/utils.js @@ -1,23 +1,16 @@ // Function to generate a creative prompt using text.pollinations.ai export async function generatePrompt() { try { - const response = await fetch('https://text.pollinations.ai/v1/generate', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - prompt: 'Generate a creative and descriptive image prompt that would be interesting to visualize.', - max_tokens: 50, - }), - }); + const seed = Math.floor(Math.random() * 1000000); + const promptRequest = encodeURIComponent('Generate a creative and descriptive image prompt that would be interesting to visualize. Keep it concise.'); + const response = await fetch(`https://text.pollinations.ai/${promptRequest}?seed=${seed}`); if (!response.ok) { throw new Error('Failed to generate prompt'); } - const data = await response.json(); - return data.choices[0].text.trim(); + const text = await response.text(); + return text.trim(); } catch (error) { console.error('Error generating prompt:', error); throw error; @@ -27,7 +20,8 @@ export async function generatePrompt() { // Function to generate an image from a prompt using image.pollinations.ai export async function generateImage(prompt) { try { - const response = await fetch('https://image.pollinations.ai/prompt/' + encodeURIComponent(prompt)); + const seed = Math.floor(Math.random() * 1000000); + const response = await fetch(`https://image.pollinations.ai/prompt/${encodeURIComponent(prompt)}?seed=${seed}`); if (!response.ok) { throw new Error('Failed to generate image'); @@ -43,36 +37,47 @@ export async function generateImage(prompt) { // Function to evaluate similarity between guess and actual prompt export async function evaluateGuess(guess, actualPrompt) { try { - const response = await fetch('https://text.pollinations.ai/v1/similarity', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - text1: guess, - text2: actualPrompt, - }), - }); + const seed = Math.floor(Math.random() * 1000000); + const promptRequest = encodeURIComponent( + `Rate how similar these two image prompts are on a scale of 0-100, responding with ONLY a number: + Prompt 1: "${guess}" + Prompt 2: "${actualPrompt}"` + ); + const response = await fetch(`https://text.pollinations.ai/${promptRequest}?seed=${seed}`); if (!response.ok) { throw new Error('Failed to evaluate guess'); } - const data = await response.json(); - const similarity = data.similarity; - + const scoreText = await response.text(); + const similarity = parseInt(scoreText.trim(), 10) / 100; + // Return feedback based on similarity score - if (similarity > 0.9) { - return { message: "Perfect! You got it!", isCorrect: true, similarity }; - } else if (similarity > 0.7) { - return { message: "Very close! Try being more specific.", isCorrect: false, similarity }; - } else if (similarity > 0.5) { - return { message: "You're on the right track!", isCorrect: false, similarity }; + if (similarity > 0.8) { + return { message: `Perfect! You got it! (Score: ${Math.round(similarity * 100)}%)`, isCorrect: true, similarity }; + } else if (similarity > 0.6) { + return { message: `Very close! Try being more specific. (Score: ${Math.round(similarity * 100)}%)`, isCorrect: false, similarity }; + } else if (similarity > 0.4) { + return { message: `You're on the right track! (Score: ${Math.round(similarity * 100)}%)`, isCorrect: false, similarity }; } else { - return { message: "Not quite. Try a different approach.", isCorrect: false, similarity }; + return { message: `Not quite. Try a different approach. (Score: ${Math.round(similarity * 100)}%)`, isCorrect: false, similarity }; } } catch (error) { console.error('Error evaluating guess:', error); - throw error; + // Fallback to word overlap method if API fails + const normalizedGuess = guess.toLowerCase().trim(); + const normalizedActual = actualPrompt.toLowerCase().trim(); + + const guessWords = new Set(normalizedGuess.split(/\s+/)); + const actualWords = new Set(normalizedActual.split(/\s+/)); + const intersection = new Set([...guessWords].filter(x => actualWords.has(x))); + const union = new Set([...guessWords, ...actualWords]); + const similarity = intersection.size / union.size; + + return { + message: `Score (word overlap): ${Math.round(similarity * 100)}%`, + isCorrect: similarity > 0.8, + similarity + }; } } \ No newline at end of file From 78b55d48501052561f6fc1bb9f9e7d2deb51d94c Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:27:22 +0100 Subject: [PATCH 07/26] Update vite.config.js --- prompt-guessing-game/vite.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/prompt-guessing-game/vite.config.js b/prompt-guessing-game/vite.config.js index fdafbd4..7da6a7e 100644 --- a/prompt-guessing-game/vite.config.js +++ b/prompt-guessing-game/vite.config.js @@ -5,7 +5,6 @@ export default defineConfig({ plugins: [react()], build: { outDir: 'dist', - assetsDir: 'assets', }, server: { port: 3000, From 978a7ee2b254d148ca3748a4e92d8c91b9fce820 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:40:10 +0100 Subject: [PATCH 08/26] Update vite.config.js --- prompt-guessing-game/vite.config.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/prompt-guessing-game/vite.config.js b/prompt-guessing-game/vite.config.js index 7da6a7e..98a5356 100644 --- a/prompt-guessing-game/vite.config.js +++ b/prompt-guessing-game/vite.config.js @@ -1,12 +1,24 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], + base: '/prompt-guessing-game/', build: { outDir: 'dist', + assetsDir: 'assets', + rollupOptions: { + output: { + manualChunks: undefined, + assetFileNames: 'assets/[name]-[hash][extname]', + chunkFileNames: 'assets/[name]-[hash].js', + entryFileNames: 'assets/[name]-[hash].js', + }, + }, }, server: { - port: 3000, - }, + port: 5173, + host: true + } }) \ No newline at end of file From 775d517283bfd001ece3abf219ee27562464df4b Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:42:10 +0100 Subject: [PATCH 09/26] Update vite.config.js --- prompt-guessing-game/vite.config.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/prompt-guessing-game/vite.config.js b/prompt-guessing-game/vite.config.js index 98a5356..1f9fd77 100644 --- a/prompt-guessing-game/vite.config.js +++ b/prompt-guessing-game/vite.config.js @@ -1,21 +1,11 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - base: '/prompt-guessing-game/', build: { outDir: 'dist', assetsDir: 'assets', - rollupOptions: { - output: { - manualChunks: undefined, - assetFileNames: 'assets/[name]-[hash][extname]', - chunkFileNames: 'assets/[name]-[hash].js', - entryFileNames: 'assets/[name]-[hash].js', - }, - }, }, server: { port: 5173, From 2046ac5efc7f8bbcec55ea9e833856cb434f77a7 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 01:47:08 +0100 Subject: [PATCH 10/26] Update vite.config.js --- prompt-guessing-game/vite.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/prompt-guessing-game/vite.config.js b/prompt-guessing-game/vite.config.js index 1f9fd77..630a566 100644 --- a/prompt-guessing-game/vite.config.js +++ b/prompt-guessing-game/vite.config.js @@ -3,6 +3,7 @@ import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], + base: '/hive/prompt-guessing-game/', // GitHub Pages path: username.github.io/hive/prompt-guessing-game build: { outDir: 'dist', assetsDir: 'assets', From bc87a8c0f781302cd2ed40d101759acb09d3401a Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:30:49 +0100 Subject: [PATCH 11/26] Crop --- llm-feedback/index.html | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/llm-feedback/index.html b/llm-feedback/index.html index 4e2c8be..af4337f 100644 --- a/llm-feedback/index.html +++ b/llm-feedback/index.html @@ -351,7 +351,16 @@

History

continue; } - frames.push(text); + // Extract the state from between backticks if present + const stateMatch = text.match(/```([\s\S]*?)```/); + const state = stateMatch ? stateMatch[1] : text; + + // Split into lines and ensure correct dimensions (35x20) + const lines = state.split('\n').map(line => line.padEnd(35, ' ').slice(0, 35)); + const paddedState = lines.slice(0, 20).join('\n'); + const finalState = paddedState.padEnd(35 * 20 + 19, '\n' + ' '.repeat(35)).slice(0, 35 * 20 + 19); + + frames.push(finalState); currentState = text; // Keep full text for LLM context console.log('State updated, frame count:', frames.length); @@ -364,7 +373,7 @@

History

// Wait 3 seconds before next iteration console.log('Waiting 3 seconds...'); - await new Promise(resolve => setTimeout(resolve, 2000)); + await new Promise(resolve => setTimeout(resolve, 200)); console.log('Wait complete'); } catch (error) { console.error('Evolution error:', error); From 81f145060a30f08ea1f36d00ff92fbc03d486588 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:44:30 +0100 Subject: [PATCH 12/26] Add svg feedback experiment --- src/index.css | 32 ---- svg-feedback/index.html | 404 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 404 insertions(+), 32 deletions(-) delete mode 100644 src/index.css create mode 100644 svg-feedback/index.html diff --git a/src/index.css b/src/index.css deleted file mode 100644 index c1776bb..0000000 --- a/src/index.css +++ /dev/null @@ -1,32 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -body { - margin: 0; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 2.2em; - line-height: 1.1; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } -} \ No newline at end of file diff --git a/svg-feedback/index.html b/svg-feedback/index.html new file mode 100644 index 0000000..215065e --- /dev/null +++ b/svg-feedback/index.html @@ -0,0 +1,404 @@ + + + + + + LLM SVG Art Evolution + + + +

LLM SVG Art Evolution

+ +
+ + + + + + + + + +
+
+ + + 0.8 +
+
+ + +
+
+ +
+ +
+ + +
+ +
+ + +
+
+ +
+

History

+
+
+ + + + From b4c9f3267b8e16d1ca855f90a525d6bf7307bf46 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:46:03 +0100 Subject: [PATCH 13/26] Update index.html --- svg-feedback/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 215065e..9351174 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -218,7 +218,7 @@

History

.then(r => r.json()) .then(models => { elements.modelSelect.innerHTML = models - .map(m => ``) + .map(m => ``) .join(''); }); From 4c9c87659aacdf29f7d87084f4be49356564e3bd Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:48:46 +0100 Subject: [PATCH 14/26] Update index.html --- svg-feedback/index.html | 202 +++++++++++++++++++++++++++------------- 1 file changed, 137 insertions(+), 65 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 9351174..c97e683 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -5,74 +5,106 @@ LLM SVG Art Evolution @@ -106,16 +178,16 @@

LLM SVG Art Evolution

@@ -171,45 +243,45 @@

History

// Presets for SVG generation const presets = { - geometric: { - prompt: "Create an SVG with basic geometric shapes (circles, rectangles, polygons) arranged in a balanced composition. Use clean lines and primary colors. The shapes should form an abstract pattern that suggests movement and harmony.", - temperature: 0.8 - }, - organic: { - prompt: "Generate an SVG with flowing, organic curves using path elements. Create natural, biomorphic shapes that suggest growth and movement. Include gentle gradients and earth tones.", + solarpunk: { + prompt: "Create an evolving solarpunk cityscape where nature and technology harmoniously intertwine. Use flowing organic curves for plant life mixed with clean geometric shapes for sustainable architecture. Include animated elements like swaying trees, floating gardens, and shimmering solar panels. Use vibrant greens and warm sunlit colors.", temperature: 0.9 }, - abstract: { - prompt: "Design an abstract SVG composition using a mix of geometric and organic shapes. Layer transparent elements, use bold colors, and create dynamic intersections between shapes. Think Kandinsky-style modernist artwork.", - temperature: 0.9 - }, - landscape: { - prompt: "Create a minimalist landscape SVG using simple shapes and lines. Represent hills, trees, or buildings using geometric abstractions. Use a limited color palette with subtle gradients for depth.", - temperature: 0.7 - }, - portrait: { - prompt: "Generate an abstract face or portrait using SVG shapes. Use simple geometric forms to suggest facial features. Create an expressive composition that balances representation and abstraction.", + isometric: { + prompt: "Generate an isometric architectural composition inspired by M.C. Escher and impossible geometry. Create intricate 3D structures with precise angles, interconnected pathways, and recursive patterns. Use animated perspective shifts and transformations. Employ a sophisticated color palette with subtle gradients.", temperature: 0.8 }, - circuit: { - prompt: "Design an SVG that resembles a circuit board pattern. Use straight lines, right angles, and circular connection points. Create a complex network of paths that suggests technological connectivity.", + cellular: { + prompt: "Visualize a cellular automaton system inspired by Conway's Game of Life but with artistic flair. Create evolving patterns of geometric cells that pulse, grow, and transform. Use animated transitions between states. Incorporate mathematical beauty with organic unpredictability.", + temperature: 0.85 + }, + bauhaus: { + prompt: "Design an animated Bauhaus-inspired composition that celebrates geometric abstraction and modernist principles. Use primary colors, bold shapes, and clean lines in dynamic arrangements. Include subtle rotations and translations that reflect industrial rhythm and mechanical precision.", temperature: 0.7 }, - mandala: { - prompt: "Generate a symmetrical mandala pattern using SVG. Create intricate geometric patterns that radiate from the center. Use repetition and mathematical precision in the arrangement of shapes.", - temperature: 0.8 + quantum: { + prompt: "Visualize quantum phenomena through abstract art - wave-particle duality, superposition, and entanglement. Create animated probability clouds, interference patterns, and quantum tunneling effects. Use ethereal colors and translucent layers to suggest the mysterious nature of quantum reality.", + temperature: 0.95 }, - waves: { - prompt: "Create an SVG pattern of intersecting waves and ripples. Use curved paths and varying stroke widths to suggest interference patterns. Layer semi-transparent shapes to create depth and complexity.", - temperature: 0.85 + biomorphic: { + prompt: "Create a living system of biomorphic forms inspired by Ernst Haeckel's scientific illustrations. Design intricate organic shapes that grow, divide, and evolve. Use animated transformations to suggest cellular processes and biological rhythms. Include delicate details and symmetrical patterns.", + temperature: 0.9 }, - grid: { - prompt: "Generate a grid-based SVG composition. Create variations in the grid using different sizes and colors of shapes. Include occasional disruptions to the pattern for visual interest.", - temperature: 0.7 + cosmology: { + prompt: "Design an abstract representation of cosmic architecture - galaxy formations, gravitational lensing, and spacetime fabric. Create animated elements suggesting orbital motion and celestial mechanics. Use deep space colors and geometric patterns inspired by astronomical phenomena.", + temperature: 0.85 }, - flow: { - prompt: "Design an SVG flow field visualization. Create patterns of curved lines that suggest fluid dynamics or magnetic fields. Use varying line weights and colors to indicate field strength.", + neural: { + prompt: "Visualize a garden of artificial neural networks as living, breathing entities. Create organic-mechanical hybrid forms with animated synaptic connections and information flows. Show learning and adaptation through evolving patterns and emergent behaviors.", temperature: 0.9 + }, + meditation: { + prompt: "Generate abstract visualizations of inner mental states and consciousness. Create flowing mandalas and organic patterns that pulse with meditative rhythms. Use subtle animations and transitions to induce contemplative states. Incorporate sacred geometry and archetypal forms.", + temperature: 0.8 + }, + emergence: { + prompt: "Design a complex system showing emergent behavior from simple rules. Create animated patterns that suggest flocking birds, forming crystals, or growing cities. Use mathematical principles to generate organic complexity. Show how individual elements combine to create larger organized structures.", + temperature: 0.85 } }; @@ -235,8 +307,8 @@

History

function createEmptyCanvas() { elements.preview.innerHTML = ` - - + + Start evolution to generate SVG art From 7123bda463728a239d4386c546df7d4178f9a0e7 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:54:33 +0100 Subject: [PATCH 15/26] Update index.html --- svg-feedback/index.html | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index c97e683..adef79c 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -244,7 +244,7 @@

History

// Presets for SVG generation const presets = { solarpunk: { - prompt: "Create an evolving solarpunk cityscape where nature and technology harmoniously intertwine. Use flowing organic curves for plant life mixed with clean geometric shapes for sustainable architecture. Include animated elements like swaying trees, floating gardens, and shimmering solar panels. Use vibrant greens and warm sunlit colors.", + prompt: "Isometric minimalism. Game engine. Create an evolving solarpunk cityscape where nature and technology harmoniously intertwine. Use flowing organic curves for plant life mixed with clean geometric shapes for sustainable architecture. Include animated elements like swaying trees, floating gardens, and shimmering solar panels. Use vibrant greens and warm sunlit colors.", temperature: 0.9 }, isometric: { @@ -342,15 +342,18 @@

History

const systemPrompt = `You are an animated SVG art generator. Create SVG code that fits within a 800x600 viewBox. Follow these rules: 1. Always start with and proper SVG tags - 2. Use simple shapes, paths, and basic SVG elements + 2. Dont modify too many things at once if receiving a previous state 3. Include style definitions in a section 4. Always ensure the SVG is complete and properly closed 5. If evolving from a previous state, introduce only gradual changes! 6. Return ONLY the SVG code wrapped in \`\`\`svg code blocks 7. use animations abundantly - - Current state: ${currentState ? 'Building upon previous SVG. Change gradually.' : 'Creating initial SVG'}`; + Creative Direction: ${prompt}`; + + const userMessage = currentState ? + `Here is the previous SVG state. Evolve it gradually while maintaining its essence:\n\n${currentState}` : + "Generate the initial SVG state following the creative direction."; try { const response = await fetch('https://text.pollinations.ai/', { @@ -360,7 +363,7 @@

History

model, messages: [ { role: "system", content: systemPrompt }, - { role: "user", content: prompt } + { role: "user", content: userMessage } ], temperature, seed From 2fcdbc231be0ec4877c644e1c5a8163c6efd2133 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:55:58 +0100 Subject: [PATCH 16/26] Update index.html --- svg-feedback/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index adef79c..c427e68 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -348,6 +348,7 @@

History

5. If evolving from a previous state, introduce only gradual changes! 6. Return ONLY the SVG code wrapped in \`\`\`svg code blocks 7. use animations abundantly + 8. please add directions for the next evolution as explanation underneath the svg Creative Direction: ${prompt}`; From 3177b8335b365d41bcaa4ead4c03504fdd9c1e20 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 12:57:41 +0100 Subject: [PATCH 17/26] Update index.html --- svg-feedback/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index c427e68..3f875ca 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -303,6 +303,7 @@

History

let frames = []; let frameIndex = 0; let animationTimer = null; + let currentSeed = 42; function createEmptyCanvas() { elements.preview.innerHTML = ` @@ -337,7 +338,7 @@

History

const temperature = parseFloat(elements.temperature.value); const seed = parseInt(elements.seed.value) >= 0 ? parseInt(elements.seed.value) : - Math.floor(Math.random() * 1000000) + retryCount; // Add retryCount to ensure different seeds + currentSeed++; // Use and increment the deterministic seed const systemPrompt = `You are an animated SVG art generator. Create SVG code that fits within a 800x600 viewBox. Follow these rules: From 7e993fdbf6775acfe9412a55ef810ac1e06efdc1 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 13:33:33 +0100 Subject: [PATCH 18/26] Beautiful version --- svg-feedback/index.html | 320 ++++++++++++++-------------------------- svg-feedback/styles.css | 217 +++++++++++++++++++++++++++ 2 files changed, 327 insertions(+), 210 deletions(-) create mode 100644 svg-feedback/styles.css diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 3f875ca..d4172bd 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -4,173 +4,7 @@ LLM SVG Art Evolution - +

LLM SVG Art Evolution

@@ -178,12 +12,13 @@

LLM SVG Art Evolution

-
-
- - - 0.8 -
-
- - -
+
+ + + 0.8 +
+
+ +
-
- - +
+ +
-
+
+ Frame 0/0
@@ -235,14 +69,27 @@

History

temperatureValue: document.getElementById('temperature-value'), seed: document.getElementById('seed'), preview: document.getElementById('preview-window'), - speedSlider: document.getElementById('speed-slider'), start: document.getElementById('startBtn'), stop: document.getElementById('stopBtn'), + speedSlider: document.getElementById('speed-slider'), + frameCounter: document.getElementById('frame-counter'), history: document.getElementById('history') }; // Presets for SVG generation const presets = { + biomorphic: { + prompt: "Create a living system of biomorphic forms inspired by Ernst Haeckel's scientific illustrations. Design intricate organic shapes that grow, divide, and evolve. Use animated transformations to suggest cellular processes and biological rhythms. Include delicate details and symmetrical patterns.", + temperature: 0.9 + }, + boids: { + prompt: "Create a dynamic flock of abstract geometric birds (boids) following Craig Reynolds' flocking rules: alignment, cohesion, and separation. Use simple triangular or arrow-like shapes for the boids. Animate their movement with smooth paths, rotation, and subtle variations. Include emergent flocking behavior and occasional splitting/merging of groups. Use a minimal color palette inspired by early computer graphics.", + temperature: 0.85 + }, + retrogame: { + prompt: "Create an animated scene inspired by classic 8-bit and 16-bit video games. Use pixel-perfect geometric shapes, limited color palettes, and simple patterns. Include game elements like platforms, power-ups, or enemies with classic gaming animations (bouncing, rotating, pulsing). Add scan lines or CRT effects for authenticity. Think early Nintendo or Atari aesthetic with smooth sprite animations.", + temperature: 0.85 + }, solarpunk: { prompt: "Isometric minimalism. Game engine. Create an evolving solarpunk cityscape where nature and technology harmoniously intertwine. Use flowing organic curves for plant life mixed with clean geometric shapes for sustainable architecture. Include animated elements like swaying trees, floating gardens, and shimmering solar panels. Use vibrant greens and warm sunlit colors.", temperature: 0.9 @@ -263,10 +110,6 @@

History

prompt: "Visualize quantum phenomena through abstract art - wave-particle duality, superposition, and entanglement. Create animated probability clouds, interference patterns, and quantum tunneling effects. Use ethereal colors and translucent layers to suggest the mysterious nature of quantum reality.", temperature: 0.95 }, - biomorphic: { - prompt: "Create a living system of biomorphic forms inspired by Ernst Haeckel's scientific illustrations. Design intricate organic shapes that grow, divide, and evolve. Use animated transformations to suggest cellular processes and biological rhythms. Include delicate details and symmetrical patterns.", - temperature: 0.9 - }, cosmology: { prompt: "Design an abstract representation of cosmic architecture - galaxy formations, gravitational lensing, and spacetime fabric. Create animated elements suggesting orbital motion and celestial mechanics. Use deep space colors and geometric patterns inspired by astronomical phenomena.", temperature: 0.85 @@ -302,12 +145,13 @@

History

let isRunning = false; let frames = []; let frameIndex = 0; - let animationTimer = null; - let currentSeed = 42; + let currentSeed; + let lastFrameTime = 0; + let animationFrame = null; function createEmptyCanvas() { elements.preview.innerHTML = ` - + Start evolution to generate SVG art @@ -321,15 +165,48 @@

History

return svgMatch ? svgMatch[1].trim() : null; } + function updateFrame(currentFrame) { + // Update preview + elements.preview.innerHTML = frames[currentFrame]; + + // Update frame counter + elements.frameCounter.textContent = `Frame ${currentFrame + 1}/${frames.length}`; + + // Update history highlight + const historyItems = document.querySelectorAll('.history-item'); + historyItems.forEach((item, index) => { + if (index === currentFrame) { + item.classList.add('active'); + } else { + item.classList.remove('active'); + } + }); + } + function startPreviewAnimation() { - if (animationTimer) clearInterval(animationTimer); + if (animationFrame) { + cancelAnimationFrame(animationFrame); + } - animationTimer = setInterval(() => { - if (frames.length > 0) { - elements.preview.innerHTML = frames[frameIndex]; + lastFrameTime = performance.now(); + frameIndex = 0; + + function animate(currentTime) { + const frameDelay = parseInt(elements.speedSlider.value); + const elapsed = currentTime - lastFrameTime; + + if (elapsed >= frameDelay && frames.length > 0) { + updateFrame(frameIndex); frameIndex = (frameIndex + 1) % frames.length; + lastFrameTime = currentTime; } - }, parseInt(elements.speedSlider.value)); + + if (isRunning) { + animationFrame = requestAnimationFrame(animate); + } + } + + animationFrame = requestAnimationFrame(animate); } async function generateText(prompt, currentState, retryCount = 0) { @@ -338,7 +215,7 @@

History

const temperature = parseFloat(elements.temperature.value); const seed = parseInt(elements.seed.value) >= 0 ? parseInt(elements.seed.value) : - currentSeed++; // Use and increment the deterministic seed + currentSeed++; // Use and increment the current seed const systemPrompt = `You are an animated SVG art generator. Create SVG code that fits within a 800x600 viewBox. Follow these rules: @@ -357,6 +234,13 @@

History

`Here is the previous SVG state. Evolve it gradually while maintaining its essence:\n\n${currentState}` : "Generate the initial SVG state following the creative direction."; + console.log('=== LLM Request ==='); + console.log('System:', systemPrompt); + console.log('User:', userMessage); + console.log('Temperature:', temperature); + console.log('Seed:', seed); + console.log('Model:', model); + try { const response = await fetch('https://text.pollinations.ai/', { method: 'POST', @@ -375,6 +259,9 @@

History

if (!response.ok) throw new Error('API request failed'); const text = await response.text(); + console.log('=== LLM Response ==='); + console.log(text); + const svgContent = extractSvgContent(text); // Validate SVG completeness @@ -387,14 +274,13 @@

History

} return svgContent; + } catch (error) { - console.error(`Generation error (attempt ${retryCount + 1}/${maxRetries + 1}):`, error); - + console.error('Error:', error); if (retryCount < maxRetries) { - console.log('Retrying with a different seed...'); + console.log(`Retry ${retryCount + 1}/${maxRetries}: ${error.message}`); return generateText(prompt, currentState, retryCount + 1); } - return null; } } @@ -420,23 +306,36 @@

History

const historyItem = document.createElement('div'); historyItem.className = 'history-item'; historyItem.innerHTML = ` -
+
${svgContent}
`; - elements.history.insertBefore(historyItem, elements.history.firstChild); + elements.history.appendChild(historyItem); + + // If this is the first frame, start the animation + if (frames.length === 1) { + startPreviewAnimation(); + } // Keep evolving if (isRunning) { - setTimeout(evolve, 100); + setTimeout(evolve, 1500); } } else { console.error('Failed to generate SVG content'); - stopEvolution(); + if (isRunning) { + currentSeed++; + elements.seed.value = currentSeed; + setTimeout(evolve, 1500); + } } } catch (error) { console.error('Evolution error:', error); - stopEvolution(); + if (isRunning) { + currentSeed++; + elements.seed.value = currentSeed; + setTimeout(evolve, 1500); + } } } @@ -446,17 +345,18 @@

History

elements.stop.disabled = false; frames = []; frameIndex = 0; + currentSeed = parseInt(elements.seed.value); + elements.frameCounter.textContent = 'Frame 0/0'; evolve(); - startPreviewAnimation(); } function stopEvolution() { isRunning = false; elements.start.disabled = false; elements.stop.disabled = true; - if (animationTimer) { - clearInterval(animationTimer); - animationTimer = null; + if (animationFrame) { + cancelAnimationFrame(animationFrame); + animationFrame = null; } } diff --git a/svg-feedback/styles.css b/svg-feedback/styles.css new file mode 100644 index 0000000..e850b59 --- /dev/null +++ b/svg-feedback/styles.css @@ -0,0 +1,217 @@ +:root { + --bg-primary: #1a1a1a; + --bg-secondary: #2a2a2a; + --text-primary: #ffffff; + --text-secondary: #cccccc; + --accent: #4f9eff; + --border: #404040; + --input-bg: #333333; + --button-bg: #4f9eff; + --button-text: #ffffff; +} + +body { + font-family: system-ui, -apple-system, sans-serif; + margin: 0; + padding: 20px; + background: var(--bg-primary); + color: var(--text-primary); +} + +.container { + max-width: 600px; + margin: 0 auto 20px auto; + padding: 15px; + background: var(--bg-secondary); + border-radius: 8px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); + border: 1px solid var(--border); +} + +h1 { + font-size: 1.5rem; + margin: 0 0 15px 0; +} + +h2 { + font-size: 1.2rem; + margin: 10px 0; +} + +select, textarea { + width: 100%; + padding: 5px; + margin: 5px 0; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--input-bg); + color: var(--text-primary); + font-family: inherit; +} + +select:focus, textarea:focus { + outline: none; + border-color: var(--accent); +} + +.svg-container { + display: block; + width: 480px; + height: 360px; + overflow: hidden; + background: var(--bg-primary); + padding: 10px; + border: 1px solid var(--border); + border-radius: 4px; + margin: 0 auto; + transform: translateZ(0); + backface-visibility: hidden; + perspective: 1000; + will-change: transform; +} + +.svg-container svg { + width: 100%; + height: 100%; + display: block; +} + +button { + padding: 5px 10px; + margin: 5px; + background: var(--button-bg); + color: var(--button-text); + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.2s; +} + +button:hover { + background-color: #3d8beb; +} + +button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +#history { + display: flex; + flex-wrap: wrap; + gap: 5px; + margin-top: 5px; +} + +.history-item { + display: inline-block; + margin: 5px; + padding: 5px; + border: 2px solid var(--border); + border-radius: 4px; + background: var(--bg-secondary); + transition: border-color 0.2s ease-in-out; +} + +.history-item.active { + border-color: var(--accent); +} + +label { + display: block; + margin: 5px 0; + color: var(--text-secondary); +} + +input[type="number"] { + background: var(--input-bg); + color: var(--text-primary); + border: 1px solid var(--border); + border-radius: 4px; + padding: 4px 8px; +} + +input[type="range"] { + accent-color: var(--accent); +} + +#speed-slider { + -webkit-appearance: none; + background: var(--border); + height: 2px; + direction: rtl; +} + +#speed-slider::-webkit-slider-thumb { + -webkit-appearance: none; + width: 15px; + height: 15px; + border-radius: 50%; + background: var(--accent); + cursor: pointer; + transition: background-color 0.2s; +} + +#speed-slider::-webkit-slider-thumb:hover { + background: #3d8be6; +} + +#speed-slider::-moz-range-thumb { + width: 15px; + height: 15px; + border-radius: 50%; + background: var(--accent); + cursor: pointer; + border: none; + transition: background-color 0.2s; +} + +#speed-slider::-moz-range-thumb:hover { + background: #3d8be6; +} + +#speed-slider::-moz-range-progress { + background-color: transparent; +} + +.temperature-container, .seed-container, .speed-slider-container { + display: flex; + align-items: center; + gap: 10px; + margin: 10px 0; +} + +.speed-slider-container { + margin-top: 10px; +} + +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--bg-secondary); +} + +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--accent); +} + +.controls { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 10px; +} + +.frame-counter { + color: var(--text-secondary); + font-family: monospace; + margin-left: 10px; +} From c15e53d7022a79a93b55bb094a409969e4627a87 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 13:46:19 +0100 Subject: [PATCH 19/26] Update index.html --- svg-feedback/index.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index d4172bd..3ee167c 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -146,6 +146,7 @@

History

let frames = []; let frameIndex = 0; let currentSeed; + let initialSeed; let lastFrameTime = 0; let animationFrame = null; @@ -219,13 +220,14 @@

History

const systemPrompt = `You are an animated SVG art generator. Create SVG code that fits within a 800x600 viewBox. Follow these rules: + 0. Your code should be inspired by the demoscene. Self-containted. Small. Re-using elements and groups creatively. 1. Always start with and proper SVG tags 2. Dont modify too many things at once if receiving a previous state 3. Include style definitions in a section 4. Always ensure the SVG is complete and properly closed 5. If evolving from a previous state, introduce only gradual changes! 6. Return ONLY the SVG code wrapped in \`\`\`svg code blocks - 7. use animations abundantly + 7. animations should be slow and fluid 8. please add directions for the next evolution as explanation underneath the svg Creative Direction: ${prompt}`; @@ -345,7 +347,8 @@

History

elements.stop.disabled = false; frames = []; frameIndex = 0; - currentSeed = parseInt(elements.seed.value); + initialSeed = parseInt(elements.seed.value); + currentSeed = initialSeed; elements.frameCounter.textContent = 'Frame 0/0'; evolve(); } @@ -354,6 +357,8 @@

History

isRunning = false; elements.start.disabled = false; elements.stop.disabled = true; + currentSeed = initialSeed; + elements.seed.value = initialSeed; if (animationFrame) { cancelAnimationFrame(animationFrame); animationFrame = null; From 55df13cb3db8813478f50fe542f27896eb7b5ca5 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 13:56:38 +0100 Subject: [PATCH 20/26] Update index.html --- svg-feedback/index.html | 80 +++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 3ee167c..476b889 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -23,6 +23,7 @@

LLM SVG Art Evolution

+ @@ -49,8 +50,9 @@

LLM SVG Art Evolution

- - + + + Frame 0/0
@@ -69,15 +71,23 @@

History

temperatureValue: document.getElementById('temperature-value'), seed: document.getElementById('seed'), preview: document.getElementById('preview-window'), - start: document.getElementById('startBtn'), - stop: document.getElementById('stopBtn'), + start: document.getElementById('start'), + stop: document.getElementById('stop'), speedSlider: document.getElementById('speed-slider'), frameCounter: document.getElementById('frame-counter'), history: document.getElementById('history') }; - // Presets for SVG generation + // Load saved presets from localStorage + const savedPresets = JSON.parse(localStorage.getItem('savedPresets') || '{}'); + + // Base presets combined with saved presets const presets = { + 'neural': { + name: 'Neural Gardens', + prompt: "Create an abstract garden of neural networks. Use flowing lines and organic shapes to represent neurons, synapses, and the flow of information. Incorporate subtle color transitions and pulsing animations to suggest the dynamic nature of neural processing.", + temperature: 0.8 + }, biomorphic: { prompt: "Create a living system of biomorphic forms inspired by Ernst Haeckel's scientific illustrations. Design intricate organic shapes that grow, divide, and evolve. Use animated transformations to suggest cellular processes and biological rhythms. Include delicate details and symmetrical patterns.", temperature: 0.9 @@ -114,10 +124,6 @@

History

prompt: "Design an abstract representation of cosmic architecture - galaxy formations, gravitational lensing, and spacetime fabric. Create animated elements suggesting orbital motion and celestial mechanics. Use deep space colors and geometric patterns inspired by astronomical phenomena.", temperature: 0.85 }, - neural: { - prompt: "Visualize a garden of artificial neural networks as living, breathing entities. Create organic-mechanical hybrid forms with animated synaptic connections and information flows. Show learning and adaptation through evolving patterns and emergent behaviors.", - temperature: 0.9 - }, meditation: { prompt: "Generate abstract visualizations of inner mental states and consciousness. Create flowing mandalas and organic patterns that pulse with meditative rhythms. Use subtle animations and transitions to induce contemplative states. Incorporate sacred geometry and archetypal forms.", temperature: 0.8 @@ -125,9 +131,22 @@

History

emergence: { prompt: "Design a complex system showing emergent behavior from simple rules. Create animated patterns that suggest flocking birds, forming crystals, or growing cities. Use mathematical principles to generate organic complexity. Show how individual elements combine to create larger organized structures.", temperature: 0.85 + }, + 'digital-nature': { + prompt: `Create a mesmerizing fusion of nature and technology: a fractal tree growing from a digital seedling, +with branches that transform into circuitboard pathways lit by electric blue lightning. +Matrix-style digital rain falls in the background, but using varying shades of green and cyan. +The tree should grow slowly and majestically, +while the lightning pulses should be subtle and ethereal. The digital rain should fall at different speeds, +creating layers of depth. Color palette should focus on deep greens, electric blues, and cyan accents, +with occasional golden sparks where the lightning meets the tree branches.`, + temperature: 0.9 } }; + // Add saved presets to base presets + Object.assign(presets, savedPresets); + // Fetch available models fetch('https://text.pollinations.ai/models') .then(r => r.json()) @@ -365,6 +384,35 @@

History

} } + function getFirstFourWords(str) { + return str.split(/\s+/).slice(0, 4).join(' ').toLowerCase().replace(/[^\w\s-]/g, ''); + } + + function saveCurrentPreset() { + const prompt = elements.basePrompt.value; + const temperature = parseFloat(elements.temperature.value); + const key = getFirstFourWords(prompt); + + const savedPresets = JSON.parse(localStorage.getItem('savedPresets') || '{}'); + savedPresets[key] = { + prompt, + temperature, + name: key + }; + + localStorage.setItem('savedPresets', JSON.stringify(savedPresets)); + + // Add to select if not exists + if (!elements.presetSelect.querySelector(`option[value="${key}"]`)) { + const option = document.createElement('option'); + option.value = key; + option.textContent = key; + elements.presetSelect.appendChild(option); + } + + elements.presetSelect.value = key; + } + // Event Listeners elements.start.addEventListener('click', startEvolution); elements.stop.addEventListener('click', stopEvolution); @@ -379,8 +427,18 @@

History

}); // Initialize - createEmptyCanvas(); - elements.basePrompt.value = presets[elements.presetSelect.value].prompt; + document.addEventListener('DOMContentLoaded', () => { + // Add saved presets to select + Object.entries(savedPresets).forEach(([key, preset]) => { + const option = document.createElement('option'); + option.value = key; + option.textContent = preset.name; + elements.presetSelect.appendChild(option); + }); + createEmptyCanvas(); + elements.presetSelect.value = 'digital-nature'; + elements.basePrompt.value = presets['digital-nature'].prompt; + }); From aeca570a9b2b18b1f4dd6722e8c3e857a7c5252f Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 15:41:10 +0100 Subject: [PATCH 21/26] initial svg state --- svg-feedback/index.html | 74 ++++++++++++++++++++++++++++++----------- svg-feedback/styles.css | 16 +++++++++ 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 476b889..38a3004 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -27,8 +27,11 @@

LLM SVG Art Evolution

- + + + + @@ -75,7 +78,8 @@

History

stop: document.getElementById('stop'), speedSlider: document.getElementById('speed-slider'), frameCounter: document.getElementById('frame-counter'), - history: document.getElementById('history') + history: document.getElementById('history'), + initialSvg: document.getElementById('initial-svg') }; // Load saved presets from localStorage @@ -168,6 +172,7 @@

History

let initialSeed; let lastFrameTime = 0; let animationFrame = null; + let currentState = null; function createEmptyCanvas() { elements.preview.innerHTML = ` @@ -181,8 +186,22 @@

History

} function extractSvgContent(text) { - const svgMatch = text.match(/```(?:svg|xml)\n([\s\S]*?)\n```/); - return svgMatch ? svgMatch[1].trim() : null; + // Try to match SVG with language specifier + let svgMatch = text.match(/```(?:svg|xml)\n([\s\S]*?)\n```/); + if (svgMatch) return svgMatch[1].trim(); + + // Try to match SVG without language specifier + svgMatch = text.match(/```([\s\S]*?)```/); + if (svgMatch && svgMatch[1].trim().startsWith('History } lastFrameTime = performance.now(); - frameIndex = 0; function animate(currentTime) { const frameDelay = parseInt(elements.speedSlider.value); const elapsed = currentTime - lastFrameTime; if (elapsed >= frameDelay && frames.length > 0) { - updateFrame(frameIndex); frameIndex = (frameIndex + 1) % frames.length; + updateFrame(frameIndex); lastFrameTime = currentTime; } @@ -294,6 +312,8 @@

History

throw new Error('Incomplete SVG content'); } + console.log(`Response character count: ${text.length}`); + return svgContent; } catch (error) { @@ -313,7 +333,6 @@

History

const basePrompt = elements.basePrompt.value || preset.prompt; try { - const currentState = frames.length > 0 ? frames[frames.length - 1] : null; const evolutionPrompt = currentState ? `Evolve this SVG art while maintaining some consistency with the previous state. ${basePrompt}` : basePrompt; @@ -321,6 +340,7 @@

History

const svgContent = await generateText(evolutionPrompt, currentState); if (svgContent) { + currentState = svgContent; frames.push(svgContent); // Add to history @@ -333,7 +353,11 @@

History

`; elements.history.appendChild(historyItem); - // If this is the first frame, start the animation + // Update frame index to show the latest frame + frameIndex = frames.length - 1; + updateFrame(frameIndex); + + // Start animation if it's not already running if (frames.length === 1) { startPreviewAnimation(); } @@ -342,13 +366,6 @@

History

if (isRunning) { setTimeout(evolve, 1500); } - } else { - console.error('Failed to generate SVG content'); - if (isRunning) { - currentSeed++; - elements.seed.value = currentSeed; - setTimeout(evolve, 1500); - } } } catch (error) { console.error('Evolution error:', error); @@ -360,16 +377,33 @@

History

} } - function startEvolution() { + async function startEvolution() { + if (isRunning) return; + isRunning = true; elements.start.disabled = true; elements.stop.disabled = false; + frames = []; frameIndex = 0; - initialSeed = parseInt(elements.seed.value); - currentSeed = initialSeed; - elements.frameCounter.textContent = 'Frame 0/0'; - evolve(); + currentState = null; + + if (elements.initialSvg.value?.trim?.()) { + const prompt = elements.basePrompt.value; + const initialSvg = elements.initialSvg.value.trim() + `\n\nPrompt: ${prompt}`; + try { + const svgContent = extractSvgContent(initialSvg); + if (svgContent) { + currentState = svgContent; + frames.push(svgContent); + updateFrame(frameIndex); + } + } catch (error) { + console.error('Invalid initial SVG:', error); + } + } + + await evolve(); } function stopEvolution() { diff --git a/svg-feedback/styles.css b/svg-feedback/styles.css index e850b59..feb7254 100644 --- a/svg-feedback/styles.css +++ b/svg-feedback/styles.css @@ -215,3 +215,19 @@ input[type="range"] { font-family: monospace; margin-left: 10px; } + +textarea { + width: 100%; + margin-bottom: 1rem; + padding: 0.5rem; + border: 1px solid #ccc; + border-radius: 4px; + font-family: monospace; +} + +#initial-svg { + font-size: 0.9em; + background-color: #1a1a1a; + border-color: #333; + color: #aaa; +} From 47cf8fbd07b0fc7fbff73ca255fa878fd9c10abb Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 15:57:51 +0100 Subject: [PATCH 22/26] save preset too --- svg-feedback/index.html | 36 ++++++++++++++++++++++-------------- svg-feedback/styles.css | 24 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 38a3004..33ab567 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -83,7 +83,7 @@

History

}; // Load saved presets from localStorage - const savedPresets = JSON.parse(localStorage.getItem('savedPresets') || '{}'); + const savedPresets = JSON.parse(localStorage.getItem('savedPresets2') || '{}'); // Base presets combined with saved presets const presets = { @@ -423,28 +423,30 @@

History

} function saveCurrentPreset() { - const prompt = elements.basePrompt.value; - const temperature = parseFloat(elements.temperature.value); - const key = getFirstFourWords(prompt); + const name = prompt('Enter a name for this preset:'); + if (!name) return; - const savedPresets = JSON.parse(localStorage.getItem('savedPresets') || '{}'); - savedPresets[key] = { - prompt, - temperature, - name: key + const preset = { + name, + prompt: elements.basePrompt.value, + temperature: elements.temperature.value, + initialSvg: elements.initialSvg.value }; - localStorage.setItem('savedPresets', JSON.stringify(savedPresets)); + const savedPresets = JSON.parse(localStorage.getItem('savedPresets2') || '{}'); + savedPresets[name] = preset; + + localStorage.setItem('savedPresets2', JSON.stringify(savedPresets)); // Add to select if not exists - if (!elements.presetSelect.querySelector(`option[value="${key}"]`)) { + if (!elements.presetSelect.querySelector(`option[value="${name}"]`)) { const option = document.createElement('option'); - option.value = key; - option.textContent = key; + option.value = name; + option.textContent = name; elements.presetSelect.appendChild(option); } - elements.presetSelect.value = key; + elements.presetSelect.value = name; } // Event Listeners @@ -458,6 +460,9 @@

History

elements.basePrompt.value = preset.prompt; elements.temperature.value = preset.temperature; elements.temperatureValue.textContent = preset.temperature; + if (preset.initialSvg) { + elements.initialSvg.value = preset.initialSvg; + } }); // Initialize @@ -472,6 +477,9 @@

History

createEmptyCanvas(); elements.presetSelect.value = 'digital-nature'; elements.basePrompt.value = presets['digital-nature'].prompt; + if (presets['digital-nature'].initialSvg) { + elements.initialSvg.value = presets['digital-nature'].initialSvg; + } }); diff --git a/svg-feedback/styles.css b/svg-feedback/styles.css index feb7254..43e2cf4 100644 --- a/svg-feedback/styles.css +++ b/svg-feedback/styles.css @@ -96,11 +96,31 @@ button:disabled { cursor: not-allowed; } +#preview { + width: 100%; + aspect-ratio: 1; + border: 1px solid #ccc; + margin-bottom: 1rem; + overflow: hidden; +} + #history { display: flex; flex-wrap: wrap; - gap: 5px; - margin-top: 5px; + gap: 10px; + margin-top: 20px; + overflow: hidden; +} + +.history-item { + border: 1px solid #ccc; + padding: 5px; + cursor: pointer; + overflow: hidden; +} + +.history-item > div { + overflow: hidden; } .history-item { From 8bc7de5540daeeda45506cd4b79b12221b86a31c Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 16:03:59 +0100 Subject: [PATCH 23/26] Update index.html --- svg-feedback/index.html | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 33ab567..331fb00 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -168,8 +168,8 @@

History

let isRunning = false; let frames = []; let frameIndex = 0; - let currentSeed; - let initialSeed; + let currentSeed = 42; + let initialSeed = 42; let lastFrameTime = 0; let animationFrame = null; let currentState = null; @@ -364,6 +364,7 @@

History

// Keep evolving if (isRunning) { + currentSeed++; setTimeout(evolve, 1500); } } @@ -371,7 +372,6 @@

History

console.error('Evolution error:', error); if (isRunning) { currentSeed++; - elements.seed.value = currentSeed; setTimeout(evolve, 1500); } } @@ -388,6 +388,9 @@

History

frameIndex = 0; currentState = null; + // Reset seed to initial value + currentSeed = initialSeed; + if (elements.initialSvg.value?.trim?.()) { const prompt = elements.basePrompt.value; const initialSvg = elements.initialSvg.value.trim() + `\n\nPrompt: ${prompt}`; @@ -410,12 +413,11 @@

History

isRunning = false; elements.start.disabled = false; elements.stop.disabled = true; - currentSeed = initialSeed; - elements.seed.value = initialSeed; if (animationFrame) { cancelAnimationFrame(animationFrame); - animationFrame = null; } + // Reset seed to initial value + currentSeed = initialSeed; } function getFirstFourWords(str) { @@ -430,7 +432,9 @@

History

name, prompt: elements.basePrompt.value, temperature: elements.temperature.value, - initialSvg: elements.initialSvg.value + initialSvg: elements.initialSvg.value, + model: elements.modelSelect.value, + seed: currentSeed }; const savedPresets = JSON.parse(localStorage.getItem('savedPresets2') || '{}'); @@ -449,20 +453,32 @@

History

elements.presetSelect.value = name; } - // Event Listeners - elements.start.addEventListener('click', startEvolution); - elements.stop.addEventListener('click', stopEvolution); - elements.temperature.addEventListener('input', (e) => { - elements.temperatureValue.textContent = e.target.value; - }); - elements.presetSelect.addEventListener('change', (e) => { - const preset = presets[e.target.value]; + elements.presetSelect.addEventListener('change', () => { + const preset = { ...presets[elements.presetSelect.value] }; + console.log('Loading preset:', preset); elements.basePrompt.value = preset.prompt; elements.temperature.value = preset.temperature; elements.temperatureValue.textContent = preset.temperature; if (preset.initialSvg) { elements.initialSvg.value = preset.initialSvg; } + if (preset.model) { + elements.modelSelect.value = preset.model; + } + if (preset.seed) { + currentSeed = preset.seed; + initialSeed = preset.seed; + } else { + currentSeed = 42; + initialSeed = 42; + } + }); + + // Event Listeners + elements.start.addEventListener('click', startEvolution); + elements.stop.addEventListener('click', stopEvolution); + elements.temperature.addEventListener('input', (e) => { + elements.temperatureValue.textContent = e.target.value; }); // Initialize From 8f9b7ca8d7fb8a02af3c38a32ac15686a7dab868 Mon Sep 17 00:00:00 2001 From: voodoohop Date: Fri, 17 Jan 2025 16:11:15 +0100 Subject: [PATCH 24/26] Update index.html --- svg-feedback/index.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/svg-feedback/index.html b/svg-feedback/index.html index 331fb00..a0902cb 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -420,12 +420,13 @@

History

currentSeed = initialSeed; } - function getFirstFourWords(str) { - return str.split(/\s+/).slice(0, 4).join(' ').toLowerCase().replace(/[^\w\s-]/g, ''); + function getFirstThreeWords(str) { + return str.trim().split(/\s+/).slice(0, 3).join(' '); } function saveCurrentPreset() { - const name = prompt('Enter a name for this preset:'); + const defaultName = getFirstThreeWords(elements.basePrompt.value); + const name = prompt('Enter a name for this preset:', defaultName); if (!name) return; const preset = { From 11f4abd1507cd8c277413f67501b56dfdbffc24c Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:16:47 +0000 Subject: [PATCH 25/26] Fix svg-feedback CSS path and test server path handling This PR fixes two issues: 1. Corrects the CSS file path in svg-feedback/index.html to properly reference the stylesheet 2. Improves the test server path handling to correctly serve both HTML and asset files The changes resolve the HTML test failures for the svg-feedback component that were introduced in PR # 148. Mentat precommits passed. Log: https://mentat.ai/log/25bf79fc-caeb-4c0d-b63b-c69d2561293b --- scripts/test-server.js | 11 ++++++----- svg-feedback/index.html | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/test-server.js b/scripts/test-server.js index a9ce0bb..d0d86b2 100644 --- a/scripts/test-server.js +++ b/scripts/test-server.js @@ -11,12 +11,13 @@ function createServer(rootDir) { } let filePath; - if (req.url.startsWith('/../') || req.url === '/styles.css') { - // Remove leading /.. or / for root directory access - const urlPath = req.url.startsWith('/../') ? req.url.substring(3) : req.url.substring(1); - filePath = path.join(projectRoot, urlPath); + if (req.url === '/index.html' || req.url === '/') { + // Serve index.html from rootDir + filePath = path.join(rootDir, 'index.html'); } else { - filePath = path.join(rootDir, req.url); + // Serve other assets from project root + const urlPath = req.url.replace(/^\/+/, ''); + filePath = path.join(projectRoot, urlPath); } const ext = path.extname(filePath); diff --git a/svg-feedback/index.html b/svg-feedback/index.html index a0902cb..7b8c6ee 100644 --- a/svg-feedback/index.html +++ b/svg-feedback/index.html @@ -4,7 +4,7 @@ LLM SVG Art Evolution - +

LLM SVG Art Evolution

From 0fe14e3c2132e5dda21c334843df85359e9d0598 Mon Sep 17 00:00:00 2001 From: MentatBot <160964065+MentatBot@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:18:49 +0000 Subject: [PATCH 26/26] Fix asset paths in multiple components This PR fixes path issues in multiple components: 1. svg-feedback: Fixed CSS file path and improved test server path handling 2. graphics-editor: Fixed paths to style.css and main.js 3. millionaire-game: Fixed paths to styles.css and script.js The changes ensure that all static assets are properly served during testing and deployment. Mentat precommits passed. Log: https://mentat.ai/log/1d44f098-f7a9-4ba7-9fd2-69d505a049d2 --- graphics-editor/index.html | 4 ++-- millionaire-game/index.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics-editor/index.html b/graphics-editor/index.html index cb10b9f..dd8f92a 100644 --- a/graphics-editor/index.html +++ b/graphics-editor/index.html @@ -4,7 +4,7 @@ Graphics Editor - +
@@ -65,7 +65,7 @@

}); // Import and initialize the editor - import('./src/main.js').catch(error => { + import('/graphics-editor/src/main.js').catch(error => { console.error('Failed to load editor:', error); }); diff --git a/millionaire-game/index.html b/millionaire-game/index.html index c3bbe80..7b1476f 100644 --- a/millionaire-game/index.html +++ b/millionaire-game/index.html @@ -4,7 +4,7 @@ Who Wants to Be a Millionaire? - AI Edition - +
@@ -54,6 +54,6 @@

Who Wants to Be a Millionaire?

- + \ No newline at end of file