AI Voice Designer
Run ID: 69cbf31561b1021a29a8dd9c2026-03-31Design
PantheraHive BOS
BOS Dashboard

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

This document outlines the detailed design specifications, user interface (UI) wireframe descriptions, color palette recommendations, and user experience (UX) best practices for an "AI Voice Designer" tool. This deliverable focuses on enabling customers to design a completely custom AI voice by defining its characteristics, leveraging advanced text-to-speech (TTS) capabilities similar to ElevenLabs' voice design functionalities.


AI Voice Designer: Detailed Design Specifications

The core of the AI Voice Designer is to provide granular control over various vocal characteristics. The following specifications detail the parameters available for customization:

1. Core Voice Archetype

  • Gender Archetype:

* Options: Male, Female, Gender-Neutral.

* Description: Establishes the fundamental vocal range and perceived gender.

  • Age Range:

* Options: Young Adult (18-30), Adult (30-50), Middle-Aged (50-65), Senior (65+).

* Description: Influences vocal maturity, timbre, and perceived energy levels.

  • Accent/Language:

* Options: Standard American English, British English (RP), Australian English, Indian English, etc. (expandable based on supported languages/accents).

* Description: Defines the primary linguistic accent and pronunciation style.

2. Tone & Style Characteristics

  • Professionalism:

* Range: Casual (1) to Highly Professional (10).

* Description: Controls the formality and gravitas of the voice.

  • Friendliness/Warmth:

* Range: Reserved (1) to Very Friendly (10).

* Description: Adjusts the perceived approachability and warmth of the voice.

  • Energy Level:

* Range: Calm/Relaxed (1) to Energetic/Enthusiastic (10).

* Description: Dictates the overall vivacity and pace of delivery.

  • Authoritativeness:

* Range: Gentle (1) to Authoritative (10).

* Description: Modulates the perceived command and confidence in the voice.

  • Emotional Expressiveness:

* Range: Monotone/Neutral (1) to Highly Expressive (10).

* Description: Controls the voice's ability to convey a broad range of emotions naturally.

3. Speech Dynamics & Acoustics

  • Pitch:

* Range: Very Low (-5) to Very High (+5) relative to archetype average.

* Description: Fine-tunes the fundamental frequency of the voice.

  • Speech Rate:

* Range: Very Slow (0.5x) to Very Fast (2.0x) relative to natural pace.

* Description: Adjusts words per minute (WPM) for the voice.

  • Volume/Loudness:

* Range: Soft (-5dB) to Loud (+5dB) relative to standard.

* Description: Controls the perceived intensity of the voice.

  • Clarity/Articulation:

* Range: Muffled (1) to Crystal Clear (10).

* Description: Defines the crispness and distinctness of pronunciation.

  • Resonance/Timbre:

* Options (discrete or slider with blend): Warm, Clear, Deep, Bright, Husky, Smooth.

* Description: Affects the unique quality and "color" of the voice.

4. Advanced Settings (Collapsible Section)

  • Stability (ElevenLabs specific):

* Range: Low (0%) to High (100%).

* Description: Controls the consistency of the voice across different text inputs. Lower stability can introduce more variability and emotion; higher stability ensures uniformity.

  • Clarity + Style Exaggeration (ElevenLabs specific):

* Range: Low (0%) to High (100%).

* Description: Controls how much the voice emphasizes text-based style and clarity. Higher values can make the voice more dramatic or pronounced.

  • Pause Duration:

* Range: Shorter (0.5x) to Longer (2.0x) relative to natural pauses.

* Description: Adjusts the length of natural pauses within speech.


Wireframe Descriptions (User Interface)

The AI Voice Designer will feature an intuitive, single-page interface with distinct sections for voice parameter selection, preview, and saving.

1. Layout Overview

  • Left Panel (Collapsible): Voice Presets / Saved Voices Library.
  • Central Panel: Voice Design Controls (main area for sliders, dropdowns).
  • Bottom Panel: Text Input for Preview, Playback Controls, Save/Download Actions.

2. Central Panel: Voice Design Controls

  • Section Header: "Define Voice Characteristics"

* Sub-section: "Core Archetype"

* Gender Archetype: Radio buttons (Male, Female, Neutral) or a single dropdown.

* Age Range: Dropdown menu (Young Adult, Adult, Middle-Aged, Senior).

* Accent/Language: Dropdown menu (e.g., Standard American English, British English (RP)).

* Sub-section: "Tone & Style"

* Professionalism: Horizontal Slider (1-10) with descriptive labels at ends (e.g., "Casual" - "Formal").

* Friendliness/Warmth: Horizontal Slider (1-10) with descriptive labels (e.g., "Reserved" - "Warm").

* Energy Level: Horizontal Slider (1-10) with descriptive labels (e.g., "Calm" - "Energetic").

* Authoritativeness: Horizontal Slider (1-10) with descriptive labels (e.g., "Gentle" - "Commanding").

* Emotional Expressiveness: Horizontal Slider (1-10) with descriptive labels (e.g., "Monotone" - "Vibrant").

* Sub-section: "Speech Dynamics & Acoustics"

* Pitch: Horizontal Slider (-5 to +5) with a central "Normal" marker.

* Speech Rate: Horizontal Slider (0.5x to 2.0x) with a central "Normal" (1.0x) marker.

* Volume/Loudness: Horizontal Slider (-5dB to +5dB) with a central "Normal" (0dB) marker.

* Clarity/Articulation: Horizontal Slider (1-10) with descriptive labels (e.g., "Muffled" - "Crystal Clear").

* Resonance/Timbre: Multi-select checkboxes or a single dropdown (Warm, Clear, Deep, Bright, Husky, Smooth).

* Sub-section: "Advanced Settings" (Collapsible Accordion)

* Stability: Horizontal Slider (0% to 100%).

* Clarity + Style Exaggeration: Horizontal Slider (0% to 100%).

* Pause Duration: Horizontal Slider (0.5x to 2.0x).

Each advanced slider will have a small 'i' icon with a tooltip explaining its function.*

3. Bottom Panel: Preview & Actions

  • Text Input Area: Large multi-line text field (<textarea>) for users to enter text for voice preview. Placeholder text: "Enter text to preview your custom voice..."
  • Character Count: Displays remaining characters for the preview text (e.g., "500/1000 characters").
  • "Preview Voice" Button: Prominently displayed, initiates the voice generation for the entered text.
  • Playback Controls:

* Play/Pause Button: Standard play/pause icon.

* Stop Button: Standard stop icon.

* Progress Bar/Waveform Visualizer: Shows playback progress and provides a visual representation of the audio.

  • "Save Voice" Button: After previewing, allows the user to save their custom voice.
  • Voice Name Input Field: Appears upon clicking "Save Voice," prompting the user to name their creation.
  • "Download Audio" Button (Optional): Allows downloading the previewed audio clip.

4. Left Panel (Optional but Recommended): Voice Library/Presets

  • Section Header: "Voice Library"

* "Create New Voice" Button: Clears all current selections and resets sliders to default.

* "Presets" Sub-section:

* List of predefined voice templates (e.g., "News Anchor," "Podcast Host," "Friendly AI Assistant"). Clicking a preset populates the controls.

* "My Saved Voices" Sub-section:

* List of user-saved custom voices. Each entry includes:

* Voice Name

* "Load" Button: Loads the voice's parameters into the designer.

* "Edit" Button: Loads for modification.

* "Delete" Button: Removes the voice.


Color Palette Recommendations

A professional, clean, and modern color palette will enhance usability and visual appeal.

  • Primary Accent Color: #007bff (A vibrant, professional blue)

Usage:* Buttons, interactive elements, highlights, active states.

  • Secondary Accent Color: #28a745 (A subtle, reassuring green)

Usage:* Success messages, "Save" button.

  • Backgrounds:

* Main Background: #f8f9fa (Light off-white/very light gray)

* Panel Backgrounds: #ffffff (Pure white)

* Hover/Active Backgrounds: #e9ecef (Slightly darker light gray)

  • Text Colors:

* Primary Text: #343a40 (Dark charcoal gray)

* Secondary Text/Labels: #6c757d (Medium gray)

* Disabled Text: #adb5bd (Light gray)

  • Feedback Colors:

* Success: #28a745 (Same as secondary accent)

* Warning: #ffc107 (Amber yellow)

* Error: #dc3545 (Red)

  • Interactive Elements (Sliders, Toggles):

* Track: #dee2e6 (Light gray)

* Thumb: #007bff (Primary accent)


UX Recommendations

1. Intuitive & Guided Experience

  • Default Presets: Start users with a few well-designed presets (e.g., "Standard Male Voice," "Friendly Female Voice") to provide a baseline and demonstrate capabilities.
  • Clear Labeling & Tooltips: Every slider, dropdown, and button should have a clear, concise label. Information icons (i) with tooltips should explain complex parameters (e.g., "Stability," "Clarity + Style Exaggeration") in simple terms.
  • Visual Feedback: When adjusting sliders, provide immediate visual changes (if possible, e.g., a subtle change in a waveform visualizer) or at least a clear numerical value.

2. Efficient Iteration & Feedback Loop

  • "Preview Voice" Prominence: Make the preview button highly visible and easy to access.
  • Fast Generation: Aim for minimal latency between clicking "Preview Voice" and hearing the output.
  • Real-time Parameter Updates (Ideal): If technically feasible, allow some parameters (e.g., Pitch, Speech Rate) to update the previewed audio in near real-time as the slider is moved, reducing the need for repeated clicks.
  • Compare Feature: Allow users to save multiple voice "snapshots" and compare them side-by-side or switch between
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
\n\n\n"); 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'\nimport ReactDOM from 'react-dom/client'\nimport App from './App'\nimport './index.css'\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n \n \n)\n"); 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'\nimport './App.css'\n\nfunction App(){\n return(\n
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n
\n )\n}\nexport default App\n"); zip.file(folder+"src/index.css","*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e}\n.app{min-height:100vh;display:flex;flex-direction:column}\n.app-header{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:40px}\nh1{font-size:2.5rem;font-weight:700}\n"); 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)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\n## Open in IDE\nOpen the project folder in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- 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",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "type": "module",\n "scripts": {\n "dev": "vite",\n "build": "vue-tsc -b && vite build",\n "preview": "vite preview"\n },\n "dependencies": {\n "vue": "^3.5.13",\n "vue-router": "^4.4.5",\n "pinia": "^2.3.0",\n "axios": "^1.7.9"\n },\n "devDependencies": {\n "@vitejs/plugin-vue": "^5.2.1",\n "typescript": "~5.7.3",\n "vite": "^6.0.5",\n "vue-tsc": "^2.2.0"\n }\n}\n'); zip.file(folder+"vite.config.ts","import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport { resolve } from 'path'\n\nexport default defineConfig({\n plugins: [vue()],\n resolve: { alias: { '@': resolve(__dirname,'src') } }\n})\n"); zip.file(folder+"tsconfig.json",'{"files":[],"references":[{"path":"./tsconfig.app.json"},{"path":"./tsconfig.node.json"}]}\n'); zip.file(folder+"tsconfig.app.json",'{\n "compilerOptions":{\n "target":"ES2020","useDefineForClassFields":true,"module":"ESNext","lib":["ES2020","DOM","DOM.Iterable"],\n "skipLibCheck":true,"moduleResolution":"bundler","allowImportingTsExtensions":true,\n "isolatedModules":true,"moduleDetection":"force","noEmit":true,"jsxImportSource":"vue",\n "strict":true,"paths":{"@/*":["./src/*"]}\n },\n "include":["src/**/*.ts","src/**/*.d.ts","src/**/*.tsx","src/**/*.vue"]\n}\n'); zip.file(folder+"env.d.ts","/// \n"); zip.file(folder+"index.html","\n\n\n \n \n "+slugTitle(pn)+"\n\n\n
\n \n\n\n"); 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'\nimport { createPinia } from 'pinia'\nimport App from './App.vue'\nimport './assets/main.css'\n\nconst app = createApp(App)\napp.use(createPinia())\napp.mount('#app')\n"); var hasApp=Object.keys(extracted).some(function(k){return k.indexOf("App.vue")>=0;}); if(!hasApp) zip.file(folder+"src/App.vue","\n\n\n\n\n"); 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}\n"); 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)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nnpm run dev\n\`\`\`\n\n## Build\n\`\`\`bash\nnpm run build\n\`\`\`\n\nOpen in VS Code or WebStorm.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n"); } /* --- 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",'{\n "name": "'+pn+'",\n "version": "0.0.0",\n "scripts": {\n "ng": "ng",\n "start": "ng serve",\n "build": "ng build",\n "test": "ng test"\n },\n "dependencies": {\n "@angular/animations": "^19.0.0",\n "@angular/common": "^19.0.0",\n "@angular/compiler": "^19.0.0",\n "@angular/core": "^19.0.0",\n "@angular/forms": "^19.0.0",\n "@angular/platform-browser": "^19.0.0",\n "@angular/platform-browser-dynamic": "^19.0.0",\n "@angular/router": "^19.0.0",\n "rxjs": "~7.8.0",\n "tslib": "^2.3.0",\n "zone.js": "~0.15.0"\n },\n "devDependencies": {\n "@angular-devkit/build-angular": "^19.0.0",\n "@angular/cli": "^19.0.0",\n "@angular/compiler-cli": "^19.0.0",\n "typescript": "~5.6.0"\n }\n}\n'); zip.file(folder+"angular.json",'{\n "$schema": "./node_modules/@angular/cli/lib/config/schema.json",\n "version": 1,\n "newProjectRoot": "projects",\n "projects": {\n "'+pn+'": {\n "projectType": "application",\n "root": "",\n "sourceRoot": "src",\n "prefix": "app",\n "architect": {\n "build": {\n "builder": "@angular-devkit/build-angular:application",\n "options": {\n "outputPath": "dist/'+pn+'",\n "index": "src/index.html",\n "browser": "src/main.ts",\n "tsConfig": "tsconfig.app.json",\n "styles": ["src/styles.css"],\n "scripts": []\n }\n },\n "serve": {"builder":"@angular-devkit/build-angular:dev-server","configurations":{"production":{"buildTarget":"'+pn+':build:production"},"development":{"buildTarget":"'+pn+':build:development"}},"defaultConfiguration":"development"}\n }\n }\n }\n}\n'); zip.file(folder+"tsconfig.json",'{\n "compileOnSave": false,\n "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"]},\n "references":[{"path":"./tsconfig.app.json"}]\n}\n'); zip.file(folder+"tsconfig.app.json",'{\n "extends":"./tsconfig.json",\n "compilerOptions":{"outDir":"./dist/out-tsc","types":[]},\n "files":["src/main.ts"],\n "include":["src/**/*.d.ts"]\n}\n'); zip.file(folder+"src/index.html","\n\n\n \n "+slugTitle(pn)+"\n \n \n \n\n\n \n\n\n"); zip.file(folder+"src/main.ts","import { bootstrapApplication } from '@angular/platform-browser';\nimport { appConfig } from './app/app.config';\nimport { AppComponent } from './app/app.component';\n\nbootstrapApplication(AppComponent, appConfig)\n .catch(err => console.error(err));\n"); zip.file(folder+"src/styles.css","* { margin: 0; padding: 0; box-sizing: border-box; }\nbody { font-family: system-ui, -apple-system, sans-serif; background: #f9fafb; color: #111827; }\n"); 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';\nimport { RouterOutlet } from '@angular/router';\n\n@Component({\n selector: 'app-root',\n standalone: true,\n imports: [RouterOutlet],\n templateUrl: './app.component.html',\n styleUrl: './app.component.css'\n})\nexport class AppComponent {\n title = '"+pn+"';\n}\n"); zip.file(folder+"src/app/app.component.html","
\n
\n

"+slugTitle(pn)+"

\n

Built with PantheraHive BOS

\n
\n \n
\n"); 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}\n"); } zip.file(folder+"src/app/app.config.ts","import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\nimport { provideRouter } from '@angular/router';\nimport { routes } from './app.routes';\n\nexport const appConfig: ApplicationConfig = {\n providers: [\n provideZoneChangeDetection({ eventCoalescing: true }),\n provideRouter(routes)\n ]\n};\n"); zip.file(folder+"src/app/app.routes.ts","import { Routes } from '@angular/router';\n\nexport const routes: Routes = [];\n"); 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)+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\nng serve\n# or: npm start\n\`\`\`\n\n## Build\n\`\`\`bash\nng build\n\`\`\`\n\nOpen in VS Code with Angular Language Service extension.\n"); zip.file(folder+".gitignore","node_modules/\ndist/\n.env\n.DS_Store\n*.local\n.angular/\n"); } /* --- Python --- */ function buildPython(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/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("\n"):"# add dependencies here\n"; zip.file(folder+"main.py",src||"# "+title+"\n# Generated by PantheraHive BOS\n\nprint(title+\" loaded\")\n"); zip.file(folder+"requirements.txt",reqsTxt); zip.file(folder+".env.example","# Environment variables\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\n\`\`\`\n\n## Run\n\`\`\`bash\npython main.py\n\`\`\`\n"); zip.file(folder+".gitignore",".venv/\n__pycache__/\n*.pyc\n.env\n.DS_Store\n"); } /* --- Node.js --- */ function buildNode(zip,folder,app,code){ var title=slugTitle(app); var pn=pkgName(app); var src=code.replace(/^\`\`\`[\w]*\n?/m,"").replace(/\n?\`\`\`$/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)+"\n"; zip.file(folder+"package.json",pkgJson); var fallback="const express=require(\"express\");\nconst app=express();\napp.use(express.json());\n\napp.get(\"/\",(req,res)=>{\n res.json({message:\""+title+" API\"});\n});\n\nconst PORT=process.env.PORT||3000;\napp.listen(PORT,()=>console.log(\"Server on port \"+PORT));\n"; zip.file(folder+"src/index.js",src||fallback); zip.file(folder+".env.example","PORT=3000\n"); zip.file(folder+".gitignore","node_modules/\n.env\n.DS_Store\n"); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Setup\n\`\`\`bash\nnpm install\n\`\`\`\n\n## Run\n\`\`\`bash\nnpm run dev\n\`\`\`\n"); } /* --- 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:"\n\n\n\n\n"+title+"\n\n\n\n"+code+"\n\n\n\n"; zip.file(folder+"index.html",indexHtml); zip.file(folder+"style.css","/* "+title+" — styles */\n*{margin:0;padding:0;box-sizing:border-box}\nbody{font-family:system-ui,-apple-system,sans-serif;background:#fff;color:#1a1a2e}\n"); zip.file(folder+"script.js","/* "+title+" — scripts */\n"); zip.file(folder+"assets/.gitkeep",""); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\n## Open\nDouble-click \`index.html\` in your browser.\n\nOr serve locally:\n\`\`\`bash\nnpx serve .\n# or\npython3 -m http.server 3000\n\`\`\`\n"); zip.file(folder+".gitignore",".DS_Store\nnode_modules/\n.env\n"); } /* ===== 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(/\n{2,}/g,"

"); h+="

"+hc+"

Generated by PantheraHive BOS
"; zip.file(folder+app+".html",h); zip.file(folder+"README.md","# "+title+"\n\nGenerated by PantheraHive BOS.\n\nFiles:\n- "+app+".md (Markdown)\n- "+app+".html (styled HTML)\n"); } 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);}});}