for this web app is there any other way to create bubbles so that the user can choose other styles of bubbles and change the tails of the bubbles either down, left or right, depending on the position of the character? maybe with some js library? : <html><head><base href="http://localhost/">
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Comic Strip Creator</title>
  <!-- Google Fonts -->
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
  <!-- Interact.js for draggable, resizable, rotatable dialogues -->
  <script src="https://cdn.jsdelivr.net/npm/interactjs/dist/interact.min.js"></script>
  <style>
    /* Root Variables for Consistent Theming */
    :root {
      --primary-color: #6B48FF;
      --secondary-color: #FFB648;
      --accent-color: #FF6B6B;
      --background-color: #F0F2F5;
      --card-bg: #FFFFFF;
      --text-primary: #2C3E50;
      --text-secondary: #7F8C8D;
      --success: #2ECC71;
      --error: #E74C3C;
      --shadow: rgba(0, 0, 0, 0.1);
      --border-radius: 8px;
      --transition-speed: 0.3s;
    }

    /* Global Styles */
    body {
      font-family: 'Poppins', sans-serif;
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
      background: var(--background-color);
      color: var(--text-primary);
      line-height: 1.6;
    }

    h1, h2 {
      color: var(--primary-color);
      text-align: center;
      margin-bottom: 20px;
    }

    h1 {
      font-size: 2.5em;
      position: relative;
    }

    h1::after {
      content: '';
      display: block;
      width: 60px;
      height: 4px;
      background: var(--secondary-color);
      margin: 10px auto;
      border-radius: 2px;
    }

    /* Input Section Styling */
    .input-section {
      background: var(--card-bg);
      padding: 30px;
      border-radius: var(--border-radius);
      box-shadow: 0 8px 24px var(--shadow);
      margin-bottom: 30px;
      transition: transform var(--transition-speed) ease;
    }

    .input-section:hover {
      transform: translateY(-2px);
    }

    .character-inputs {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
      gap: 30px;
      margin-bottom: 20px;
    }

    .input-group {
      margin-bottom: 20px;
      position: relative;
    }

    label {
      display: block;
      margin-bottom: 8px;
      font-weight: 600;
      color: var(--text-primary);
      font-size: 0.95em;
    }

    input, textarea, select {
      width: 100%;
      padding: 12px;
      border: 2px solid #E0E7FF;
      border-radius: var(--border-radius);
      font-family: 'Poppins', sans-serif;
      transition: border-color var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
      font-size: 1em;
    }

    input:focus, textarea:focus, select:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgba(107, 72, 255, 0.1);
    }

    /* Buttons Styling */
    .button-group {
      display: flex;
      flex-wrap: wrap;
      gap: 15px;
      justify-content: center;
      margin-top: 20px;
    }

    button {
      background: var(--primary-color);
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: var(--border-radius);
      cursor: pointer;
      font-size: 16px;
      font-weight: 600;
      transition: background var(--transition-speed) ease, transform var(--transition-speed) ease, box-shadow var(--transition-speed) ease;
      text-transform: uppercase;
      letter-spacing: 1px;
    }

    button:hover {
      background: #5536FF;
      transform: translateY(-2px);
      box-shadow: 0 4px 12px rgba(107, 72, 255, 0.2);
    }

    #generate-combined-image {
      display: none; /* Initially hidden */
      margin-top: 20px; /* Space above button */
      background: var(--secondary-color);
    }

    #generate-combined-image:hover {
      background: #FF9F29;
    }

    #generate-dialogues {
      display: none; /* Initially hidden */
      margin-top: 20px; /* Space above button */
      background: #3498DB;
    }

    #generate-dialogues:hover {
      background: #2980B9;
    }

    /* Feedback Messages */
    .error-message, .success-message {
      padding: 15px;
      border-radius: var(--border-radius);
      margin: 15px 0;
      display: none;
      font-size: 0.95em;
    }

    .error-message {
      color: var(--error);
      background: #FFF5F5;
      border-left: 4px solid var(--error);
    }

    .success-message {
      color: var(--success);
      background: #F0FFF0;
      border-left: 4px solid var(--success);
    }

    /* Loading Indicators */
    .loading {
      display: none;
      text-align: center;
      padding: 20px;
      color: var(--primary-color);
      font-weight: 600;
      position: relative;
    }

    .loading::before {
      content: '';
      display: block;
      width: 40px;
      height: 40px;
      margin: 0 auto 10px;
      border: 4px solid var(--primary-color);
      border-top: 4px solid transparent;
      border-radius: 50%;
      animation: spin 1s linear infinite;
    }

    .loading::after {
      content: attr(data-message);
      display: block;
      font-size: 14px;
      margin-top: 8px;
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    /* Story and Image Containers */
    #story-preview, #combined-image-container {
      background: var(--card-bg);
      padding: 30px;
      border-radius: var(--border-radius);
      margin: 30px 0;
      box-shadow: 0 8px 24px var(--shadow);
      display: none;
      animation: fadeIn 0.5s ease;
      text-align: center; /* Center the content */
    }

    #story-preview p {
      white-space: pre-wrap;
    }

    #combined-comic-image {
      width: 100%;
      max-width: 1024px;
      border: 3px solid var(--primary-color);
      border-radius: 12px;
      transition: transform var(--transition-speed) ease;
    }

    #combined-comic-image:hover {
      transform: scale(1.02);
    }

    /* Updated Dialogue Bubbles */
    .dialogue-bubble {
      position: absolute;
      min-width: 100px;
      max-width: 250px;
      padding: 15px;
      background: rgba(255, 255, 255, 0.85);
      border: 2.5px solid var(--primary-color);
      border-radius: 18px;
      cursor: move;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
      user-select: text;
      font-size: 0.95em;
      transform-origin: top left;
      transition: border-color 0.3s, box-shadow 0.3s;
      backdrop-filter: blur(4px);
    }

    /* Speech Bubble Tail Styles */
    .dialogue-bubble.speech::after {
      content: '';
      position: absolute;
      bottom: -15px;
      left: 25px;
      width: 30px;
      height: 15px;
      background: inherit;
      border-right: 2.5px solid var(--primary-color);
      border-bottom: 2.5px solid var(--primary-color);
      transform: skew(-45deg);
      transform-origin: 0 0;
      transition: border-color 0.3s;
    }

    /* Thought Bubble Style */
    .dialogue-bubble.thought {
      border-radius: 24px;
      background: rgba(255, 255, 255, 0.85);
      border-style: dashed;
    }

    .dialogue-bubble.thought::after {
      content: '';
      position: absolute;
      bottom: -20px;
      left: 25px;
      width: 12px;
      height: 12px;
      background: inherit;
      border: 2.5px dashed var(--primary-color);
      border-radius: 50%;
    }

    .dialogue-bubble.thought::before {
      content: '';
      position: absolute;
      bottom: -35px;
      left: 15px;
      width: 8px;
      height: 8px;
      background: inherit;
      border: 2.5px dashed var(--primary-color);
      border-radius: 50%;
    }

    /* Hover and Selected States */
    .dialogue-bubble:hover {
      box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
      border-color: var(--secondary-color);
    }

    .dialogue-bubble.selected {
      border-color: var(--accent-color);
      box-shadow: 0 0 0 3px rgba(255, 107, 107, 0.2);
    }

    /* Control Buttons */
    .dialogue-bubble .delete-button {
      position: absolute;
      width: 24px;
      height: 24px;
      border-radius: 50%;
      border: none;
      cursor: pointer;
      font-size: 14px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.3s ease;
      opacity: 0; /* Start hidden */
      transform: scale(0.8);
    }

    .dialogue-bubble:hover .delete-button,
    .dialogue-bubble.selected .delete-button {
      opacity: 1;
      transform: scale(1);
    }

    .dialogue-bubble:focus .delete-button {
      opacity: 1;
      transform: scale(1);
    }

    .dialogue-bubble:focus-within .delete-button {
      opacity: 1;
      transform: scale(1);
    }

    .dialogue-bubble .delete-button {
      top: -12px;
      right: -12px;
      background: var(--error);
      color: white;
    }

    .dialogue-bubble .delete-button:hover {
      transform: scale(1.1);
    }

    /* Customization Panel */
    .customization-panel {
      display: none; /* Hide by default */
      position: fixed;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: var(--card-bg);
      padding: 20px;
      border-radius: var(--border-radius);
      box-shadow: 0 4px 24px var(--shadow);
      z-index: 1000;
      width: 300px;
      cursor: move;
      user-select: none;
      background: var(--card-bg);
      border: 1px solid var(--shadow);
      box-shadow: 0 4px 24px var(--shadow);
    }

    .panel-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 10px;
      background: var(--primary-color);
      color: white;
      border-top-left-radius: var(--border-radius);
      border-top-right-radius: var(--border-radius);
    }

    .panel-header h2 {
      margin: 0;
      font-size: 1.2em;
      color: white;
    }

    .close-button {
      background: none;
      border: none;
      color: white;
      font-size: 24px;
      cursor: pointer;
      padding: 0 5px;
      line-height: 1;
    }

    .close-button:hover {
      color: var(--secondary-color);
    }

    #art-style-section {
      display: none; /* Initially hidden */
      margin: 20px 0;
    }

    /* Responsive Design */
    @media (max-width: 768px) {
      body {
        padding: 10px;
      }

      .input-section {
        padding: 20px;
      }

      h1 {
        font-size: 2em;
      }

      button {
        width: 100%;
      }

      .dialogue-bubble {
        max-width: 120px;
        padding: 8px;
        font-size: 0.9em;
      }

      .customization-panel {
        width: 90%;
      }
    }
  </style>
</head>
<body>
  <main>
    <!-- Input Section -->
    <section class="input-section" aria-labelledby="app-title">
      <h1 id="app-title">Comic Strip Creator</h1>
      
      <form id="comic-form" novalidate>
        <div class="character-inputs">
          <!-- Character 1 Inputs -->
          <div class="character-1">
            <h2>Character 1</h2>
            <div class="input-group">
              <label for="char1-name">Name:</label>
              <input type="text" id="char1-name" name="char1-name" required placeholder="Enter character name" aria-required="true">
            </div>
            <div class="input-group">
              <label for="char1-description">Description:</label>
              <textarea id="char1-description" name="char1-description" rows="4" required placeholder="Describe your character's appearance and personality" aria-required="true"></textarea>
            </div>
          </div>
          
          <!-- Character 2 Inputs -->
          <div class="character-2">
            <h2>Character 2</h2>
            <div class="input-group">
              <label for="char2-name">Name:</label>
              <input type="text" id="char2-name" name="char2-name" required placeholder="Enter character name" aria-required="true">
            </div>
            <div class="input-group">
              <label for="char2-description">Description:</label>
              <textarea id="char2-description" name="char2-description" rows="4" required placeholder="Describe your character's appearance and personality" aria-required="true"></textarea>
            </div>
          </div>
        </div>
    
        <!-- Story Outline -->
        <div class="input-group">
          <label for="story-outline">Story Outline:</label>
          <textarea id="story-outline" name="story-outline" rows="4" required placeholder="Write your story outline here" aria-required="true"></textarea>
        </div>
    
        <!-- Scene Description -->
        <div class="input-group">
          <label for="scene-description">Scene Description:</label>
          <textarea id="scene-description" name="scene-description" rows="4" required placeholder="Describe the scene and setting" aria-required="true"></textarea>
        </div>
        
        <!-- Feedback Messages -->
        <div id="error-message" class="error-message" role="alert"></div>
        <div id="success-message" class="success-message" role="status"></div>
    
        <!-- Buttons -->
        <div class="button-group">
          <button type="button" id="generate-story">Generate Story</button>
        </div>
      </form>
    </section>
    
    <!-- Story Preview -->
    <section id="story-preview" aria-live="polite">
      <h2>Generated Story Panels:</h2>
      <p></p>
      
      <!-- Art Style Selection -->
      <div id="art-style-section" class="input-group">
        <label for="art-style">Select Art Style for Comic Strip:</label>
        <select id="art-style" name="art-style" required aria-required="true">
          <option value="" disabled selected>Select an art style</option>
          <option value="manga">Manga</option>
          <option value="comic">Comic Book</option>
          <option value="realistic">Realistic</option>
          <option value="cartoon">Cartoon</option>
          <option value="watercolor">Watercolor</option>
          <option value="whimsical">Whimsical Storybook</option>
          <option value="pop">Pop Art</option>
          <option value="sketch">Detailed Sketch</option>
        </select>
      </div>
      
      <button type="button" id="generate-combined-image" style="display: none;">Generate Comic Strip</button>
    </section>
    
    <!-- Combined Comic Image -->
    <section id="combined-image-container" aria-live="polite">
      <h2>Your Comic Strip:</h2>
      <img id="combined-comic-image" src="" alt="Combined Comic Strip">
      <button type="button" id="generate-dialogues" style="display: none;">Generate Dialogues</button>
    </section>
    
    <!-- Customization Panel -->
    <section id="customization-panel" class="customization-panel" aria-hidden="true">
      <div class="panel-header">
        <h2>Customize Dialogue</h2>
        <button class="close-button">&times;</button>
      </div>

      <div class="customization-group">
        <label for="font-style">Font Style:</label>
        <select id="font-style">
          <option value="Poppins" selected>Poppins</option>
          <option value="Arial">Arial</option>
          <option value="Times New Roman">Times New Roman</option>
          <option value="Courier New">Courier New</option>
          <option value="Georgia">Georgia</option>
          <!-- Add more fonts as needed -->
        </select>
      </div>
      
      <div class="customization-group">
        <label for="font-size">Font Size:</label>
        <input type="number" id="font-size" min="10" max="36" value="14"> px
      </div>
      
      <div class="customization-group">
        <label for="text-color">Text Color:</label>
        <input type="color" id="text-color" value="#000000">
      </div>
      
      <div class="customization-group">
        <label for="bubble-color">Bubble Background:</label>
        <input type="color" id="bubble-color" value="#FFFFFF">
      </div>
      
      <div class="customization-group">
        <label for="bubble-style">Bubble Style:</label>
        <select id="bubble-style">
          <option value="speech" selected>Speech Bubble</option>
          <option value="thought">Thought Bubble</option>
          <!-- Add more styles if desired -->
        </select>
      </div>
      
      <div class="button-group">
        <button type="button" id="apply-customization">Apply</button>
        <button type="button" id="reset-customization">Reset</button>
      </div>
    </section>
    
    <!-- Loading Indicators -->
    <div id="loading-story" class="loading" data-message="Creating your story..."></div>
    <div id="loading-image" class="loading" data-message="Crafting your comic panels..."></div>
    <div id="loading-dialogues" class="loading" data-message="Generating dialogues..."></div>
    
  </main>

  <script>
    // Check if html2canvas is loaded
    if (typeof html2canvas === 'undefined') {
      console.error('html2canvas library not loaded');
      // Fallback to load the library dynamically if needed
      const script = document.createElement('script');
      script.src = 'https://html2canvas.hertzen.com/dist/html2canvas.min.js';
      script.onload = () => console.log('html2canvas loaded dynamically');
      document.head.appendChild(script);
    }

    // Convert RGB color to Hex
    const rgbToHex = (rgb) => {
      // If already hex, return as is
      if (rgb.startsWith('#')) return rgb;
      
      // Extract RGB values
      const rgbMatch = rgb.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
      if (!rgbMatch) return '#000000'; // Default to black if invalid

      const r = parseInt(rgbMatch[1]);
      const g = parseInt(rgbMatch[2]);
      const b = parseInt(rgbMatch[3]);

      // Convert to hex
      const toHex = (n) => {
        const hex = n.toString(16);
        return hex.length === 1 ? '0' + hex : hex;
      };

      return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
    };

    // Utility Function for Displaying Messages
    const displayMessage = (element, message, type) => {
      element.textContent = message;
      element.style.display = 'block';
      element.className = type === 'error' ? 'error-message' : 'success-message';
      setTimeout(() => {
        element.style.display = 'none';
      }, 5000);
    };

    // Validate Form Inputs
    const validateForm = () => {
      const form = document.getElementById('comic-form');
      const requiredFields = form.querySelectorAll('[required]:not(#art-style)'); // Exclude art style
      let isValid = true;
      requiredFields.forEach(field => {
        if (!field.value.trim()) {
          isValid = false;
          field.classList.add('input-error');
        } else {
          field.classList.remove('input-error');
        }
      });
      return isValid;
    };

    // Fetch API Wrapper with Error Handling
    const fetchAPI = async (url, options) => {
      try {
        const response = await fetch(url, options);
        if (!response.ok) throw new Error(`Error: ${response.status} ${response.statusText}`);
        return response;
      } catch (error) {
        throw error;
      }
    };

    // Function to Generate Story
    const generateStory = async () => {
      const errorMessage = document.getElementById('error-message');
      const successMessage = document.getElementById('success-message');
      const loading = document.getElementById('loading-story');
      const storyPreview = document.getElementById('story-preview');
      const generateImageBtn = document.getElementById('generate-combined-image');

      errorMessage.style.display = 'none';
      successMessage.style.display = 'none';
      storyPreview.style.display = 'none';
      generateImageBtn.style.display = 'none';

      if (!validateForm()) {
        displayMessage(errorMessage, 'Please fill in all required fields correctly.', 'error');
        return;
      }

      loading.style.display = 'block';

      try {
        const char1Name = document.getElementById('char1-name').value.trim();
        const char1Desc = document.getElementById('char1-description').value.trim();
        const char2Name = document.getElementById('char2-name').value.trim();
        const char2Desc = document.getElementById('char2-description').value.trim();
        const storyOutline = document.getElementById('story-outline').value.trim();
        const sceneDesc = document.getElementById('scene-description').value.trim();

        const prompt = `Compose a 4-panel strip story featuring two characters: ${char1Name} (${char1Desc}) and ${char2Name} (${char2Desc}). Based on the following inputs:

- **Story Outline:** ${storyOutline}
- **Scene Description:** ${sceneDesc}

Please create a cohesive and engaging narrative broken down into four distinct visual scenes without any dialogue. Each panel should clearly depict a sequential part of the story, emphasizing the characters actions and emotions.`;

        const response = await fetchAPI('https://text.pollinations.ai/', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            messages: [
              { role: 'system', content: 'You are a creative story strip writer.' },
              { role: 'user', content: prompt }
            ],
            model: 'openai',
            jsonMode: false
          }),
        });

        const data = await response.text();

        // Display the generated story
        storyPreview.querySelector('p').innerHTML = data.replace(/\n/g, '<br>');
        storyPreview.style.display = 'block';
        
        // Show art style section along with generate comic strip button
        document.getElementById('art-style-section').style.display = 'block';
        generateImageBtn.style.display = 'inline-block';
        
        window.storyData = data; // Store story data globally
        displayMessage(successMessage, 'Story generated successfully!', 'success');
      } catch (error) {
        displayMessage(errorMessage, error.message || 'Failed to generate story. Please try again.', 'error');
        console.error('Error:', error);
      } finally {
        loading.style.display = 'none';
      }
    };

    // Function to Generate Combined Image
    const generateCombinedImage = () => {
      const loadingImage = document.getElementById('loading-image');
      const combinedImageContainer = document.getElementById('combined-image-container');
      const combinedComicImage = document.getElementById('combined-comic-image');
      const errorMessage = document.getElementById('error-message');
      const successMessage = document.getElementById('success-message');
      const generateDialoguesBtn = document.getElementById('generate-dialogues');

      errorMessage.style.display = 'none';
      successMessage.style.display = 'none';
      combinedImageContainer.style.display = 'none';
      generateDialoguesBtn.style.display = 'none';

      try {
        const artStyle = document.getElementById('art-style').value;
        const char1Name = document.getElementById('char1-name').value.trim();
        const char2Name = document.getElementById('char2-name').value.trim();

        const scenes = window.storyData.split('\n').filter(scene => scene.trim()).slice(0, 4);
        if (scenes.length < 4) {
          throw new Error('Insufficient number of scenes to create a 4-panel story.');
        }

        const prompt = `Generate a single high-resolution image (1024x1024 pixels) of a 4-panel story strip arranged in a 2x2 grid, featuring two characters: ${char1Name} and ${char2Name} in the ${artStyle} style. Based on the following scene descriptions:

- **Panel 1:** ${scenes[0]}
- **Panel 2:** ${scenes[1]}
- **Panel 3:** ${scenes[2]}
- **Panel 4:** ${scenes[3]}

Ensure that:

1. **Consistent Design:** Both characters maintain consistent appearances, expressions, and postures across all panels.
2. **Art Style Adherence:** The entire strip adheres to the specified ${artStyle}, reflecting its unique aesthetic.
3. **Seamless Transitions:** Scenes flow logically from one panel to the next, showcasing a coherent and engaging storyline.
4. **No Text or Dialogues:** Exclude any textual elements, speech bubbles, or dialogues from the image.
5. **Visual Clarity:** Each panel should clearly represent the described scene with distinct and recognizable actions and emotions.
6. **High Quality:** The final image should be free from logos, watermarks, and maintain high visual fidelity.

Provide the 4 panel image without any annotations or additional elements outside the specified parameters.`;

        const encodedPrompt = encodeURIComponent(prompt);
        const imageUrl = `https://image.pollinations.ai/prompt/${encodedPrompt}?model=flux&width=1024&height=1024&nologo=true&private=true`;

        // Display the loading indicator
        loadingImage.style.display = 'block';

        // Once the image is loaded, display it
        combinedComicImage.onload = () => {
          loadingImage.style.display = 'none';
          combinedImageContainer.style.display = 'block';
          
          // Hide generate comic strip button and show generate dialogues button
          document.getElementById('generate-combined-image').style.display = 'none';
          generateDialoguesBtn.style.display = 'inline-block';
          
          displayMessage(successMessage, 'Comic strip generated successfully!', 'success');
        };

        combinedComicImage.onerror = () => {
          loadingImage.style.display = 'none';
          displayMessage(errorMessage, 'Failed to load the comic strip image. Please try again.', 'error');
        };

        // Set the image source
        combinedComicImage.src = imageUrl;

      } catch (error) {
        displayMessage(errorMessage, error.message || 'Failed to generate the combined comic image.', 'error');
        console.error('Error generating combined image:', error);
      }
    };

    // Function to Generate Dialogues
    const generateDialogues = async () => {
      const errorMessage = document.getElementById('error-message');
      const successMessage = document.getElementById('success-message');
      const loading = document.getElementById('loading-dialogues');
      const dialogues = [];
      
      errorMessage.style.display = 'none';
      
      try {
        loading.style.display = 'block';
        
        // Extract necessary data
        const storyData = window.storyData; // Assuming this contains the generated story
        const panels = window.storyData.split('\n').filter(scene => scene.trim()).slice(0, 4);
        const artStyle = document.getElementById('art-style').value;
        const char1Name = document.getElementById('char1-name').value.trim();
        const char1Desc = document.getElementById('char1-description').value.trim();
        const char2Name = document.getElementById('char2-name').value.trim();
        const char2Desc = document.getElementById('char2-description').value.trim();
        
        // Generate dialogues for each panel
        for (let i = 0; i < panels.length; i++) {
          const prompt = `For Panel ${i + 1} of a 4-panel comic strip featuring ${char1Name} (${char1Desc}) and ${char2Name} (${char2Desc}) in the ${artStyle} style, based on the following scene description:

"${panels[i]}"

Generate a concise and contextually appropriate dialogue between ${char1Name} and ${char2Name}. The dialogue should reflect the characters' personalities and emotions conveyed in the scene, matching the overall narrative style. Limit the dialogue to 2 lines maximum.`;

          const response = await fetchAPI('https://text.pollinations.ai/', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              messages: [
                { role: 'system', content: 'You are a skilled dialogue writer for comic strips.' },
                { role: 'user', content: prompt }
              ],
              model: 'openai',
              jsonMode: true
            }),
          });
          
          const data = await response.text();
          dialogues.push(data.trim());
        }
        
        // Store dialogues globally
        window.dialogueData = dialogues;

        // After successfully generating dialogues, hide the generate dialogues button
        document.getElementById('generate-dialogues').style.display = 'none';
        
        // Show customization panel
        const customizationPanel = document.getElementById('customization-panel');
        customizationPanel.style.display = 'block';

        // Render dialogues on the comic strip
        renderDialogues(dialogues);
        displayMessage(successMessage, 'Dialogues generated successfully!', 'success');
        
      } catch (error) {
        displayMessage(errorMessage, error.message || 'Failed to generate dialogues. Please try again.', 'error');
        console.error('Error:', error);
      } finally {
        loading.style.display = 'none';
      }
    };

    // Function to Render Dialogues
    const renderDialogues = (dialogues) => {
      const combinedComicImage = document.getElementById('combined-comic-image');
      
      // Ensure the image container is positioned relatively to place absolute elements inside
      const container = document.getElementById('combined-image-container');
      container.style.position = 'relative';
      
      // Clear existing dialogue bubbles if any
      const existingBubbles = container.querySelectorAll('.dialogue-bubble');
      existingBubbles.forEach(bubble => bubble.remove());
      
      // Create dialogue bubbles for each panel
      dialogues.forEach((dialogue, index) => {
        const bubble = document.createElement('div');
        bubble.className = 'dialogue-bubble speech';
        bubble.style.backgroundColor = 'rgba(255, 255, 255, 0.75)'; // Set initial opacity
        bubble.setAttribute('data-bubble-style', 'speech'); // Default style attribute
        bubble.setAttribute('data-id', `bubble-${Date.now()}-${index}`); // Unique ID for tracking
        bubble.contentEditable = 'true';
        bubble.innerText = dialogue;
        
        // Add Delete Button
        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'delete-button';
        deleteBtn.innerHTML = '&times;';
        deleteBtn.title = 'Delete Bubble';
        bubble.appendChild(deleteBtn);
        
        // Positioning logic based on panel
        // Assuming panels are laid out in a 2x2 grid
        // Adjust positions as needed
        switch(index) {
          case 0:
            bubble.style.top = '10%';
            bubble.style.left = '10%';
            break;
          case 1:
            bubble.style.top = '10%';
            bubble.style.right = '10%';
            break;
          case 2:
            bubble.style.bottom = '10%';
            bubble.style.left = '10%';
            break;
          case 3:
            bubble.style.bottom = '10%';
            bubble.style.right = '10%';
            break;
          default:
            bubble.style.top = '10%';
            bubble.style.left = '10%';
        }
        
        container.appendChild(bubble);
        
        // Make the bubble draggable and resizable
        makeInteractive(bubble);
        
        // Event Listener for Delete Button
        deleteBtn.addEventListener('click', () => {
          bubble.remove();
        });
        
        // Event Listener for Selecting a Bubble
        bubble.addEventListener('click', (e) => {
          e.stopPropagation(); // Prevent event bubbling
          document.querySelectorAll('.dialogue-bubble').forEach(b => b.classList.remove('selected'));
          bubble.classList.add('selected');
          openCustomizationPanel(bubble);
        });
        
        // Optional: Double-Click to Open Customization Panel
        bubble.addEventListener('dblclick', (e) => {
          e.stopPropagation();
          openCustomizationPanel(bubble);
        });
      });
    };

    // Function to Make Dialogue Bubbles Interactive
    const makeInteractive = (element) => {
      interact(element)
        .draggable({
          inertia: true,
          modifiers: [
            interact.modifiers.restrictRect({
              restriction: 'parent',
              endOnly: true
            })
          ],
          autoScroll: true,
          listeners: {
            move: dragMoveListener,
          }
        })
        .resizable({
          edges: { left: true, right: true, bottom: true, top: true },
          inertia: true,
          modifiers: [
            interact.modifiers.restrictSize({
              min: { width: 80, height: 40 },
              max: { width: 400, height: 200 }
            })
          ],
          listeners: {
            move: resizeMoveListener,
          }
        });
    };

    // Drag Move Listener
    const dragMoveListener = (event) => {
      const target = event.target;
      // Keep the dragged position in the data attribute
      const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
      const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;

      // Translate the element
      target.style.transform = `translate(${x}px, ${y}px)`;
      
      // Update the position attributes
      target.setAttribute('data-x', x);
      target.setAttribute('data-y', y);
    };

    // Resize Move Listener
    const resizeMoveListener = (event) => {
      const target = event.target;
      
      // Update the element's style
      let { width, height } = event.rect;
      target.style.width = `${width}px`;
      target.style.height = `${height}px`;
      
      // Adjust the transform to keep the element's top-left corner in place
      const x = (parseFloat(target.getAttribute('data-x')) || 0);
      const y = (parseFloat(target.getAttribute('data-y')) || 0);
      target.style.transform = `translate(${x}px, ${y}px)`;
    };

    // Function to Open the Customization Panel
    const openCustomizationPanel = (bubble) => {
      const customizationPanel = document.getElementById('customization-panel');
      
      // Populate the customization panel with current styles
      const fontStyle = window.getComputedStyle(bubble).fontFamily.replace(/['"]/g, "");
      const fontSize = parseInt(window.getComputedStyle(bubble).fontSize);
      const textColor = rgbToHex(window.getComputedStyle(bubble).color);
      const bubbleColor = rgbToHex(window.getComputedStyle(bubble).backgroundColor);
      
      // Set font style
      const fonts = document.getElementById('font-style');
      fonts.value = fonts.querySelector(`option[value="${fontStyle}"]`) ? fontStyle : 'Poppins';

      // Set font size
      document.getElementById('font-size').value = fontSize;

      // Set text color
      document.getElementById('text-color').value = textColor;

      // Set bubble background color
      document.getElementById('bubble-color').value = bubbleColor;
      
      // Set bubble style
      const currentBubbleStyle = bubble.getAttribute('data-bubble-style') || 'speech';
      document.getElementById('bubble-style').value = currentBubbleStyle;
      
      // Show the customization panel
      customizationPanel.classList.add('active');
      customizationPanel.setAttribute('aria-hidden', 'false');
    };

    // Function to Close the Customization Panel
    const closeCustomizationPanel = () => {
      const customizationPanel = document.getElementById('customization-panel');
      customizationPanel.classList.remove('active');
      customizationPanel.setAttribute('aria-hidden', 'true');
    };

    // Make customization panel draggable
    const makeCustomizationPanelDraggable = () => {
      const panel = document.getElementById('customization-panel');
      const header = panel.querySelector('.panel-header');
      let isDragging = false;
      let currentX;
      let currentY;
      let initialX;
      let initialY;
      let xOffset = 0;
      let yOffset = 0;

      const dragStart = (e) => {
        if (e.type === "touchstart") {
          initialX = e.touches[0].clientX - xOffset;
          initialY = e.touches[0].clientY - yOffset;
        } else {
          initialX = e.clientX - xOffset;
          initialY = e.clientY - yOffset;
        }

        if (e.target === header || e.target.parentNode === header) {
          isDragging = true;
        }
      };

      const dragEnd = () => {
        isDragging = false;
      };

      const drag = (e) => {
        if (isDragging) {
          e.preventDefault();

          if (e.type === "touchmove") {
            currentX = e.touches[0].clientX - initialX;
            currentY = e.touches[0].clientY - initialY;
          } else {
            currentX = e.clientX - initialX;
            currentY = e.clientY - initialY;
          }

          xOffset = currentX;
          yOffset = currentY;

          panel.style.transform = `translate(${currentX}px, ${currentY}px)`;
        }
      };

      // Add event listeners
      header.addEventListener('mousedown', dragStart);
      document.addEventListener('mousemove', drag);
      document.addEventListener('mouseup', dragEnd);
      header.addEventListener('touchstart', dragStart);
      document.addEventListener('touchmove', drag);
      document.addEventListener('touchend', dragEnd);

      // Add close button functionality
      const closeButton = panel.querySelector('.close-button');
      closeButton.addEventListener('click', () => {
        panel.style.display = 'none';
        // Remove selected state from all bubbles
        document.querySelectorAll('.dialogue-bubble').forEach(bubble => 
          bubble.classList.remove('selected')
        );
      });
    };

    // Call this function when the page loads
    window.addEventListener('load', () => {
      makeCustomizationPanelDraggable();
    });

    // Generate Story Function Integration
    const generateStoryFunction = async () => {
      const generateStoryButton = document.getElementById('generate-story');
      generateStoryButton.addEventListener('click', generateStory);
    };

    // Generate Combined Image Function Integration
    const generateCombinedImageFunction = () => {
      const generateImageButton = document.getElementById('generate-combined-image');
      generateImageButton.addEventListener('click', generateCombinedImage);
    };

    // Generate Dialogues Function Integration
    const generateDialoguesFunction = () => {
      const generateDialoguesButton = document.getElementById('generate-dialogues');
      generateDialoguesButton.addEventListener('click', generateDialogues);
    };

    // Initialize All Event Listeners
    const initializeApp = () => {
      generateStoryFunction();
      generateCombinedImageFunction();
      generateDialoguesFunction();
    };

    // Call Initialize Function on Page Load
    window.onload = initializeApp;

  </script>
</body>
</html>