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

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

AI Voice Designer: Custom Voice Generation Specifications

This document outlines the detailed design specifications, wireframe descriptions, color palettes, and user experience (UX) recommendations for a "Custom AI Voice Designer" tool. The goal is to empower users to craft highly personalized AI voices by describing desired characteristics, leveraging the advanced capabilities of ElevenLabs.


1. Introduction: Crafting Your Unique AI Voice

The AI Voice Designer provides a powerful and intuitive interface for creating completely custom AI voices. Instead of selecting from a predefined list, you will describe the specific characteristics you envision, and the system will generate a voice tailored to your specifications. This allows for unparalleled creativity and precision in voice design for any application, from virtual assistants and narrators to unique character voices.


2. Core Design Philosophy & User Experience Goals

Our primary objective is to make the complex process of voice synthesis feel simple, intuitive, and iterative.

  • Intuitive Control: Users should feel in command of the voice design process, with clear parameters and immediate feedback.
  • Iterative Refinement: Voice design is often a process of trial and error. The tool will support rapid iteration, allowing users to describe, generate a sample, listen, and refine until satisfied.
  • Immediate Feedback: Visual and auditory feedback will be provided promptly to guide the user's decisions.
  • Powerful Flexibility: While offering simplicity, the tool must expose sufficient depth for granular control over voice characteristics.
  • Professional & Engaging: The interface will be clean, modern, and aesthetically pleasing, reflecting the advanced technology it represents.

3. Detailed Design Specifications for Voice Characteristics

The AI Voice Designer will offer a comprehensive set of parameters, categorized for ease of use, allowing users to define every nuance of their custom voice.

3.1 Primary Input: Natural Language Description

  • "Describe Your Desired Voice" Text Area:

* Purpose: The primary entry point. Users can type a natural language description of the voice they want.

* Example Prompts: "A calm, authoritative male voice, suitable for narrating documentaries, with a clear British accent." or "A friendly, energetic female voice, mid-20s, perfect for a podcast host, with a slight Californian lilt."

* NLP Integration: The system will attempt to parse this description and pre-populate relevant sliders and dropdowns in the detailed controls section, providing a smart starting point.

3.2 Categorized Detailed Controls (Sliders, Dropdowns, Toggles)

These controls allow for precise adjustments and override/fine-tune any initial NLP interpretation.

A. Demographic & Core Attributes:

  • Gender:

* Options: Male, Female, Neutral/Androgynous.

* Control: Radio buttons or a slider from "More Male" to "More Female."

  • Age Range:

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

* Control: Dropdown or a slider representing age progression.

  • Accent & Region:

* Options (Dropdown): American English (General, Californian, Southern, New York), British English (RP, Cockney, Scottish, Welsh), Australian English, Indian English, Spanish (Castilian, Latin American), French (Parisian, Canadian), German, Japanese, Mandarin Chinese, etc.

* Control: Multi-select dropdown for primary and secondary accents, or a search field for specific accents.

B. Tone, Style & Emotion:

  • Emotional Range:

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

* Control: Multi-select checkboxes or a "mood board" slider grid.

  • Speaking Style:

* Options: Professional, Friendly, Authoritative, Casual, Conversational, Narrative, Dramatic, Playful, Sarcastic.

* Control: Multi-select checkboxes or a slider between opposing styles (e.g., "Formal" to "Casual").

  • Pace/Rate:

* Range: Very Slow to Very Fast (e.g., 80 WPM to 200 WPM).

* Control: Slider.

  • Pitch:

* Range: Very Low to Very High.

* Control: Slider.

  • Volume/Loudness:

* Range: Soft Whisper to Loud Shout.

* Control: Slider.

C. Uniqueness & Character:

  • Distinctiveness:

* Options: Common, Unique, Very Unique, Highly Distinctive.

* Control: Slider. (This parameter influences how "generic" or "memorable" the voice sounds compared to typical AI voices).

  • Breathiness:

* Range: None to Very Breathy.

* Control: Slider.

  • Clarity/Articulation:

* Range: Muffled to Extremely Clear.

* Control: Slider.

  • Resonance:

* Range: Flat to Deeply Resonant.

* Control: Slider.

D. Purpose/Application (Optional but helpful for context):

  • Options (Dropdown): Narrator, Chatbot, Virtual Assistant, Podcast Host, Video Game Character, Advertisement, eLearning, IVR System.
  • Control: Dropdown. (This can subtly influence other parameters if not explicitly set by the user).

3.3 Voice Profile Management

  • Voice Name Field: A text input field to name the custom voice (e.g., "Aura - Documentary Narrator").
  • Voice ID/Token (Read-only): Display the unique identifier generated by ElevenLabs once the voice is saved.

4. Wireframe Description

The user interface will be designed for clarity and ease of interaction, following a common two- or three-column layout.

Overall Layout:

  • Header: Application title, user profile, help/support links.
  • Main Content Area: Divided into input/controls and output/preview sections.
  • Footer: Copyright, legal links.

Key UI Elements & Sections:

  1. Left Panel: Voice Description & Controls (Input)

* Section Title: "Describe & Define Your Voice"

* "Describe Your Desired Voice" Text Area:

* Large multi-line input field with a clear placeholder text.

* Hint: "Start with a general description, then refine with specific controls below."

* Parameter Control Accordions/Sections:

* Each category (Demographic, Tone, Uniqueness) will be in a collapsible section or clearly separated by headings.

* Sliders will have numerical value displays and clear labels.

* Dropdowns will have descriptive options.

* Toggles/Radio buttons will be clearly labeled.

* "Reset All Parameters" Button: Clears all custom settings.

* "Load Template" Dropdown: Provides pre-configured starting points (e.g., "Professional Narrator," "Friendly Chatbot," "Energetic Podcast Host").

  1. Right Panel: Voice Preview & Profile (Output)

* Section Title: "Listen & Refine"

* "Voice Name" Input Field: Prominently displayed for users to name their creation.

* Voice Profile Summary:

* A concise, human-readable summary of the currently selected parameters (e.g., "Female, Mid-aged, British RP accent, Calm & Professional, Medium pace, High clarity").

* Dynamically updates as controls are adjusted.

* Text-to-Speech Input Field (for Sample Generation):

* A multi-line text area where users type text for the AI voice to speak.

* Pre-populated with a default sample text (e.g., "The quick brown fox jumps over the lazy dog. This is a test of your custom voice.")

* Users can input their own text to hear how the voice handles specific phrases.

* "Generate Sample" Button:

* Primary Call-to-Action (CTA) in this panel.

* Triggers the ElevenLabs API call to synthesize the voice sample based on current parameters and sample text.

* Changes to a "Generating..." state with a spinner during processing.

* Audio Playback Controls:

* Standard play, pause, stop buttons.

* Volume slider.

* Seek bar/progress indicator for the audio sample.

* Waveform Visualizer:

* A dynamic visual representation of the generated audio, appearing once a sample is generated. Provides visual feedback of the sound.

* "Compare Samples" Button/Feature:

* Allows users to save multiple generated samples and play them side-by-side for comparison.

* Action Buttons:

* "Save Voice" Button: Saves the current voice profile to the user's account.

* "Export Voice" / "Get API Access" Button: Provides options to download voice models (if applicable) or get API keys/SDK instructions for integration.


5. Color Palette Recommendations

A professional, modern, and inviting color palette will enhance user experience and reflect the cutting-edge nature of the technology.

  • Primary Brand Color (e.g., Deep Teal/Blue-Green): #007B8C (or similar rgb(0, 123, 140))

Usage:* Main header, active navigation items, primary button backgrounds (e.g., "Generate Sample"). Represents innovation and professionalism.

  • Secondary Accent Color (e.g., Lighter Teal/Aqua): #00B8D4 (or similar rgb(0, 184, 212))

Usage:* Hover states, progress bars, active slider tracks, selected tabs. Adds vibrancy and indicates interactivity.

  • Call-to-Action/Highlight Color (e.g., Vibrant Orange/Gold): #FF8C00 (or similar rgb(255, 140, 0))

Usage:* "Save Voice" button, important alerts, key visual highlights. Draws attention to critical actions.

  • Neutral Background (Light Grey/Off-White): #F8F8F8

Usage:* Main content background, card backgrounds. Provides a clean canvas.

  • Dark Text Color (Charcoal Grey): #333333

Usage:* Primary text, headings. Ensures readability.

  • Secondary Text Color (Medium Grey): #666666

Usage:* Helper text, labels, less prominent information.

  • Border/Divider Color (Light Grey): #E0E0E0

Usage:* Separators between sections, input field borders.


6. User Experience (UX) Recommendations

6.1 Iterative Design & Feedback Loop

  • Describe → Generate → Listen → Refine: Clearly guide the user through this cycle.
  • Visual Feedback: Loading spinners, progress bars, and waveform visualizations during audio generation and playback.
  • Auditory Feedback: A subtle "ding" or confirmation sound when a
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);}});}