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

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

AI Voice Designer: UI/UX Design Specifications

This document outlines the detailed design specifications, wireframe descriptions, color palettes, and user experience (UX) recommendations for the "AI Voice Designer" tool. This tool aims to provide users with an intuitive and powerful interface to create completely custom AI voices, leveraging advanced text-to-speech capabilities like those offered by ElevenLabs.


1. Project Overview & Design Goals

The "AI Voice Designer" is a web-based application designed to empower users to craft unique synthetic voices by manipulating a range of acoustic and stylistic parameters. The primary goal is to abstract the complexity of underlying AI models into a user-friendly interface, allowing for precise control and real-time feedback.

Key Design Goals:

  • Intuitive Control: Make complex voice parameters accessible and easy to understand.
  • Real-time Feedback: Enable users to hear changes instantly as they adjust parameters.
  • Granular Customization: Offer a wide array of adjustable characteristics for truly unique voices.
  • Professional Aesthetic: Maintain a clean, modern, and efficient user interface.
  • Scalability: Design a flexible system that can integrate future voice customization features.

2. Detailed Design Specifications

The AI Voice Designer will allow users to define a voice through a combination of linguistic, acoustic, and stylistic attributes.

2.1. Voice Characteristic Parameters

Users will be able to adjust the following core parameters to sculpt their custom voice:

  1. Gender (Primary Attribute):

* Type: Slider or Radio Buttons

* Options: "Male" ↔ "Female" (with a continuum for less distinct gendered voices)

* Range: 0% (more masculine) to 100% (more feminine)

  1. Age Range:

* Type: Slider or Dropdown (with predefined ranges)

* Options: "Young Adult" ↔ "Middle-Aged" ↔ "Senior"

* Range: 0% (younger) to 100% (older)

  1. Pitch:

* Type: Slider

* Range: Low (-50%) to High (+50%)

* Default: 0% (natural/average)

  1. Tone/Resonance:

* Type: Sliders for multiple aspects or a combined "Tone" slider.

* Sub-parameters (if applicable):

* Brightness: Muted (-50%) to Bright (+50%)

* Warmth: Cold (-50%) to Warm (+50%)

* Huskiness: Clear (-50%) to Husky (+50%)

* Default: 0% for all.

  1. Accent/Dialect:

* Type: Dropdown with search functionality.

* Options: Standard American English, British English (RP), Australian English, Indian English, etc. (and potentially other languages if supported).

* Note: This might be a foundational choice rather than a continuous slider.

  1. Speaking Style/Pace:

* Type: Sliders

* Parameters:

* Pace: Slow (-50%) to Fast (+50%)

* Clarity/Articulation: Mumbled (-50%) to Articulate (+50%)

* Rhythm: Monotone (-50%) to Expressive (+50%)

* Default: 0% for all.

  1. Emotional Range/Intensity:

* Type: Sliders for primary emotions or a combined "Emotional Range" slider.

* Parameters:

* Calmness: Anxious (-50%) to Calm (+50%)

* Enthusiasm: Flat (-50%) to Enthusiastic (+50%)

* Formality: Casual (-50%) to Formal (+50%)

* Default: 0% for all (neutral).

  1. Voice Stability & Clarity (ElevenLabs Specific):

* Type: Sliders, potentially with advanced settings.

* Parameters:

* Stability: Control how consistent the voice is. (0-100%)

* Clarity/Similarity Enhancement: Reduce "artifacts" and improve naturalness. (0-100%)

* Style Exaggeration: Control how much the AI emphasizes stylistic elements. (0-100%)

* Default: Recommended values (e.g., 75% stability, 75% clarity).

2.2. Input Mechanisms

  • Sliders: Primary mechanism for continuous parameters (Gender, Age, Pitch, Tone, Pace, Emotional Intensity, Stability, Clarity). Sliders will have clear numerical values displayed alongside them.
  • Dropdowns: For discrete choices like Accent/Language.
  • Text Input Area: For users to type sample text to preview the voice.
  • Upload Audio (Optional/Advanced): For "Voice Cloning" or "Voice Design from Audio" features, allowing users to upload a reference voice to extract characteristics.

2.3. Preview Functionality

  • Text-to-Speech Preview: A dedicated section where users can type or paste text and trigger an audio playback of the currently designed voice.
  • Real-time Waveform: A visual representation of the generated audio during playback.
  • Quick Compare: Ability to save snapshots of voice designs and quickly switch between them for comparison.

2.4. Save & Export Options

  • Save Voice Profile: Store the custom voice parameters to the user's account for future use.
  • Export Voice Model (API Key/ID): Provide an API key or a unique ID for the custom voice, allowing integration into other applications.
  • Download Sample Audio: Option to download the preview audio in various formats (MP3, WAV).

2.5. ElevenLabs Integration Points

The "AI Voice Designer" will abstract ElevenLabs' Voice Lab and Voice Settings features:

  • Voice Lab Analogue: The core parameter sliders (Gender, Age, Pitch, Tone, etc.) will directly influence the underlying ElevenLabs synthesis model.
  • Voice Settings Analogue: Parameters like "Stability," "Clarity/Similarity Enhancement," and "Style Exaggeration" will map directly to ElevenLabs' voice settings, providing advanced fine-tuning.
  • Model Selection: Potentially allow users to choose between different underlying ElevenLabs models (e.g., standard, high-quality, or experimental models) if exposed by the API.

3. Wireframe Descriptions

The interface will be organized into logical sections to facilitate an efficient voice design workflow.

3.1. Main Layout (Two-Column Structure)

  • Left Column (Voice Parameters - ~65% width):

* Header: "Design Your Voice"

* Parameter Groups:

* Core Attributes: Gender, Age Range. (Prominently displayed)

* Acoustic Properties: Pitch, Brightness, Warmth, Huskiness.

* Speaking Style: Pace, Clarity, Rhythm.

* Emotional Nuance: Calmness, Enthusiasm, Formality.

* Advanced Settings (ElevenLabs): Stability, Clarity/Similarity Enhancement, Style Ex Exaggeration. (Collapsible section)

* Each parameter will have:

* Label (e.g., "Gender")

* Slider with current value display (e.g., "50% - Neutral")

* Optional tooltip/info icon.

* Accent/Language Selector: Dropdown with search.

  • Right Column (Preview & Actions - ~35% width):

* Header: "Preview & Actions"

* Text Input Area:

* Multi-line text field with a placeholder like "Type your sample text here..."

* Character count.

* "Generate Preview" Button: Prominently placed below the text field.

* Audio Playback Section:

* Play/Pause/Stop controls.

* Progress bar with current time.

* Real-time waveform visualization.

* Volume control.

* Voice Snapshots/Comparison (Optional):

* List of saved voice profiles.

* "Save Snapshot" button.

* "Compare" button to A/B test voices.

* Action Buttons:

* "Save Voice" Button: Saves the current configuration.

* "Export Voice ID" Button: Provides the integration ID/key.

* "Download Sample" Button: Downloads the current preview audio.

3.2. Component Descriptions

  • Sliders: Horizontal sliders with a circular thumb. Value displayed numerically next to the slider or within the thumb.
  • Dropdowns: Standard dropdown menus, with a search bar for extensive lists (e.g., accents).
  • Text Area: Resizable, multi-line input field.
  • Buttons: Clearly labeled, with primary actions (Generate Preview, Save Voice) having distinct styling.
  • Waveform Display: A dynamic, visually engaging waveform that updates during audio playback.
  • Info Icons: Small 'i' icons next to complex parameters, revealing tooltips on hover.

4. Color Palettes

A professional, clean, and modern color palette will be used to enhance usability and maintain brand consistency.

  • Primary Palette (Core UI Elements):

* Dark Blue/Grey (#1A202C): Backgrounds, main containers. Provides a sophisticated and calm base.

* Light Grey (#F7FAFC): Card backgrounds, secondary containers, text input fields. Offers contrast and clarity.

* Medium Grey (#A0AEC0): Secondary text, borders, inactive elements.

* White (#FFFFFF): Primary text, icons.

  • Accent Palette (Interactive Elements & Highlights):

* Vibrant Teal (#00B5AD): Primary action buttons ("Generate Preview", "Save Voice"), active slider thumbs, progress bars, active states. Conveys innovation and clarity.

* Softer Teal (#4FD1C5): Hover states, selected elements.

* Subtle Orange (#ED8936): Secondary or warning actions (e.g., "Reset All"). Provides a warm contrast.

  • Text & Iconography:

* Primary Text: White on dark backgrounds, Dark Blue/Grey on light backgrounds.

* Secondary Text: Medium Grey.

* Icons: White or Medium Grey, changing to Vibrant Teal on hover/active.

Example Usage:

  • Background: Dark Blue/Grey
  • Card/Panel Backgrounds: Light Grey
  • Main Headings: White
  • Parameter Labels: White
  • Slider Track (inactive): Medium Grey
  • Slider Track (active): Vibrant Teal
  • Slider Thumb: White with Vibrant Teal border
  • "Generate Preview" Button: Vibrant Teal background, White text
  • Text Input Field: Light Grey background, Dark Blue/Grey text, Medium Grey border
  • Waveform: Vibrant Teal lines on a transparent or slightly darker background.

5. UX Recommendations

Optimizing the user experience is paramount for a tool that involves detailed customization.

  1. Real-time Auditory Feedback: The most critical UX feature. As soon as a slider is released or a dropdown selected, the preview audio should reflect the change immediately upon the next "Generate Preview" click, or ideally, an auto-generate option for rapid iteration.
  2. Clear Labeling and Tooltips: Every parameter should have a concise, understandable label. Hoverable info icons should provide more detailed explanations of what each parameter influences and its typical range/effect.
  3. Visual Cues for Parameter Ranges: Sliders should visually indicate their min/max values and potentially highlight "neutral" or "recommended" zones.
  4. Undo/Redo Functionality: Allow users to easily revert or reapply changes during the design process, fostering experimentation.
  5. Voice Snapshots & Comparison: Enable users to save multiple iterations of their voice design and quickly switch between them. A "Compare Mode" could play two selected voices sequentially or in an A/B fashion.
  6. Default Settings & "Reset to Default": Provide intelligent default values for all parameters to give users a good starting point. A "Reset All" button should be available (with a confirmation prompt).
  7. Guidance & Onboarding: For first-time users, a brief interactive tutorial or guided tour could explain the purpose of each section and parameter.
  8. Performance Optimization: Ensure the voice generation process is fast and responsive to maintain a smooth workflow, especially for previews.
  9. Accessibility:

* Keyboard Navigation: Ensure all interactive elements are reachable and controllable via keyboard.

* Contrast Ratios: Adhere to WCAG guidelines for text and interactive element contrast.

* Screen Reader Compatibility: Proper ARIA labels and semantic HTML for screen reader users.

  1. Error Handling & Feedback:

* Clear, non-technical error messages if voice generation fails (e.g., "Text too long," "Network error").

* Loading indicators during voice generation to manage user expectations.

  1. Responsive Design: Ensure the interface is usable across various screen sizes, from desktops to tablets (though voice design might be less common
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);}});}