AI Voice Designer
Run ID: 69cd052f3e7fb09ff16a73382026-04-01Design
PantheraHive BOS
BOS Dashboard

Design a completely custom AI voice by describing the characteristics you want

AI Voice Designer: Custom Voice Design Specifications

This document outlines the detailed design specifications, wireframe descriptions, color palettes, and user experience (UX) recommendations for the "AI Voice Designer" step. The goal is to provide a comprehensive and intuitive interface for users to design completely custom AI voices by describing their desired characteristics.


1. Overall Concept & Goal

The "AI Voice Designer" provides a powerful, user-friendly interface to craft unique synthetic voices. Users will be able to define a voice's core attributes (e.g., pitch, tone, pace), emotional range, accent, perceived age/gender, and overall persona through a combination of intuitive controls and descriptive inputs. The system will then generate a voice that matches these specifications, allowing for real-time preview and iterative refinement.

Core Objective: Enable users to articulate and create a highly personalized AI voice, moving beyond pre-set options to truly custom sonic identities.


2. Detailed Design Specifications

The voice design interface will be structured around key voice attributes, offering both qualitative and quantitative controls.

2.1 Core Voice Attributes

These are the fundamental building blocks of the voice, controlled primarily via sliders and descriptive tags.

  • Pitch:

* Control: Slider (Very Low - High - Very High). Numerical value (e.g., -5 to +5 semitones relative to a neutral baseline).

* Description: Perceived "highness" or "lowness" of the voice.

  • Tone/Resonance:

* Control: Slider (Warm/Resonant - Neutral - Clear/Bright).

* Description: The timber and quality of the voice.

  • Pace/Speed:

* Control: Slider (Very Slow - Normal - Very Fast). Numerical value (e.g., 0.7x to 1.5x normal speed).

* Description: Words per minute (WPM).

  • Volume/Loudness:

* Control: Slider (Soft - Normal - Loud).

* Description: Perceived amplitude of the voice.

  • Inflection/Prosody:

* Control: Slider (Monotone - Natural - Expressive).

* Description: The variation in pitch, rhythm, and stress in speech.

  • Clarity/Articulation:

* Control: Slider (Mumbled - Clear - Crisp).

* Description: How distinct and easy to understand the speech is.

2.2 Perceived Characteristics

These attributes define how the voice is generally perceived.

  • Perceived Gender:

* Control: Slider (Masculine - Neutral - Feminine).

* Description: The perceived gender identity conveyed by the voice's characteristics.

  • Perceived Age:

* Control: Slider (Young Adult - Middle-Aged - Elderly).

* Description: The perceived age range of the speaker.

  • Speech Style/Persona:

* Control: Multi-select tags/checkboxes (e.g., Professional, Conversational, Authoritative, Empathetic, Storyteller, News Anchor, Energetic, Calm, Witty, Serious, Friendly).

* Description: The overall manner and character of the voice.

2.3 Accent & Dialect

  • Primary Accent:

* Control: Dropdown menu with common accents (e.g., US English - General American, US English - Southern, UK English - RP, UK English - Cockney, Australian English, Indian English, etc.).

* Description: The geographical or social origin of the pronunciation.

  • Accent Strength:

* Control: Slider (Subtle - Moderate - Strong).

* Description: How pronounced the selected accent is.

2.4 Emotional Range & Expressiveness

  • Default Emotion:

* Control: Dropdown/Radio buttons (Neutral, Happy, Sad, Angry, Fearful, Surprised, Calm, Excited, Empathetic).

* Description: The primary emotional baseline of the voice.

  • Emotional Variability:

* Control: Slider (Consistent - Dynamic).

* Description: How much the voice's emotional expression can fluctuate.

2.5 Advanced Technical Parameters (Optional for Power Users)

These parameters allow finer control for users familiar with ElevenLabs' underlying technology. They can be presented in an "Advanced Settings" collapsible section.

  • Voice Stability:

* Control: Slider (0.0 - 1.0).

* Description: Consistency of the voice's characteristics. Higher values produce more stable voices but can sound monotonous.

  • Clarity/Similarity Boost:

* Control: Slider (0.0 - 1.0).

* Description: How closely the generated voice matches the intended characteristics. Higher values can sometimes introduce artifacts.

  • Style Exaggeration:

* Control: Slider (0.0 - 1.0).

* Description: Controls the degree of accent and emotional expressiveness.

2.6 Preview & Iteration

  • Text Input Field: A large text area for users to type sample sentences (min 10 words, max 200 words) to hear their designed voice.
  • "Generate Preview" Button: Initiates the voice synthesis based on current parameters.
  • Play/Pause/Stop Controls: Standard audio playback controls.
  • Volume Control: For the preview playback.

2.7 Save & Manage

  • "Save Voice" Button: Prompts the user to name their custom voice.
  • Voice Name Input: Text field for naming the voice.
  • "My Custom Voices" Section: A list/grid view of previously saved custom voices, with options to:

* Load (to edit)

* Use (to apply to a project)

* Rename

* Delete

* Share (optional)


3. Wireframe Descriptions

The interface will be organized into logical panels, ensuring a clear flow from definition to preview and saving.

3.1 Main Voice Designer Layout

  • Layout: Two-column or three-panel layout.

* Left Panel (Controls - ~60% width): Houses all the sliders, dropdowns, and checkboxes for voice attribute definition. Organized into collapsible sections.

* Right Panel (Preview & Action - ~40% width): Dedicated to text input, preview playback, and save/load options.

  • Top Header:

* "AI Voice Designer" title.

* "Reset to Default" button.

* "Help/Tutorial" icon.

  • Left Panel Sections (Collapsible):

1. Core Voice Attributes: Sliders for Pitch, Tone, Pace, Volume, Inflection, Clarity.

2. Perceived Characteristics: Sliders for Perceived Gender, Perceived Age; Multi-select for Speech Style/Persona.

3. Accent & Dialect: Dropdown for Primary Accent, Slider for Accent Strength.

4. Emotional Range: Dropdown for Default Emotion, Slider for Emotional Variability.

5. Advanced Settings (Collapsible by default): Sliders for Voice Stability, Clarity/Similarity Boost, Style Exaggeration.

  • Right Panel Sections:

1. Preview Text Input:

* Large textarea with a placeholder: "Type text here to preview your custom voice (min 10 words, max 200 words)..."

* Word/character count below.

2. Preview Controls:

* "Generate Preview" button (prominent).

* Audio Player with Play/Pause/Stop, progress bar, and volume slider.

3. Actions:

* "Save Voice" button.

* "Load Existing Voice" button (opens a modal or expands a section to show saved voices).

3.2 "Save Voice" Modal/Flyout

  • Title: "Save Custom Voice"
  • Input Field: Label: "Voice Name", Placeholder: "e.g., 'My AI Assistant', 'Narrator Bot'"
  • Buttons: "Cancel", "Save"

3.3 "My Custom Voices" Modal/Section

  • Title: "My Custom Voices"
  • List/Grid: Each item displays:

* Voice Name

* Small icon/visual representation

* Action Buttons: "Load", "Use", "Rename", "Delete"

  • Search/Filter Bar: (Optional, for many saved voices)
  • Close Button.

4. Color Palettes

A professional, modern, and accessible color palette will be used, prioritizing readability and a clean aesthetic.

  • Primary Brand Color (Accent): #007AFF (A vibrant, professional blue, common in tech UIs).
  • Secondary Accent/Highlight: #34C759 (A subtle green for success states or active elements).
  • Background (Light Mode):

* Main Background: #F9F9F9 (Soft off-white)

* Panel Background: #FFFFFF (Pure white for content cards/panels)

  • Text Colors:

* Primary Text: #2C2C2E (Dark charcoal for headings and main content)

* Secondary Text/Labels: #8E8E93 (Medium gray for descriptions, placeholders)

* Disabled Text: #C7C7CC (Light gray)

  • Interactive Elements:

* Buttons (Primary): Background: #007AFF, Text: #FFFFFF

* Buttons (Secondary/Outline): Background: transparent, Border: #007AFF, Text: #007AFF

* Sliders/Toggles (Active): #007AFF

* Borders/Dividers: #E5E5EA (Light gray)

  • Error/Warning: #FF3B30 (Red)

Accessibility Considerations:

  • Ensure sufficient contrast ratios (WCAG 2.1 AA standard) for all text and interactive elements.
  • Provide clear focus states for keyboard navigation.
  • Consider a future Dark Mode option.

5. UX Recommendations

User experience is paramount for a complex tool like a voice designer.

  1. Progressive Disclosure: Initially, show core attributes. Advanced settings can be collapsed by default or accessed via a dedicated tab/button, preventing overwhelm for new users.
  2. Real-time Feedback: As sliders are adjusted, provide immediate visual feedback (e.g., a numerical value change). While full real-time audio synthesis might be too resource-intensive, the "Generate Preview" button should be prominently available and quick.
  3. Clear Labeling & Tooltips: Every slider, dropdown, and button should have a clear, concise label. Hover tooltips should provide brief explanations or examples for complex attributes (e.g., "What is 'Inflection'?").
  4. Intuitive Controls: Utilize standard UI patterns (sliders for continuous values, dropdowns for discrete choices, checkboxes for multiple selections).
  5. Undo/Redo Functionality: Essential for iterative design. Allow users to backtrack changes.
  6. "Reset to Default" Option: A quick way to revert all parameters to a neutral starting point.
  7. Guidance & Examples:

* Provide example text for the preview.

* Offer "Suggested Voices" or "Templates" to kickstart the design process, allowing users to load a template and then customize it.

* A small "i" icon next to complex terms linking to a glossary or help article.

  1. Performance: Ensure the preview generation is fast. Delays will frustrate users. Optimize the underlying ElevenLabs API calls.
  2. Error Handling: Clearly communicate any errors during voice generation or saving (e.g., "Preview generation failed. Please try again.").
  3. Mobile Responsiveness: Design should adapt gracefully to smaller screens, potentially reorganizing panels into tabs or vertical stacks.
  4. Save State: Automatically save user's current design parameters locally (e.g., in browser storage) so they don't lose work if they navigate away accidentally.
  5. Onboarding Tour: For first-time users, a brief interactive tour highlighting key features and controls can significantly reduce the learning curve.

By implementing these detailed specifications and UX best practices, the AI Voice Designer will empower users to create truly unique and expressive AI voices with ease and precision.

ai_voice_designer.md
Download as Markdown
Copy all content
Full output as text
Download ZIP
IDE-ready project ZIP
Copy share link
Permanent URL for this run
Get Embed Code
Embed this result on any website
Print / Save PDF
Use browser print dialog
"); var hasSrcMain=Object.keys(extracted).some(function(k){return k.indexOf("src/main")>=0;}); if(!hasSrcMain) zip.file(folder+"src/main."+ext,"import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( ) "); var hasSrcApp=Object.keys(extracted).some(function(k){return k==="src/App."+ext||k==="App."+ext;}); if(!hasSrcApp) zip.file(folder+"src/App."+ext,"import React from 'react' import './App.css' function App(){ return(

"+slugTitle(pn)+"

Built with PantheraHive BOS

) } export default App "); zip.file(folder+"src/index.css","*{margin:0;padding:0;box-sizing:border-box} body{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e} .app{min-height:100vh;display:flex;flex-direction:column} .app-header{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px} h1{font-size:2.5rem;font-weight:700} "); zip.file(folder+"src/App.css",""); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/pages/.gitkeep",""); zip.file(folder+"src/hooks/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+" Generated by PantheraHive BOS. ## Setup ```bash npm install npm run dev ``` ## Build ```bash npm run build ``` ## Open in IDE Open the project folder in VS Code or WebStorm. "); zip.file(folder+".gitignore","node_modules/ dist/ .env .DS_Store *.local "); } /* --- Vue (Vite + Composition API + TypeScript) --- */ function buildVue(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{ "name": "'+pn+'", "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vue-tsc -b && vite build", "preview": "vite preview" }, "dependencies": { "vue": "^3.5.13", "vue-router": "^4.4.5", "pinia": "^2.3.0", "axios": "^1.7.9" }, "devDependencies": { "@vitejs/plugin-vue": "^5.2.1", "typescript": "~5.7.3", "vite": "^6.0.5", "vue-tsc": "^2.2.0" } } '); zip.file(folder+"vite.config.ts","import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': resolve(__dirname,'src') } } }) "); zip.file(folder+"tsconfig.json",'{"files":[],"references":[{"path":"./tsconfig.app.json"},{"path":"./tsconfig.node.json"}]} '); zip.file(folder+"tsconfig.app.json",'{ "compilerOptions":{ "target":"ES2020","useDefineForClassFields":true,"module":"ESNext","lib":["ES2020","DOM","DOM.Iterable"], "skipLibCheck":true,"moduleResolution":"bundler","allowImportingTsExtensions":true, "isolatedModules":true,"moduleDetection":"force","noEmit":true,"jsxImportSource":"vue", "strict":true,"paths":{"@/*":["./src/*"]} }, "include":["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"] } '); zip.file(folder+"env.d.ts","/// "); zip.file(folder+"index.html"," "+slugTitle(pn)+"
"); var hasMain=Object.keys(extracted).some(function(k){return k==="src/main.ts"||k==="main.ts";}); if(!hasMain) zip.file(folder+"src/main.ts","import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' import './assets/main.css' const app = createApp(App) app.use(createPinia()) app.mount('#app') "); var hasApp=Object.keys(extracted).some(function(k){return k.indexOf("App.vue")>=0;}); if(!hasApp) zip.file(folder+"src/App.vue"," "); zip.file(folder+"src/assets/main.css","*{margin:0;padding:0;box-sizing:border-box}body{font-family:system-ui,sans-serif;background:#fff;color:#213547} "); zip.file(folder+"src/components/.gitkeep",""); zip.file(folder+"src/views/.gitkeep",""); zip.file(folder+"src/stores/.gitkeep",""); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+" Generated by PantheraHive BOS. ## Setup ```bash npm install npm run dev ``` ## Build ```bash npm run build ``` Open in VS Code or WebStorm. "); zip.file(folder+".gitignore","node_modules/ dist/ .env .DS_Store *.local "); } /* --- Angular (v19 standalone) --- */ function buildAngular(zip,folder,app,code,panelTxt){ var pn=pkgName(app); var C=cc(pn); var sel=pn.replace(/_/g,"-"); var extracted=extractCode(panelTxt); zip.file(folder+"package.json",'{ "name": "'+pn+'", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test" }, "dependencies": { "@angular/animations": "^19.0.0", "@angular/common": "^19.0.0", "@angular/compiler": "^19.0.0", "@angular/core": "^19.0.0", "@angular/forms": "^19.0.0", "@angular/platform-browser": "^19.0.0", "@angular/platform-browser-dynamic": "^19.0.0", "@angular/router": "^19.0.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" }, "devDependencies": { "@angular-devkit/build-angular": "^19.0.0", "@angular/cli": "^19.0.0", "@angular/compiler-cli": "^19.0.0", "typescript": "~5.6.0" } } '); zip.file(folder+"angular.json",'{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "'+pn+'": { "projectType": "application", "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:application", "options": { "outputPath": "dist/'+pn+'", "index": "src/index.html", "browser": "src/main.ts", "tsConfig": "tsconfig.app.json", "styles": ["src/styles.css"], "scripts": [] } }, "serve": {"builder":"@angular-devkit/build-angular:dev-server","configurations":{"production":{"buildTarget":"'+pn+':build:production"},"development":{"buildTarget":"'+pn+':build:development"}},"defaultConfiguration":"development"} } } } } '); zip.file(folder+"tsconfig.json",'{ "compileOnSave": false, "compilerOptions": {"baseUrl":"./","outDir":"./dist/out-tsc","forceConsistentCasingInFileNames":true,"strict":true,"noImplicitOverride":true,"noPropertyAccessFromIndexSignature":true,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"paths":{"@/*":["src/*"]},"skipLibCheck":true,"esModuleInterop":true,"sourceMap":true,"declaration":false,"experimentalDecorators":true,"moduleResolution":"bundler","importHelpers":true,"target":"ES2022","module":"ES2022","useDefineForClassFields":false,"lib":["ES2022","dom"]}, "references":[{"path":"./tsconfig.app.json"}] } '); zip.file(folder+"tsconfig.app.json",'{ "extends":"./tsconfig.json", "compilerOptions":{"outDir":"./dist/out-tsc","types":[]}, "files":["src/main.ts"], "include":["src/**/*.d.ts"] } '); zip.file(folder+"src/index.html"," "+slugTitle(pn)+" "); zip.file(folder+"src/main.ts","import { bootstrapApplication } from '@angular/platform-browser'; import { appConfig } from './app/app.config'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent, appConfig) .catch(err => console.error(err)); "); zip.file(folder+"src/styles.css","* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, -apple-system, sans-serif; background: #f9fafb; color: #111827; } "); var hasComp=Object.keys(extracted).some(function(k){return k.indexOf("app.component")>=0;}); if(!hasComp){ zip.file(folder+"src/app/app.component.ts","import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { title = '"+pn+"'; } "); zip.file(folder+"src/app/app.component.html","

"+slugTitle(pn)+"

Built with PantheraHive BOS

"); zip.file(folder+"src/app/app.component.css",".app-header{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;gap:16px}h1{font-size:2.5rem;font-weight:700;color:#6366f1} "); } zip.file(folder+"src/app/app.config.ts","import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { providers: [ provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes) ] }; "); zip.file(folder+"src/app/app.routes.ts","import { Routes } from '@angular/router'; export const routes: Routes = []; "); Object.keys(extracted).forEach(function(p){ var fp=p.startsWith("src/")?p:"src/"+p; zip.file(folder+fp,extracted[p]); }); zip.file(folder+"README.md","# "+slugTitle(pn)+" Generated by PantheraHive BOS. ## Setup ```bash npm install ng serve # or: npm start ``` ## Build ```bash ng build ``` Open in VS Code with Angular Language Service extension. "); zip.file(folder+".gitignore","node_modules/ dist/ .env .DS_Store *.local .angular/ "); } /* --- Python --- */ function buildPython(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^```[w]* ?/m,"").replace(/ ?```$/m,"").trim(); var reqMap={"numpy":"numpy","pandas":"pandas","sklearn":"scikit-learn","tensorflow":"tensorflow","torch":"torch","flask":"flask","fastapi":"fastapi","uvicorn":"uvicorn","requests":"requests","sqlalchemy":"sqlalchemy","pydantic":"pydantic","dotenv":"python-dotenv","PIL":"Pillow","cv2":"opencv-python","matplotlib":"matplotlib","seaborn":"seaborn","scipy":"scipy"}; var reqs=[]; Object.keys(reqMap).forEach(function(k){if(src.indexOf("import "+k)>=0||src.indexOf("from "+k)>=0)reqs.push(reqMap[k]);}); var reqsTxt=reqs.length?reqs.join(" "):"# add dependencies here "; zip.file(folder+"main.py",src||"# "+title+" # Generated by PantheraHive BOS print(title+" loaded") "); zip.file(folder+"requirements.txt",reqsTxt); zip.file(folder+".env.example","# Environment variables "); zip.file(folder+"README.md","# "+title+" Generated by PantheraHive BOS. ## Setup ```bash python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## Run ```bash python main.py ``` "); zip.file(folder+".gitignore",".venv/ __pycache__/ *.pyc .env .DS_Store "); } /* --- Node.js --- */ function buildNode(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^```[w]* ?/m,"").replace(/ ?```$/m,"").trim(); var depMap={"mongoose":"^8.0.0","dotenv":"^16.4.5","axios":"^1.7.9","cors":"^2.8.5","bcryptjs":"^2.4.3","jsonwebtoken":"^9.0.2","socket.io":"^4.7.4","uuid":"^9.0.1","zod":"^3.22.4","express":"^4.18.2"}; var deps={}; Object.keys(depMap).forEach(function(k){if(src.indexOf(k)>=0)deps[k]=depMap[k];}); if(!deps["express"])deps["express"]="^4.18.2"; var pkgJson=JSON.stringify({"name":pn,"version":"1.0.0","main":"src/index.js","scripts":{"start":"node src/index.js","dev":"nodemon src/index.js"},"dependencies":deps,"devDependencies":{"nodemon":"^3.0.3"}},null,2)+" "; zip.file(folder+"package.json",pkgJson); var fallback="const express=require("express"); const app=express(); app.use(express.json()); app.get("/",(req,res)=>{ res.json({message:""+title+" API"}); }); const PORT=process.env.PORT||3000; app.listen(PORT,()=>console.log("Server on port "+PORT)); "; zip.file(folder+"src/index.js",src||fallback); zip.file(folder+".env.example","PORT=3000 "); zip.file(folder+".gitignore","node_modules/ .env .DS_Store "); zip.file(folder+"README.md","# "+title+" Generated by PantheraHive BOS. ## Setup ```bash npm install ``` ## Run ```bash npm run dev ``` "); } /* --- Vanilla HTML --- */ function buildVanillaHtml(zip,folder,app,code){ var title=slugTitle(app); var isFullDoc=code.trim().toLowerCase().indexOf("=0||code.trim().toLowerCase().indexOf("=0; var indexHtml=isFullDoc?code:" "+title+" "+code+" "; zip.file(folder+"index.html",indexHtml); zip.file(folder+"style.css","/* "+title+" — styles */ *{margin:0;padding:0;box-sizing:border-box} body{font-family:system-ui,-apple-system,sans-serif;background:#fff;color:#1a1a2e} "); zip.file(folder+"script.js","/* "+title+" — scripts */ "); zip.file(folder+"assets/.gitkeep",""); zip.file(folder+"README.md","# "+title+" Generated by PantheraHive BOS. ## Open Double-click `index.html` in your browser. Or serve locally: ```bash npx serve . # or python3 -m http.server 3000 ``` "); zip.file(folder+".gitignore",".DS_Store node_modules/ .env "); } /* ===== MAIN ===== */ var sc=document.createElement("script"); sc.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"; sc.onerror=function(){ if(lbl)lbl.textContent="Download ZIP"; alert("JSZip load failed — check connection."); }; sc.onload=function(){ var zip=new JSZip(); var base=(_phFname||"output").replace(/.[^.]+$/,""); var app=base.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")||"my_app"; var folder=app+"/"; var vc=document.getElementById("panel-content"); var panelTxt=vc?(vc.innerText||vc.textContent||""):""; var lang=detectLang(_phCode,panelTxt); if(_phIsHtml){ buildVanillaHtml(zip,folder,app,_phCode); } else if(lang==="flutter"){ buildFlutter(zip,folder,app,_phCode,panelTxt); } else if(lang==="react-native"){ buildReactNative(zip,folder,app,_phCode,panelTxt); } else if(lang==="swift"){ buildSwift(zip,folder,app,_phCode,panelTxt); } else if(lang==="kotlin"){ buildKotlin(zip,folder,app,_phCode,panelTxt); } else if(lang==="react"){ buildReact(zip,folder,app,_phCode,panelTxt); } else if(lang==="vue"){ buildVue(zip,folder,app,_phCode,panelTxt); } else if(lang==="angular"){ buildAngular(zip,folder,app,_phCode,panelTxt); } else if(lang==="python"){ buildPython(zip,folder,app,_phCode); } else if(lang==="node"){ buildNode(zip,folder,app,_phCode); } else { /* Document/content workflow */ var title=app.replace(/_/g," "); var md=_phAll||_phCode||panelTxt||"No content"; zip.file(folder+app+".md",md); var h=""+title+""; h+="

"+title+"

"; var hc=md.replace(/&/g,"&").replace(//g,">"); hc=hc.replace(/^### (.+)$/gm,"

$1

"); hc=hc.replace(/^## (.+)$/gm,"

$1

"); hc=hc.replace(/^# (.+)$/gm,"

$1

"); hc=hc.replace(/**(.+?)**/g,"$1"); hc=hc.replace(/ {2,}/g,"

"); h+="

"+hc+"

Generated by PantheraHive BOS
"; zip.file(folder+app+".html",h); zip.file(folder+"README.md","# "+title+" Generated by PantheraHive BOS. Files: - "+app+".md (Markdown) - "+app+".html (styled HTML) "); } zip.generateAsync({type:"blob"}).then(function(blob){ var a=document.createElement("a"); a.href=URL.createObjectURL(blob); a.download=app+".zip"; a.click(); URL.revokeObjectURL(a.href); if(lbl)lbl.textContent="Download ZIP"; }); }; document.head.appendChild(sc); }function phShare(){navigator.clipboard.writeText(window.location.href).then(function(){var el=document.getElementById("ph-share-lbl");if(el){el.textContent="Link copied!";setTimeout(function(){el.textContent="Copy share link";},2500);}});}function phEmbed(){var runId=window.location.pathname.split("/").pop().replace(".html","");var embedUrl="https://pantherahive.com/embed/"+runId;var code='';navigator.clipboard.writeText(code).then(function(){var el=document.getElementById("ph-embed-lbl");if(el){el.textContent="Embed code copied!";setTimeout(function(){el.textContent="Get Embed Code";},2500);}});}