Spaces:
Running
Running
Now continue, build a story based on the details, a story of up to 5 pages, one paragraph per page, from each paragraph create a picture that matches the paragraph and then animate the picture and turn it into a video that moves according to what is described in the paragraph. Add a narrator to read the story and background music that will play quietly throughout the story. Every time you turn the page, the narrator continues to read and the picture starts to move.
4756e8e
verified
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Animated Story Builder</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/anime.min.js"></script> | |
| <script src="https://unpkg.com/[email protected]/dist/core.js"></script> | |
| </head> | |
| <body class="bg-indigo-50"> | |
| <div class="container mx-auto px-4 py-8"> | |
| <h1 class="text-4xl font-bold text-center text-indigo-800 mb-8">Create Your Animated Story</h1> | |
| <div class="bg-white rounded-lg shadow-lg p-6 mb-8"> | |
| <h2 class="text-2xl font-semibold text-indigo-700 mb-4">Story Details</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div> | |
| <label class="block text-gray-700 mb-2">Genre</label> | |
| <select id="genre" class="w-full px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500"> | |
| <option value="fantasy">Fantasy</option> | |
| <option value="adventure">Adventure</option> | |
| <option value="fairy-tale">Fairy Tale</option> | |
| <option value="animal">Animal Friends</option> | |
| <option value="scifi">Sci-Fi</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-gray-700 mb-2">Moral of the Story</label> | |
| <select id="moral" class="w-full px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500"> | |
| <option value="">Choose or we'll pick one</option> | |
| <option value="Friendship is important">Friendship is important</option> | |
| <option value="Honesty is the best policy">Honesty is the best policy</option> | |
| <option value="Kindness matters">Kindness matters</option> | |
| <option value="Never give up">Never give up</option> | |
| <option value="Sharing is caring">Sharing is caring</option> | |
| <option value="Be yourself">Be yourself</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-lg shadow-lg p-6 mb-8"> | |
| <h2 class="text-2xl font-semibold text-indigo-700 mb-4">Characters</h2> | |
| <div class="mb-6"> | |
| <label class="block text-gray-700 mb-2">Number of Good Characters (max 3)</label> | |
| <input type="number" id="characterCount" min="1" max="3" value="1" class="w-20 px-4 py-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500"> | |
| </div> | |
| <div id="characterInputs" class="space-y-4"> | |
| <!-- Dynamic inputs will be added here --> | |
| </div> | |
| <div class="mt-6"> | |
| <label class="block text-gray-700 mb-2">Heroine Images</label> | |
| <div class="grid grid-cols-3 gap-4"> | |
| <div class="border rounded-lg overflow-hidden cursor-pointer"> | |
| <img src="http://static.photos/fantasy/200x200/1" class="w-full h-32 object-cover" data-character="1"> | |
| </div> | |
| <div class="border rounded-lg overflow-hidden cursor-pointer"> | |
| <img src="http://static.photos/fantasy/200x200/2" class="w-full h-32 object-cover" data-character="2"> | |
| </div> | |
| <div class="border rounded-lg overflow-hidden cursor-pointer"> | |
| <img src="http://static.photos/fantasy/200x200/3" class="w-full h-32 object-cover" data-character="3"> | |
| </div> | |
| </div> | |
| <p class="text-sm text-gray-500 mt-1">Click to select or we'll choose randomly</p> | |
| </div> | |
| <input type="hidden" id="selectedCharacterImage" value=""> | |
| </div> | |
| <div class="text-center"> | |
| <button id="generateBtn" class="px-8 py-3 bg-indigo-600 text-white rounded-lg font-semibold hover:bg-indigo-700 transition duration-200 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"> | |
| Generate Your Story | |
| </button> | |
| </div> | |
| <div id="storyView" class="hidden mt-12 bg-white rounded-lg shadow-lg p-6"> | |
| <div class="flex flex-col md:flex-row"> | |
| <div class="md:w-1/2 p-4"> | |
| <div id="storyText" class="text-lg text-gray-800"></div> | |
| </div> | |
| <div class="md:w-1/2 p-4"> | |
| <div id="storyImage" class="w-full h-64 md:h-96 bg-gray-100 rounded-lg flex items-center justify-center"> | |
| <p class="text-gray-400">Story image will appear here</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="flex justify-between mt-6"> | |
| <button id="prevPage" class="px-4 py-2 bg-indigo-100 text-indigo-700 rounded-lg hover:bg-indigo-200">Previous</button> | |
| <span id="pageCount" class="text-gray-600">Page 1 of 5</span> | |
| <button id="nextPage" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">Next</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Character image selection | |
| const characterImages = document.querySelectorAll('[data-character]'); | |
| characterImages.forEach(img => { | |
| img.addEventListener('click', function() { | |
| characterImages.forEach(i => i.parentElement.classList.remove('ring-2', 'ring-indigo-500')); | |
| this.parentElement.classList.add('ring-2', 'ring-indigo-500'); | |
| document.getElementById('selectedCharacterImage').value = this.src; | |
| }); | |
| }); | |
| // Set random values if not chosen | |
| document.getElementById('generateBtn').addEventListener('click', function() { | |
| const genreSelect = document.getElementById('genre'); | |
| const moralSelect = document.getElementById('moral'); | |
| const villainInput = document.getElementById('villain'); | |
| // Set random genre if not selected | |
| if(genreSelect.value === '') { | |
| const genres = ['fantasy', 'adventure', 'fairy-tale', 'animal', 'scifi']; | |
| genreSelect.value = genres[Math.floor(Math.random() * genres.length)]; | |
| } | |
| // Set random moral if not selected | |
| if(moralSelect.value === '') { | |
| const morals = ['Friendship is important', 'Honesty is the best policy', 'Kindness matters', | |
| 'Never give up', 'Sharing is caring', 'Be yourself']; | |
| moralSelect.value = morals[Math.floor(Math.random() * morals.length)]; | |
| } | |
| // Set random character image if not selected | |
| if(document.getElementById('selectedCharacterImage').value === '') { | |
| const randomImg = characterImages[Math.floor(Math.random() * characterImages.length)]; | |
| randomImg.parentElement.classList.add('ring-2', 'ring-indigo-500'); | |
| document.getElementById('selectedCharacterImage').value = randomImg.src; | |
| } | |
| // Generate random villain name if not provided | |
| if(villainInput.value === '') { | |
| const villainNames = ['Dark Shadow', 'Greedy Goblin', 'Wicked Witch', 'Cruel King', 'Evil Enchanter']; | |
| villainInput.value = villainNames[Math.floor(Math.random() * villainNames.length)]; | |
| } | |
| // Generate the story | |
| generateStory(); | |
| }); | |
| function generateStory() { | |
| const genre = document.getElementById('genre').value; | |
| const moral = document.getElementById('moral').value; | |
| const characterCount = document.getElementById('characterCount').value; | |
| const characterImages = []; | |
| // Get selected character images | |
| document.querySelectorAll('[data-character]').forEach(img => { | |
| if (img.parentElement.classList.contains('ring-2')) { | |
| characterImages.push(img.src); | |
| } | |
| }); | |
| // If no images selected, use random ones | |
| if (characterImages.length === 0) { | |
| const allImages = document.querySelectorAll('[data-character]'); | |
| for (let i = 0; i < characterCount; i++) { | |
| characterImages.push(allImages[i].src); | |
| } | |
| } | |
| // Generate story data | |
| const story = { | |
| title: `The ${genre.charAt(0).toUpperCase() + genre.slice(1)} Adventure`, | |
| genre: genre, | |
| moral: moral, | |
| characters: characterImages, | |
| pages: [] | |
| }; | |
| // Generate 5 story pages with images and animations | |
| for (let i = 0; i < 5; i++) { | |
| story.pages.push({ | |
| text: generatePageText(i, genre, characterCount, moral), | |
| image: generatePageImage(i, genre), | |
| animation: generateAnimationConfig(i), | |
| narrationAudio: `narration-page-${i+1}.mp3` | |
| }); | |
| } | |
| // Save story and redirect to viewer | |
| localStorage.setItem('generatedStory', JSON.stringify(story)); | |
| window.location.href = 'storyviewer.html'; | |
| } | |
| function generatePageText(pageIndex, genre, characterCount, moral) { | |
| const pageTexts = { | |
| fantasy: [ | |
| `Once upon a time in a magical kingdom, ${characterCount} brave heroes set out on a quest to retrieve the stolen Crystal of Truth.`, | |
| `The heroes encountered the evil ${document.getElementById('villain').value} who had hidden the crystal deep in the Forbidden Forest.`, | |
| `Using their wits and teamwork, the heroes navigated through treacherous traps set by the villain.`, | |
| `In a final confrontation, the heroes outsmarted the villain and reclaimed the Crystal of Truth.`, | |
| `The kingdom celebrated their return, learning that "${moral}" was the true treasure all along.` | |
| ], | |
| adventure: [ | |
| `In a land of endless adventure, ${characterCount} friends began their journey to climb the legendary Mount Destiny.`, | |
| `Their path was blocked by ${document.getElementById('villain').value}, who claimed the mountain was his domain.`, | |
| `The friends worked together to find an alternate route, helping each other through difficult terrain.`, | |
| `At the summit, they discovered ${document.getElementById('villain').value} had followed them, leading to a dramatic showdown.`, | |
| `Victorious, the friends planted their flag, proving that "${moral}" was their greatest strength.` | |
| ] | |
| // Other genre templates would go here | |
| }; | |
| return pageTexts[genre][pageIndex] || `This is page ${pageIndex + 1} of your ${genre} story about "${moral}".`; | |
| } | |
| function generatePageImage(pageIndex, genre) { | |
| const imageThemes = { | |
| fantasy: ['castle', 'forest', 'cave', 'battle', 'celebration'], | |
| adventure: ['mountain', 'river', 'cliff', 'summit', 'camp'] | |
| // Other genre image themes | |
| }; | |
| return `http://static.photos/${genre}/640x360/${pageIndex+1}`; | |
| } | |
| function generateAnimationConfig(pageIndex) { | |
| return { | |
| type: ['fadeIn', 'panLeft', 'zoomIn', 'characterMove', 'celebrate'][pageIndex], | |
| duration: 2000 | |
| }; | |
| } | |
| }); | |
| ======= | |
| </script> | |
| </body> | |
| </html> |