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

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

AI Voice Designer: Comprehensive Design Specifications

This document outlines the detailed design specifications for creating a custom AI voice, along with user interface (UI) and user experience (UX) recommendations, color palettes, and wireframe descriptions. The goal is to provide a robust, intuitive, and highly customizable tool for users to craft unique AI voices for various applications.


1. Detailed AI Voice Design Specifications

This section defines the core parameters and characteristics that will be configurable for generating a custom AI voice. These specifications directly influence the ElevenLabs synthesis engine.

1.1 Core Voice Attributes

  • Gender Spectrum:

* Options: Male, Female, Neutral/Androgynous.

* Control: Slider for continuous blend between masculine and feminine characteristics, allowing for nuanced gender expression beyond binary options.

  • Age Range:

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

* Control: Slider or discrete selection. Allows for vocal maturity and resonance associated with different age groups.

  • Accent & Dialect:

* Options (Tier 1 - Broad): North American (General), British English (General), Australian, Indian, Irish, Scottish, South African, European (General), Asian (General), etc.

* Options (Tier 2 - Specific, conditional on Tier 1):

North American:* General American, Canadian, Southern US, New York, Californian.

British English:* RP (Received Pronunciation), Estuary, Scottish Lowlands, Northern Irish, Welsh.

Australian:* General Australian, Cultivated Australian.

* Control: Dropdown menus, with conditional sub-options appearing based on the primary selection. Includes a "None/Standard" option for minimal accent.

  • Language:

* Options: English (primary focus), Spanish, French, German, Italian, Portuguese, Polish, Hindi, Chinese (Mandarin), Japanese, Korean, etc.

* Control: Dropdown menu. This selection will influence phonetics and intonation specific to the chosen language.

1.2 Tone & Emotion

  • Primary Tone Sliders (Continuous Blends):

* Professionalism: Casual $\longleftrightarrow$ Formal

* Energy Level: Calm $\longleftrightarrow$ Energetic

* Friendliness: Reserved $\longleftrightarrow$ Warm/Friendly

* Authority: Submissive $\longleftrightarrow$ Authoritative

* Seriousness: Playful $\longleftrightarrow$ Serious

* Empathy: Detached $\longleftrightarrow$ Empathetic

* Confidence: Hesitant $\longleftrightarrow$ Confident

  • Discrete Emotional States (Triggerable):

* Options: Happy, Sad, Angry, Excited, Neutral, Concerned, Empathetic.

Control: Dropdown or radio buttons for selecting a base emotional state, which can then be nuanced by the tone sliders. Note: For highly dynamic emotional range, this might be a separate API parameter for real-time adjustments rather than a fixed voice characteristic.*

1.3 Speaking Style & Pacing

  • Pacing: Slow $\longleftrightarrow$ Moderate $\longleftrightarrow$ Fast (Slider)
  • Clarity/Articulation: Mumbled $\longleftrightarrow$ Clear/Articulate (Slider)
  • Rhythm: Staccato $\longleftrightarrow$ Smooth/Flowing (Slider)
  • Intonation Variety: Monotone $\longleftrightarrow$ Expressive/Varied (Slider)
  • Speaking Manner:

* Options: Conversational, Narrator, News Reporter, Storyteller, Explainer, Announcer.

* Control: Dropdown or radio buttons. This influences the overall delivery cadence and emphasis.

1.4 Vocal Qualities

  • Pitch (Base Frequency): Lower $\longleftrightarrow$ Higher (Slider, relative to age/gender selection)
  • Resonance: Flat $\longleftrightarrow$ Resonant (Slider)
  • Breathiness: Clear $\longleftrightarrow$ Breathy (Slider)
  • Vocal Texture: Smooth $\longleftrightarrow$ Husky/Gravelly (Slider)
  • Volume (Relative): Soft $\longleftrightarrow$ Loud (Slider, for perceived loudness, not absolute dB)
  • Speech Rate: Slow $\longleftrightarrow$ Fast (Slider, separate from Pacing to allow for deliberate slow speech vs. naturally slow speech)

1.5 Intended Use Case / Context

  • Options: Narration (Audiobooks, Documentaries), Virtual Assistant, Customer Service, Podcast Host, Marketing/Advertising, E-learning, Gaming Character, IVR/Telephony, News Broadcast.
  • Control: Dropdown. This selection can provide intelligent defaults or recommendations for other parameters, guiding the user towards an appropriate voice profile.

1.6 Advanced Parameters (Optional/Expert Mode)

  • Voice Stability: (ElevenLabs specific) Consistency of voice characteristics.
  • Voice Clarity: (ElevenLabs specific) Reduction of artifacts and background noise.
  • Style Exaggeration: (ElevenLabs specific) Intensity of the selected speaking style.
  • Phoneme-level Adjustments: For highly advanced users, direct control over specific phoneme duration, pitch, and volume (requires a more complex interface).

2. Wireframe Descriptions (UI for Voice Designer)

The UI will be a multi-panel, interactive design studio, prioritizing real-time feedback and ease of use.

2.1 Overall Layout: "Voice Studio"

  • Left Panel (Navigation/Presets):

* "My Voices" List: Saved custom voices.

* "Explore Presets": Library of pre-designed voices (e.g., "Warm Narrator," "Energetic Assistant").

* "New Voice" Button: Initiates a fresh design.

  • Central Panel (Voice Design Canvas): This is the main interactive area, divided into logical sections.
  • Right Panel (Preview & Actions):

* Text Input Area: For typing text to be synthesized.

* Play/Stop Button: To hear the current voice design.

* Volume Control.

* Save/Export Options.

2.2 Central Panel Sections (Voice Design Canvas)

2.2.1 Section 1: Basic Profile

  • Elements:

* Gender Slider: Horizontal slider with "Male," "Neutral," "Female" labels at endpoints/midpoint. Visual representation might subtly change (e.g., color gradient).

* Age Range Selector: Dropdown or radio buttons (Young Adult, Middle-Aged, Senior).

* Accent & Language Pickers: Two-tiered dropdowns. A world map or flag icons could accompany selections.

* Intended Use Case: Dropdown with descriptive options.

  • Interactivity: Changes here immediately influence the base voice model.

2.2.2 Section 2: Tone & Emotion

  • Elements:

* Tone Sliders: Group of 5-7 horizontal sliders as described in 1.2. Each slider has two opposing descriptive labels (e.g., "Calm" on left, "Energetic" on right).

* Emotional State Picker (Optional): Dropdown or small icon buttons for discrete emotions.

  • Interactivity: Sliders provide granular control. Hovering over labels could show tooltips with examples.

2.2.3 Section 3: Speaking Style & Pacing

  • Elements:

* Pacing Slider: "Slow" to "Fast."

* Clarity Slider: "Mumbled" to "Articulate."

* Rhythm Slider: "Staccato" to "Smooth."

* Intonation Variety Slider: "Monotone" to "Expressive."

* Speaking Manner Selector: Radio buttons or icon-based selection (e.g., mic icon for "Narrator," speech bubble for "Conversational").

  • Interactivity: Visual feedback on sliders, subtle animation on icons.

2.2.4 Section 4: Vocal Qualities

  • Elements:

* Pitch Slider: "Lower" to "Higher."

* Resonance Slider: "Flat" to "Resonant."

* Breathiness Slider: "Clear" to "Breathy."

* Vocal Texture Slider: "Smooth" to "Husky."

* Volume (Relative) Slider: "Soft" to "Loud."

* Speech Rate Slider: "Slow" to "Fast."

  • Interactivity: Fine-tuning controls.

2.2.5 Section 5: Advanced & Fine-Tuning (Collapsible)

  • Elements:

* Voice Stability Slider.

* Voice Clarity Slider.

* Style Exaggeration Slider.

* "Reset to Default" Button for the current voice.

* "Randomize" Button for inspiration.

2.3 Right Panel: Preview & Actions

  • Text Input Area: Large textarea for user to type or paste text (e.g., 250 characters limit for quick preview).
  • "Play" Button: Prominently displayed, triangular icon.
  • "Stop" Button: Square icon.
  • "Download Preview" Button: To download a short audio clip.
  • Save Voice Button: Names and saves the custom voice to "My Voices."
  • Export Voice Button: Provides options for API key, SDK integration, or full audio file generation (for longer texts, potentially linking to a separate generation service).
  • Undo/Redo Buttons: Standard functionality for design changes.

3. Color Palettes

The UI should feel modern, clean, and professional, with good contrast for accessibility.

3.1 Palette 1: "Tech Horizon" (Primary Recommendation)

  • Primary Accent: #007AFF (Vibrant Blue - for interactive elements, highlights, primary buttons)
  • Secondary Accent: #5AC8FA (Sky Blue - for subtle highlights, active states)
  • Neutrals (Dark Mode Focused):

* Background: #1A1A1A (Deep Charcoal)

* Card/Panel Background: #2C2C2E (Dark Grey)

* Text (Primary): #F2F2F7 (Off-White)

* Text (Secondary/Labels): #AEAEB2 (Light Grey)

* Borders/Dividers: #3A3A3C (Medium Dark Grey)

  • Neutrals (Light Mode Option):

* Background: #F2F2F7 (Off-White)

* Card/Panel Background: #FFFFFF (Pure White)

* Text (Primary): #1C1C1E (Dark Charcoal)

* Text (Secondary/Labels): #636366 (Medium Grey)

* Borders/Dividers: #D1D1D6 (Light Grey)

  • Semantic Colors:

* Success: #34C759 (Green)

* Warning: #FFD60A (Yellow)

* Error: #FF3B30 (Red)

3.2 Palette 2: "Subtle Gradient" (Alternative)

  • Primary Accent: Gradient from #6A0DAD (Deep Purple) to #8A2BE2 (Blue Violet)
  • Secondary Accent: #9D72DA (Lavender)
  • Neutrals (Dark Mode Focused):

* Background: #121212 (Almost Black)

* Card/Panel Background: #1E1E1E (Very Dark Grey)

* Text (Primary): #E0E0E0 (Light Grey)

* Text (Secondary/Labels): #A0A0A0 (Medium Grey)

* Borders/Dividers: #303030 (Dark Grey)

  • Semantic Colors: Same as Palette 1 for consistency.

4. UX Recommendations

These recommendations aim to create an intuitive, efficient, and enjoyable user experience for designing AI voices.

4.1 Real-time Feedback Loop

  • Instant Audio Preview: The most critical UX element. Any change to a slider or dropdown should immediately (or with minimal delay) update the audio output when the "Play" button is pressed.
  • Visual Indicators: Sliders should subtly animate or show value changes in real-time.

4.2 Progressive Disclosure

  • Start Simple: Begin with basic profile attributes (gender, age, accent, use case).
  • Expand as Needed: Offer "Advanced Settings" or collapsible sections for more granular controls (e.g., specific vocal qualities, ElevenLabs parameters) to avoid overwhelming new users.
  • Presets as Starting Points: Provide a library of diverse, high-quality preset voices that users can load and then customize. This reduces decision fatigue.

4.3 Intuitive Controls

  • Sliders for Continuous Values: Use horizontal sliders for parameters with a continuous range (e.g., pitch, energy, professionalism). Clearly label both ends of the slider.
  • Dropdowns/Radio Buttons for Discrete Choices: For distinct options like accent, language, or speaking manner.
  • Visual Metaphors: Where possible, use icons or subtle visual cues to represent voice characteristics (e.g., a waveform icon for "expressiveness").

4.4 Guidance and Education

  • Tooltips and Explanations: Hover-over tooltips for each parameter explaining what it does and how it affects the voice. Provide concrete examples where applicable.
  • Contextual Help: Small info icons next
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);}});}